#ifndef __SYSMATH_H
#define __SYSMATH_H

#include <math.h>

#ifdef __PC
	#ifdef __CLEAN
		#pragma warning(error:4701)	// potentially uninitialized variables
		#pragma warning(error:4244)
		#pragma warning(error:4305)
	#endif

	#define __TYPES_READY
#endif

#if defined(__LINUX) || defined (__MAC)
	#define GCC34T this->
#endif

#ifndef TRUE
	#define TRUE	1
#endif

#ifndef FALSE
	#define FALSE	0
#endif

#ifndef NULL
	#define NULL 	0
#endif

#ifdef __LINUX
	typedef short int	          SWORD;
	typedef unsigned short int	UWORD;
	typedef signed int					LONG;  // m64 option makes int 32 bit
	typedef unsigned int				ULONG; // m64 option makes int 32 bit
#elif defined (__MAC)
	typedef short int	SWORD;
	typedef unsigned short int	UWORD;

	#ifdef __C4D_64BIT
		typedef signed int LONG; //Remo: 02.06.2014
		typedef unsigned int ULONG;
	#else
		typedef signed int LONG;   //Remo: 02.06.2014
		typedef unsigned int ULONG; //Remo: 02.06.2014
		//typedef long LONG;
		//typedef unsigned long	ULONG;
	#endif
#else
	typedef short			          SWORD;
	typedef unsigned short			UWORD;
	typedef signed long 	LONG;
	typedef unsigned long	ULONG;
	typedef signed long		Int32;	//Remo: 02.06.2014
	typedef unsigned long	UInt32; //Remo: 02.06.2014
	
	//this will change function signature >>>
	//typedef signed int 	 LONG;   //Remo: 02.06.2014
	//typedef unsigned int ULONG;  //Remo: 02.06.2014
	//typedef signed int		Int32;	//Remo: 02.06.2014
	//typedef unsigned int	UInt32; //Remo: 02.06.2014
#endif
typedef int                 Bool;
typedef float								SReal;
typedef double							LReal;
typedef void*								Hndl;
typedef int									INT;
typedef unsigned int 				UINT;
typedef char								CHAR;
typedef unsigned char				UCHAR;

#ifdef __C4D_64BIT
	#ifdef __INTEL_COMPILER
		#ifdef __LINUX
			typedef long									LLONG;  // m64 option makes long 64 bit
			typedef unsigned long					LULONG;  // m64 option makes long 64 bit
			typedef unsigned long					VULONG; // m64 option makes long 64 bit
			typedef long									VLONG;  // m64 option makes long 64 bit
		#else
			typedef long long							LLONG;
			typedef unsigned long long		LULONG;
			typedef unsigned long long		VULONG;
			typedef signed long long			VLONG;
		#endif
	#elif defined __MAC
		typedef signed long long				LLONG;
		typedef unsigned long long			LULONG;
		typedef unsigned long long			VULONG;
		typedef signed long long				VLONG;
	#elif defined __LINUX	
		typedef signed long long				LLONG;
		typedef unsigned long long			LULONG;
		typedef unsigned long long			VULONG;
		typedef signed long long				VLONG;
	#else
		typedef _W64 __int64						LLONG;
		typedef _W64 unsigned __int64		LULONG;
		typedef _W64 unsigned __int64   VULONG;
		typedef _W64 signed __int64		  VLONG;
	#endif
#else
	#ifdef __LINUX
		typedef long long								LLONG;
		typedef unsigned long long			LULONG;
		typedef unsigned int						VULONG;
		typedef signed int							VLONG;
	#elif defined __MAC
		typedef signed long long				LLONG;
		typedef unsigned long long			LULONG;
		typedef unsigned long						VULONG;
		typedef signed long							VLONG;
	#else
		typedef __int64									LLONG;
		typedef unsigned __int64				LULONG;
		typedef unsigned long						VULONG;
		typedef signed long							VLONG;
	#endif
#endif

#undef MAXLONG // windows header have MINLONG defines as 0x80000000
#undef MINLONG // windows header have MINLONG defines as 0x80000000

#ifdef __SINGLEPRECISION
	typedef float Real;
#else
	#define Real  LReal
#endif

#define MAXLONGl					0x7fffffff
#define MAXLONGf					2147483520.0f		// 0x7FFFFF80 - rounding MAXLONG to Real results in 0x80000000
#define MAXLONGd					LReal(MAXLONGl)
#define MINLONGl					(-0x7fffffff)		// explicitly not 0x80000000
#define MINLONGf					-2147483520.0f	// -0x7FFFFF80 - rounding MINLONG to Real results in 0x80000000
#define MINLONGd					LReal(MINLONGl)

#ifndef MAXULONG
	#define MAXULONG					0xffffffff
#endif
#ifndef MAXSWORD
	#define MAXSWORD						32767L
#endif
#ifndef MAXUWORD
	#define MAXUWORD					65535L
#endif

#define MAXREALs						( 9.0e18f)
#define MINREALs						(-9.0e18f)

#ifdef __SINGLEPRECISION
	#define MAXREALr						( 9.0e18f)
	#define MINREALr						(-9.0e18f)
#else
	#define MAXREALr						( 1.0e308)
	#define MINREALr						(-1.0e308)
#endif

#define MAXREALl						( 1.0e308)
#define MINREALl						(-1.0e308)

#ifndef NOTOK
	#define NOTOK								(-1)
#endif

// use this defines to define float consts!
// e.g. instead of 10.0f write RC(10.0)
// speed up the 64 bit version some percent!
#define SCO		(SReal)	// defines float constants to SReal
#define RCO		(Real)	// defines float constants to Real
#define LCO		(LReal)	// defines float constants to LReal

#define pi			3.1415926535897932384626433832795
#define piinv		0.31830988618379067153776752674508	// 1/pi
#define pi2			6.283185307179586476925286766559
#define pi2inv	0.15915494309189533576888376337251	// 1/pi2
#define pi05		1.5707963267948966192313216916398
#define pi05inv 0.63661977236758134307553505349036	// 1/pi05

#define EPSILON90					0.997		//EPSILON for 90 degrees
#define EPSILON           0.0001
#define EPSILON5					1e-5		//0.00001
#define EPSILON6					1e-6
#define EPSILON7					1e-7
#define EPSILON8          1e-8
#define EPSILON10         1e-10
#define EPSILON12         1e-12
#define EPSILON16					1e-16

inline SReal FMin(SReal a, SReal b) { if (a<b) return a; return b; }
inline LReal FMin(LReal a, LReal b) { if (a<b) return a; return b; }
inline LONG  LMin(LONG a,  LONG b) { if (a<b) return a; return b; }
inline VLONG VMin(VLONG a, VLONG b) { if (a<b) return a; return b; }

inline SReal FMax(SReal a, SReal b) { if (a<b) return b; return a; }
inline LReal FMax(LReal a, LReal b) { if (a<b) return b; return a; }
inline LONG  LMax(LONG a, LONG b) { if (a<b) return b; return a; }
inline VLONG VMax(VLONG a,VLONG b) { if (a<b) return b; return a; }

inline LONG  LCut(LONG  a,LONG b,LONG c) { if (a<b) return b; if (a>c) return c; return a; }
inline VLONG VCut(VLONG a,VLONG b,VLONG c) { if (a<b) return b; if (a>c) return c; return a; }
//template <class A> inline A TCut(A a,A b,A c) { if (a<b) return b; if (a>c) return c; return a; }

inline SReal FCut(SReal a,SReal b,SReal c) { if (a<b) return b; if (a>c) return c; return a; }
inline LReal FCut(LReal a,LReal b,LReal c) { if (a<b) return b; if (a>c) return c; return a; }

inline SReal FCut01(SReal a) { if (a<0.0f) return 0.0f; if (a>1.0f) return 1.0f; return a; }
inline LReal FCut01(LReal a) { if (a<0.0) return 0.0; if (a>1.0) return 1.0; return a; }

#define FtoL(x)	LONG(x)

#if defined (__MAC)
	inline SReal Sin(SReal val) { return sinf(val); }
	inline LReal Sin(LReal val) { return sin(val); }

	inline SReal Cos(SReal val) { return cosf(val); }
	inline LReal Cos(LReal val) { return cos(val); }

	inline SReal Tan(SReal val) { return tanf(val); }
	inline LReal Tan(LReal val) { return tan(val); }

	inline SReal ATan(SReal val) { return atanf(val); }
	inline LReal ATan(LReal val) { return atan(val); }

	inline SReal Exp(SReal val) { return expf(val); }
	inline LReal Exp(LReal val) { return exp(val); }

	inline SReal Ln(SReal val) { return logf(val); }
	inline LReal Ln(LReal val) { return log(val); }

	inline SReal Ln10(SReal val) { return log10f(val); }
	inline LReal Ln10(LReal val) { return log10(val); }

	inline SReal Ld(SReal val) { return log2f(val); }
	inline LReal Ld(LReal val) { return log2(val); }

	inline SReal Sqrt(SReal val) { return sqrtf(val); }
	inline LReal Sqrt(LReal val) { return sqrt(val); }

	inline SReal Floor(SReal val) { return floorf(val); }
	inline LReal Floor(LReal val) { return floor(val); }

	inline SReal Ceil(SReal val) { return ceilf(val); }
	inline LReal Ceil(LReal val) { return ceil(val); }

	inline SReal Pow(SReal v1, SReal v2) { return powf(v1,v2); }
	inline LReal Pow(LReal v1, LReal v2) { return pow(v1,v2); }

	inline SReal Sinh(SReal val) { return sinhf(val); }
	inline LReal Sinh(LReal val) { return sinh(val); }

	inline SReal Cosh(SReal val) { return coshf(val); }
	inline LReal Cosh(LReal val) { return cosh(val); }

	inline SReal Tanh(SReal val) { return tanhf(val); }
	inline LReal Tanh(LReal val) { return tanh(val); }

	inline SReal FMod(SReal v1, SReal v2) { return fmodf(v1,v2); }
	inline LReal FMod(LReal v1, LReal v2) { return fmod(v1,v2); }

	inline SReal Abs(SReal val) { return fabsf(val); }
	inline LReal Abs(LReal val) { return fabs(val); }
	inline SReal Sign(SReal val) { return (val < 0.0f) ? -1.0f : 1.0f; }
	inline LReal Sign(LReal val) { return (val < 0.0) ? -1.0 : 1.0; }
#else
	inline SReal Sin(SReal val) { return sin(val); }
	inline LReal Sin(LReal val) { return sin(val); }

	inline SReal Cos(SReal val) { return cos(val); }
	inline LReal Cos(LReal val) { return cos(val); }

	inline SReal Tan(SReal val) { return tan(val); }
	inline LReal Tan(LReal val) { return tan(val); }

	inline SReal ATan(SReal val) { return atan(val); }
	inline LReal ATan(LReal val) { return atan(val); }

	inline SReal Exp(SReal val) { return exp(val); }
	inline LReal Exp(LReal val) { return exp(val); }

	inline SReal Ln(SReal val) { return log(val); }
	inline LReal Ln(LReal val) { return log(val); }

	inline SReal Ln10(SReal val) { return log10(val); }
	inline LReal Ln10(LReal val) { return log10(val); }

	inline SReal Ld(SReal r) { return Ln(r) * (1.0f / 0.69314718055994530941723212145818f); }
	inline LReal Ld(LReal r) { return Ln(r) * (1.0 / 0.69314718055994530941723212145818); }

	inline SReal Sqrt(SReal val) { return sqrt(val); }
	inline LReal Sqrt(LReal val) { return sqrt(val); }

	inline SReal Floor(SReal val) { return floor(val); }
	inline LReal Floor(LReal val) { return floor(val); }

	inline SReal Ceil(SReal val) { return ceil(val); }
	inline LReal Ceil(LReal val) { return ceil(val); }

	inline SReal Pow(SReal v1, SReal v2) { return pow(v1,v2); }
	inline LReal Pow(LReal v1, LReal v2) { return pow(v1,v2); }

	inline SReal Sinh(SReal val) { return sinh(val); }
	inline LReal Sinh(LReal val) { return sinh(val); }

	inline SReal Cosh(SReal val) { return cosh(val); }
	inline LReal Cosh(LReal val) { return cosh(val); }

	inline SReal Tanh(SReal val) { return tanh(val); }
	inline LReal Tanh(LReal val) { return tanh(val); }

	inline SReal FMod(SReal v1, SReal v2) { return fmod(v1,v2); }
	inline LReal FMod(LReal v1, LReal v2) { return fmod(v1,v2); }

	inline SReal Abs(SReal f) { return fabs(f); }
	inline LReal Abs(LReal f) { return fabs(f); }
	inline SReal Sign(SReal val) { return (val < 0.0f) ? -1.0f : 1.0f; }
	inline LReal Sign(LReal val) { return (val < 0.0) ? -1.0 : 1.0; }
#endif

#define Mod(a,b)		((a)<0?((a)-(((a)-(b)+1)/(b))*(b)):(a)%(b))

template <class X> inline X Abs(X f) { if (f<0) return -f; return f; }

inline SReal ASin(SReal val) { if(val>=1.0f) return SCO pi05; else if (val<=-1.0f) return -SCO pi05; return asin(val); }
inline SReal ACos(SReal val) { if(val>=1.0f) return 0.0f; else if (val<=-1.0f) return SCO pi; return acos(val); }
inline LReal ASin(LReal val) { if(val>=1.0) return pi05; else if(val<=-1.0) return -pi05; return asin(val); }
inline LReal ACos(LReal val) { if(val>=1.0) return 0.0; else if(val<=-1.0) return pi; return acos(val); }

inline LONG LFloor(SReal r) { return LONG(Floor(r)); }
inline LONG LCeil(SReal r)  { return LONG(Ceil(r));  }

inline LONG LFloor(LReal r) { return LONG(Floor(r)); }
inline LONG LCeil(LReal r)  { return LONG(Ceil(r));  }

inline SReal Rad(SReal r)   { return ((r)*SCO(pi/180.0)); }
inline LReal Rad(LReal r)   { return ((r)*pi/180.0); }
inline SReal Deg(SReal r)   { return ((r)*SCO(180.0/pi)); }
inline LReal Deg(LReal r)   { return ((r)*180.0/pi); }

inline void SinCos(SReal w,SReal &sn,SReal &cn) { sn=Sin(w); cn=Cos(w); }
inline void SinCos(LReal w,LReal &sn,LReal &cn) { sn=Sin(w); cn=Cos(w); }

inline LONG SAFELONG(SReal x)
{
	if (x<=MINLONGf) return MINLONGl;
	else if (x>=MAXLONGf) return MAXLONGl;
	return LONG(x);
}

inline LONG SAFELONG(LReal x)
{
	if (x<=MINLONGd) return MINLONGl;
	else if (x>=MAXLONGd) return MAXLONGl;
	return LONG(x);
}

class IllegalEnumAccess
{
public:
	IllegalEnumAccess() {}
};

class IllegalFlagAccess
{
public:
	IllegalFlagAccess() {}
};

#define ENUM_END_FLAGS(X) ;\
	inline X operator | (X a, X b) { return X(ULONG(a)|ULONG(b)); } \
	inline X operator & (X a, X b) { return X(ULONG(a)&ULONG(b)); } \
	inline X operator ^ (X a, X b) { return X(ULONG(a)^ULONG(b)); } \
	inline X operator >> (X a, X b) { return X(ULONG(a)<<ULONG(b)); } \
	inline X operator << (X a, X b) { return X(ULONG(a)>>ULONG(b)); } \
	inline X operator ~ (X a) { return X(~ULONG(a)); } \
	inline X& operator |= (X &a, const X &b) { a = X(ULONG(a)|ULONG(b)); return a; } \
	inline X& operator &= (X &a, const X &b) { a = X(ULONG(a)&ULONG(b)); return a; } \
	inline X& operator ^= (X &a, const X &b) { a = X(ULONG(a)^ULONG(b)); return a; } \
	inline IllegalFlagAccess operator ++ (X a) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator ++ (X a, int) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator -- (X a) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator -- (X a, int) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator != (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator != (LONG s2, X s1) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator == (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator == (LONG s2, X s1) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator < (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator < (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator < (LONG s2, X s1) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator <= (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator <= (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator <= (LONG s2, X s1) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator > (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator > (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator > (LONG s2, X s1) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator >= (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator >= (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator >= (LONG s2, X s1) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator + (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator + (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator + (LONG s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator - (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator - (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator - (LONG s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator * (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator * (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator * (LONG s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator / (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator / (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator / (LONG s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator % (X s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator % (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator % (LONG s1, X s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator ^ (X s1, LONG s2) { return IllegalFlagAccess(); } \
	inline IllegalFlagAccess operator ^ (LONG s1, X s2) { return IllegalFlagAccess(); }

#define ENUM_END_LIST(X) ;\
	inline IllegalEnumAccess operator | (X a, X b) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator & (X a, X b) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator ~ (X a) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator ++ (X a) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator ++ (X a, int) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator -- (X a) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator -- (X a, int) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator == (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator == (LONG s2, X s1) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator != (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator != (LONG s2, X s1) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator ! (X a) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator + (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator + (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator - (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator - (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator * (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator * (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator / (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator / (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator % (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator % (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator < (X s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator < (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator < (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator > (X s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator > (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator > (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator <= (X s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator <= (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator <= (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator >= (X s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator >= (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator >= (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator << (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator << (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator >> (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator >> (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator ^ (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator ^ (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator || (X s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator || (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator || (LONG s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator && (X s1, X s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator && (X s1, LONG s2) { return IllegalEnumAccess(); } \
	inline IllegalEnumAccess operator && (LONG s1, X s2) { return IllegalEnumAccess(); }


#endif
