#include "c4d_tools.h"
#include "c4d_basetime.h"

LONG BaseTime::GetFrame(Real fps) const
{
	return LONG(Floor(nominator*fps)/Floor(denominator));
}

void BaseTime::Quantize(Real fps)
{
	nominator = Floor(Floor(nominator*fps)/Floor(denominator));
	denominator  = Floor(fps);
	Reduce();
}

void BaseTime::Reduce(void)
{ 
	Real z,n,m;

	z=Abs(nominator);
	n=Abs(denominator);

	if(z<MINSIZE || n<MINSIZE)
	{
		nominator=0.0;
		denominator=1.0;
		return;
	}
	else if(z<MAXLONG && n<MAXLONG)
	{
		LONG iz=z,in=n,im;
		
		do
		{
			im=iz%in;
			iz=in;in=im;
		}while(im);

		nominator/=Real(iz);
		denominator/=Real(iz);
		return;
	}
	else
	{
		do
		{
			m=FMod(z,n);
			z=n;n=m;
		}while(m>MINSIZE);

		nominator/=z;
		denominator/=z;
		return;
	}
}

BaseTime::BaseTime(void) 
{ 
	nominator = 0; 
	denominator  = 1; 
}

BaseTime::BaseTime(Real r)
{ 
	nominator = Floor(r*1000+0.5);
	denominator  = 1000.0;
	Reduce();
}	 

BaseTime::BaseTime(Real z, Real n)
{ 
	Bool sgn = (z>=0.0) == (n>=0.0);
	
	nominator = Floor(Abs(z)+0.5); 
	denominator  = Floor(Abs(n)+0.5); 
	if (!sgn) nominator = -nominator;
	Reduce();
}

Real BaseTime::Get(void) const
{ 
	return nominator/denominator;
}

void BaseTime::SetNominator(Real r)
{ 
	nominator=r;
}

void BaseTime::SetDenominator(Real r)
{ 
	denominator=r;
}

Real BaseTime::GetNominator(void) const
{ 
	return nominator;
}

Real BaseTime::GetDenominator(void) const
{ 
	return denominator;
}

const BaseTime operator * (const BaseTime &t1, const BaseTime &t2)
{
	return BaseTime(t1.nominator*t2.nominator,t1.denominator*t2.denominator);
}

const BaseTime operator / (const BaseTime &t1, const BaseTime &t2)
{
	return BaseTime(t1.nominator*t2.denominator,t1.denominator*t2.nominator);
}

const BaseTime operator + (const BaseTime &t1, const BaseTime &t2)
{
	return BaseTime(t1.nominator * t2.denominator + t2.nominator * t1.denominator,t1.denominator * t2.denominator);
}

const BaseTime operator - (const BaseTime &t1, const BaseTime &t2)
{
	return BaseTime(t1.nominator * t2.denominator - t2.nominator * t1.denominator,t1.denominator * t2.denominator);
}

Bool operator == (const BaseTime &t1, const BaseTime &t2)
{
	if (t1.nominator==t2.nominator && t1.denominator==t2.denominator) return TRUE; // massive problems otherwise (compiler miscalculating floor)
	return Floor(t1.nominator*t2.denominator)==Floor(t2.nominator*t1.denominator);
}

Bool operator < (const BaseTime &t1, const BaseTime &t2)
{
	if (t1.nominator==t2.nominator && t1.denominator==t2.denominator) return FALSE; // massive problems otherwise (compiler miscalculating floor)
	return Floor(t1.nominator*t2.denominator)<Floor(t2.nominator*t1.denominator);
}

Bool operator != (const BaseTime &t1, const BaseTime &t2)
{
	if (t1.nominator==t2.nominator && t1.denominator==t2.denominator) return FALSE; // massive problems otherwise (compiler miscalculating floor)
	return Floor(t1.nominator*t2.denominator)!=Floor(t2.nominator*t1.denominator);
}

Bool operator <= (const BaseTime &t1, const BaseTime &t2)
{
	if (t1.nominator==t2.nominator && t1.denominator==t2.denominator) return TRUE; // massive problems otherwise (compiler miscalculating floor)
	return Floor(t1.nominator*t2.denominator)<=Floor(t2.nominator*t1.denominator);
}

Bool operator >= (const BaseTime &t1, const BaseTime &t2)
{
	if (t1.nominator==t2.nominator && t1.denominator==t2.denominator) return TRUE; // massive problems otherwise (compiler miscalculating floor)
	return Floor(t1.nominator*t2.denominator)>=Floor(t2.nominator*t1.denominator);
}

Bool operator > (const BaseTime &t1, const BaseTime &t2)
{
	if (t1.nominator==t2.nominator && t1.denominator==t2.denominator) return FALSE; // massive problems otherwise (compiler miscalculating floor)
	return Floor(t1.nominator*t2.denominator)>Floor(t2.nominator*t1.denominator);
}
