#ifndef __MACMATH_H
#define __MACMATH_H

#include <fp.h>

struct Matrix;
struct Vector;

#ifndef NULL
#define NULL 0
#endif

#ifndef NIL
#define NIL 0
#endif

#ifndef TRUE
#define TRUE	1
#endif

#ifndef FALSE
#define FALSE	0
#endif

typedef void*	Hndl;
typedef int Bool;

typedef char	CHAR;
typedef unsigned char	UCHAR;
typedef short int	WORD;
typedef unsigned short int	UWORD;
typedef long LONG;
typedef unsigned long	ULONG;
typedef int	INT;
typedef unsigned int UINT;
typedef float	Real;
typedef float	SReal;
typedef double	LReal;

#ifndef MAXLONG
	#define MAXLONG						0x7fffffff
#endif
#ifndef MINLONG
	#define MINLONG						(-0x7fffffff) // explicitely not 0x80000000
#endif
#ifndef MAXULONG
	#define MAXULONG					0xffffffff
#endif
#ifndef MAXWORD
	#define MAXWORD						32767L
#endif
#ifndef MAXUWORD
	#define MAXUWORD					65535L
#endif

typedef float								Real;
#define MAXREAL							( 9.0e18)
#define MINREAL							(-9.0e18)

#define NOTOK								(-1)

#define pi		3.1415926535897932384626433832795
#define pi2		6.283185307179586476925286766559
#define pi05	1.5707963267948966192313216916398

inline Real  FMin(Real a,  Real 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 Real  FMax(Real a, Real 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 Real  FCut(Real  a,Real b,Real c) { if (a<b) return b; if (a>c) return c; return a; }
inline LReal FCut(LReal a,Real b,Real c) { if (a<b) return b; if (a>c) return c; return a; }
inline LONG  LCut(LONG  a,LONG b,LONG 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; }

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

#define Mod(a,b)		((a)<0?((a)-(((a)-(b)+1)/(b))*(b)):(a)%(b))
#define FMod(r,s)		fmod(r,s)
#define Sin(r) 			sin(r)
#define Cos(r) 			cos(r)
#define Tan(r) 			tan(r)
#define ATan(r) 		atan(r)
#define Exp(r)			exp(r)
#define Ln(r) 			log(r)
#define Ln10(r) 		log10(r)
#define Sqrt(r)			sqrt(r)
#define Floor(r)		floor(r)
#define Ceil(r)			ceil(r)
#define Pow(r,s)		pow((r),(s))
#define Cosh(r)			cosh(r)
#define Sinh(r)			sinh(r)
#define Tanh(r)			tanh(r)

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

inline Real ASin(Real val)
{
	if (val >= 1.0) return pi05;
	else if (val <= -1.0) return -pi05;
	return asin((double)val);
}//ASin

inline Real ACos(Real val)
{
	if (val >= 1.0) return 0.0;
	else if (val <= -1.0) return pi;
	return acos((double)val);
}//ACos

inline Real Rad(Real r)
{
	return ((r)*pi / 180.0);
}
inline Real Deg(Real r)
{
	return ((r)*180.0 / pi);
}

inline LONG SAFELONG(Real x)
{
	if (x <= Real(MINLONG)) return MINLONG;
	else if (x >= Real(MAXLONG)) return MAXLONG;
	return LONG(x);
}

inline LONG LFloor(Real r)
{
	LONG exp = (*(ULONG*)&r >> 23) & 0xFF;
	exp-=0x7f;

	if (*(ULONG*)&r & 0x80000000)
	{
		if (exp<0) return -1;
		if (exp>31) return MINLONG;

		LONG res = (0x7FFFFF)>>exp;
		LONG sub = ((*(ULONG*)&r)&res)!=0;
		res = ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
		return -res-sub;
	}

	if (exp<0) return 0;
	if (exp>31) return MAXLONG;
	return ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
}

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

inline LONG LCeil(Real r)
{
	LONG exp = (*(ULONG*)&r >> 23) & 0xFF;
	exp-=0x7f;

	if (!(*(ULONG*)&r & 0x80000000))
	{
		if (exp<0) return 1;
		if (exp>31) return MAXLONG;

		LONG res = (0x7FFFFF)>>exp;
		LONG sub = ((*(ULONG*)&r)&res)!=0;
		res = ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp);
		return res+sub;
	}

	if (exp<0) return 0;
	if (exp>31) return MINLONG;
	return -LONG(ULONG(LONG((*(ULONG*)&r << 8) | 0x80000000))>>(31-exp));
}

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

#define FtoL(x) LONG(x)

#endif
