/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2004 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#ifndef __C4DBASETIME_H
#define __C4DBASETIME_H

#include "ge_math.h"

enum BASETIME_NOREDUCE
{
	NOREDUCE
};

class BaseTime
{
	friend class BaseFile;
	
	private:
		Real nominator;
		Real denominator;
		void Reduce(void);

	public:

		BaseTime(void) { nominator = 0; denominator  = 1; }
		explicit BaseTime(Real r)
		{
			if (r>1.0e15) r=1.0e15; 
			if (r<-1.0e15) r=-1.0e15; 
			nominator = Floor(r*1000+0.5); 
			denominator  = 1000.0; 
			Reduce();
		}
		explicit BaseTime(Real r,BASETIME_NOREDUCE nr)
		{
			if (r>1.0e15) r=1.0e15; 
			if (r<-1.0e15) r=-1.0e15; 
			nominator = Floor(r*1000+0.5); 
			denominator  = 1000.0;
		}
		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 Get(void) const
		{
			if (denominator==0.0) return 0.0;
			return nominator/denominator;
		}

		Real GetNominator(void) const { return nominator; }
		Real GetDenominator(void) const { return denominator; }

		void SetNominator(Real r) { nominator=r; }
		void SetDenominator(Real r) { denominator=r; }

		LONG GetFrame(Real fps) const { return LONG(Floor(nominator*fps)/Floor(denominator)); }
		void Quantize(Real fps)
		{
			nominator = Floor(Floor(nominator*fps)/Floor(denominator));
			denominator  = Floor(fps);
			Reduce();
		}

		friend const BaseTime operator *  (const BaseTime &t1, const BaseTime &t2);
		friend const BaseTime operator /  (const BaseTime &t1, const BaseTime &t2);

		friend const BaseTime operator +  (const BaseTime &t1, const BaseTime &t2);
		friend const BaseTime operator -  (const BaseTime &t1, const BaseTime &t2);

		friend Bool operator == (const BaseTime &t1, const BaseTime &t2);
		friend Bool operator <  (const BaseTime &t1, const BaseTime &t2);
		friend Bool operator != (const BaseTime &t1, const BaseTime &t2);
		friend Bool operator <= (const BaseTime &t1, const BaseTime &t2);
		friend Bool operator >= (const BaseTime &t1, const BaseTime &t2);
		friend Bool operator >  (const BaseTime &t1, const BaseTime &t2);

		LONG TimeDif(const BaseTime &t2) const
		{
			Real n1 = GetNominator();
			Real n2 = t2.GetNominator();
			Real d1 = GetDenominator();
			Real d2 = t2.GetDenominator();
			if (n1==n2 && d1==d2) return 0;

			Real nd1 = Floor(n1*d2);
			Real nd2 = Floor(n2*d1);
			if (nd1<nd2) return -1;
			else if (nd1>nd2) return 1;

			/*LLONG nd1 = LLONG(n1*d2);
			LLONG nd2 = LLONG(n2*d1);
			if (nd1<nd2) return -1;
			else if (nd1>nd2) return 1;*/
			return 0;
		}
};

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

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

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

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

inline 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);
}

inline 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);
}

inline 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);
}

inline 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);
}

inline 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);
}

inline 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);
}
  
#endif
