/*************************************************************************/
/*	File : XUtil.h														 */
/*	Author :  Aymeric Bard												 */	
/*																		 */	
/*	Virtools SDK 															 */	 
/*	Copyright (c) Virtools 2000, All Rights Reserved.						 */	
/*************************************************************************/

#ifndef _XUTIL_H_
#define _XUTIL_H_

#include "math.h"


#ifdef macintosh
#include "VxMacHeader.h"
#pragma cpp_extensions on
#endif

#ifdef _DEBUG
#if defined(WIN32) || defined(_XBOX)
#ifdef _WIN32_WCE

#define _DEBUG_BREAKPOINT() 
#else
#if _XBOX_VER<200 
#define _DEBUG_BREAKPOINT() __asm { int 3 } 
#else
#define _DEBUG_BREAKPOINT() DebugBreak();
#endif
#endif
#else

#define _DEBUG_BREAKPOINT() 
#endif
#else

#define _DEBUG_BREAKPOINT() 
#endif 

#define _QUOTE(x) # x

#define QUOTE(x) _QUOTE(x)

#define __FILE__LINE__ __FILE__ "(" QUOTE(__LINE__) ") : "

#undef NOTE
#define NOTE( x )  message( x )

#define FILE_LINE  message( __FILE__LINE__ )

#define TODO( x )  message( __FILE__LINE__"\n"           \
	" ------------------------------------------------\n" \
	"|  TODO :   " #x "\n" \
	" -------------------------------------------------\n" )

#define TOFIX( x )  message(  __FILE__LINE__"\n"           \
	" ------------------------------------------------\n" \
	"|  TOFIX :  " #x "\n" \
	" -------------------------------------------------\n" )

#define todo( x )  message( __FILE__LINE__" TODO :   " #x "\n" ) 

#define tofix( x )  message( __FILE__LINE__" TOFIX:   " #x "\n" ) 

#ifndef XBYTE
typedef unsigned char XBYTE;		
#endif

#ifndef XBOOL
typedef int XBOOL;					
#endif

#ifndef XWORD
typedef unsigned short XWORD;		
#endif

#ifndef XDWORD
typedef unsigned int XDWORD;		
#endif

// TODO : specify which OS does not support assert here
#ifndef _WIN32_WCE
#if defined(PSX2)
#ifdef DEBUG

#define XASSERT(a)	if(!(a)) { asm(" breakc 0x0"); asm(" nop");}
#else
#define XASSERT(a)	
#endif
#elif defined(PSP)
#ifdef _DEBUG

#ifdef __MWERKS__
#define XASSERT(a)	if(!(a)) { asm("breakc 0x0"); asm(" nop");}
#else
#define XASSERT(a)	if(!(a)) { asm("break 0x0"); asm(" nop");}
#endif
#else

#define XASSERT(a)	
#endif
	#elif defined (macintosh)
			#if defined (_DEBUG) || defined(DEBUG)
				#include <cassert>
				#define XASSERT(a)	assert(a)
			#else
				#define XASSERT(a) 
			#endif
#else
#include <cassert>
#define XASSERT(a)	assert(a)
#endif
#else
#define XASSERT(a) 
#endif

#ifndef VX_EXPORT
#ifdef VX_LIB

#define VX_EXPORT  
#else
#ifdef VX_API
#ifdef WIN32
#define VX_EXPORT __declspec(dllexport)	// VC++ export option  {secret}
#elif macintosh
#define VX_EXPORT __declspec(export)	// CodeWarrior export pragma {secret}
#elif _LINUX
#define VX_EXPORT
#endif	
#else
#ifdef WIN32
#define VX_EXPORT __declspec(dllimport)	// VC++ export option  {secret}
#elif macintosh
#define VX_EXPORT __declspec(import)	// CodeWarrior export pragma {secret}
#elif _LINUX
#define VX_EXPORT
#endif	
#endif
#endif
#endif

#ifdef WIN32
// Summary: Sort function prototype for XArray,XBinaryTree sort operations
// 
typedef int (__cdecl  *VxSortFunc)(const void *elem1, const void *elem2 );
#else
typedef int (*VxSortFunc)(const void *elem1, const void *elem2 );
#endif

//*************** X86 ASM DEFINES *************************************************

#if defined(WIN32) || defined(_XBOX)
#ifndef _WIN32_WCE

#if (_XBOX_VER<200)
#define ASM_SUPPORTED
#endif
#endif
#endif


#ifdef ASM_SUPPORTED
#pragma warning (disable:4035)
// 
inline float XCos(float f) {
	__asm {
		fld dword ptr f
			fcos
	}
}
// 
inline  float XSin(float f) {
	__asm {
		fld dword ptr f
			fsin
	}
}
#pragma warning (default:4035)
#else 
inline float XCos(float f) {
	return cosf(f);
}
inline float XSin(float f) {
	return sinf(f);
}
#endif




/*************************************************
Summary: Enables the initialisation of a reference from two values.

Arguments:
iCond:  TRUE to return iT1 , FALSE to return iT2;
*************************************************/
template <class T>
const T& ChooseRef(XBOOL iCond, const T& iT1, const T& iT2)
{
	if (iCond)
		return iT1;
	else 
		return iT2;
}

/*************************************************
Summary: Forces a value in an interval.

Arguments:
t:  value to threshold
min: minimum valid value
max: maximum valid value
See Also: XMin,XMax
*************************************************/
template <class T>
void XThreshold(T& t,const T& min,const T& max) 
{
	if (t < min) t = min;
	else if (t > max) t = max;
}


/*************************************************
Summary: Returns the minimum of two values.

Remarks:
Returns minimum between a and b.



See Also: XMax
*************************************************/
template <class T>
const T& XMin(const T& a,const T& b) 
{
	if(a < b) return a;
	else return b;
}

#ifdef PSP
inline int XMin(const int a,const int b) {
	return __builtin_allegrex_min(a,b);
}

inline float XMin(const float a,const float b) {
	if(a < b) return a;
	else return b;
}


#endif

/*************************************************
Summary: Returns the maximum of two values.

Remarks:
Returns maximum between a and b.



See Also: XMax
*************************************************/
template <class T>
const T& XMax(const T& a,const T& b) 
{
	if(a > b) return a;
	else return b;
}

#ifdef PSP
inline int XMax(const int a,const int b) {
	return __builtin_allegrex_max(a,b);
}

inline 
float XMax(const float a,const float b) {
	if(a > b) return a;
	else return b;
}

#endif

/*************************************************
Summary: Finds the minimum and maximum of 2 values.

Remarks:
Returns minimum and maximum between a,b.



See Also: XMin,XMax
*************************************************/
template <class T>
void XMinMax(const T& a,const T& b, T& min, T& max) 
{
	if (a<b) {
		min = a;
		max = b;
	} else {
		min = b;
		max = a;
	}
}


/*************************************************
Summary: Returns the minimum of two values.

Remarks:
Returns minimum between a,b and c.



See Also: XMax
*************************************************/
template <class T>
const T& XMin(const T& a,const T& b,const T& c) 
{
	return (a<b)?((c<a)?c:a):((c<b)?c:b);
}

/*************************************************
Summary: Returns the maximum of two values.

Remarks:
Returns maximum between a,b and c.



See Also: XMin
*************************************************/
template <class T>
const T& XMax(const T& a,const T& b,const T& c) 
{
	return (a>b)?((c>a)?c:a):((c>b)?c:b);
}

/*************************************************
Summary: Finds the minimum and maximum of 3 values.

Remarks:
Returns minimum and maximum between a,b and c.



See Also: XMin,XMax
*************************************************/
template <class T>
void XMinMax(const T& a,const T& b,const T& c, T& min, T& max) 
{
	if (a<b) {
		if (c<a) {
			min = c;
			max = b;
		} else {
			min = a;
			if (b<c)	max = c;
			else		max = b;
		}
	} else {
		if (c<b) {
			min = c;
			max = a;
		} else {
			min = b;
			if (a<c)	max = c;
			else		max = a;
		}
	}
}

template <class T>
void XMinMax(const T& a,const T& b,const T& c, T& min, T& med, T& max) 
{
	if (a<b) {
		if (c<a) {
			min = c;
			med = a;
			max = b;
		} else {
			min = a;
			if (b<c) {
				med = b;
				max = c;
			} else {
				med = c;
				max = b;
			}
		}
	} else {
		if (c<b) {
			min = c;
			med = b;
			max = a;
		} else {
			min = b;
			if (a<c) {
				max = c;
				med = a;
			} else {
				max = a;
				med = c;
			}
		}
	}
}

/*************************************************
Summary: Swaps two elements.

Remarks:
Swaps a and b.	


*************************************************/
template <class T>
void XSwap(T& a,T& b) 
{
	T c = a;
	a = b;
	b = c;
}
/*************************************************
Summary: Returns the absolute value of a.

Remarks:

*************************************************/
template <class T>
T XAbs(T a)
{
	return (a>0)?a:-a;
}

// float specialization
#ifdef macintosh
template <> inline float XAbs<float>(float a) {return (float)__fabs(a);}
#else
#ifdef PSP
template <> inline float XAbs<float>(float a) {
	register float fd;
	__asm__ (
		"abs.s %0, %1\n"
		: "=f"(fd)
		: "f"(a)
		);
	return (fd);
}
#else
template <> inline float XAbs<float>(float a) {return ::fabsf(a);}
#endif
#endif

/*************************************************
Summary: Returns the absolute value of a float.

Remarks:

*************************************************/
inline float XFabs(float a)
{
#ifdef macintosh
	return (float)__fabs(a);
#elif defined(PSP)
	register float fd;
	__asm__ (
		"abs.s			%0, %1\n"
		: "=f"(fd)
		: "f"(a)
		);
	return (fd);
#else	
	return ::fabsf(a);
#endif	
}

/*************************************************
Summary: Returns the square root value of a float.

Remarks:

*************************************************/
inline float XSqrt(float a)
{
#if defined(PSP)	
	return __builtin_allegrex_sqrt_s(a) ;
#else	
	return ::sqrtf(a);
#endif	
}


//------ Memory Management

#define VxNew(a) (new unsigned char[a])

#define VxDelete(a) (delete[] (unsigned char*) a)


template <class T> T* VxAllocate	(int n);

template <class T> void VxFree		(T* t);


inline int LowestBitMask(int v)
{
	return ((v & -v));
}

/*************************************************
Summary: return true if num is a power of 2

Remarks:

*************************************************/
inline XBOOL						Is2Power(int x)
{
	return x != 0 && x == LowestBitMask(x);
}

/*************************************************
Summary: return the nearest superior power of 2 of v

Remarks:

*************************************************/
inline int						Near2Power(int v)
{
	int i = LowestBitMask(v);
	while(i < v)
		i <<= 1;
	return i;
}

#if defined(PSP)

/*************************************************
Summary: perform a right bit rotation (emulates _rotl & _rotr of Windows' Stdlib)
Remarks:
Macintosh only

*************************************************/
inline int _rotr(int v, int shift)
{
	const unsigned int invShift 	= 32 - shift;
	const unsigned int mask 		= (1 << invShift) - 1;
	return ((((unsigned int)v) >> shift) & mask) | (((unsigned int)v) << invShift);
}

/*************************************************
Summary: perform a left bit rotation (emulates _rotl & _rotr of Windows' Stdlib)
Remarks:
Macintosh only

*************************************************/
inline int _rotl(int v, int shift)
{
	const unsigned int invShift 	= 32 - shift;
	const unsigned int mask 		= (1 << invShift) - 1;
	return ((((unsigned int)v) >> invShift) & mask) | (((unsigned int)v) << shift);
}

#endif


#if defined(macintosh)
/*************************************************
Summary: perform a right bit rotation (emulates _rotl & _rotr of Windows' Stdlib)
Remarks:
Macintosh only

*************************************************/
inline int _rotr(int v, int shift)
{
	const int invShift 	= 32 - shift;
	const int mask 		= (1 << invShift) - 1;
	return ((v >> shift) & mask) | (v << invShift);
}

/*************************************************
Summary: perform a left bit rotation (emulates _rotl & _rotr of Windows' Stdlib)
Remarks:
Macintosh only

*************************************************/
inline int _rotl(int v, int shift)
{
	const int invShift 	= 32 - shift;
	const int mask 		= (1 << invShift) - 1;
	return ((v >> invShift) & mask) | (v << shift);
}
#endif

/*******************************************************************************
Summary: Global Unique Identifier Struture.

Remarks: Comparison operators are defined so XGUIDS can be compared with 
==,!= ,<,> operators.
*******************************************************************************/
class XGUID
{
public:

	explicit XGUID(XDWORD gd1=0,XDWORD gd2=0)
		: d1(gd1),d2(gd2)
	{
	}

	friend XBOOL operator==(const XGUID& v1,const XGUID& v2) 
	{
		return ((v1.d1==v2.d1)&&(v1.d2==v2.d2));
	}

	friend XBOOL operator!=(const XGUID& v1,const XGUID& v2) 
	{
		return ((v1.d1!=v2.d1)||(v1.d2!=v2.d2));
	}

	friend XBOOL operator<(const XGUID& v1,const XGUID& v2) 
	{
		if(v1.d1<v2.d1)
			return true;
		if(v1.d1==v2.d1)
			return (v1.d2<v2.d2);
		return false;
	}

	friend XBOOL operator<=(const XGUID& v1,const XGUID& v2) 
	{ 	
		return (v1.d1<=v2.d1);
	}

	friend XBOOL operator>(const XGUID& v1,const XGUID& v2) 
	{
		if(v1.d1>v2.d1)
			return true;
		if(v1.d1==v2.d1)
			return (v1.d2>v2.d2);
		return false;
	}

	friend XBOOL operator>=(const XGUID& v1,const XGUID& v2) 
	{ 
		return (v1.d1>=v2.d1);
	}

	
	XBOOL inline IsValid()
	{
		return d1&&d2;
	}

	XDWORD d1;
	XDWORD d2;
};

/*******************************************************************************
Summary: Handy macro that return the number of elements in a static array.

*******************************************************************************/
#define sizeofarray(array) (sizeof(array) / sizeof((array)[0]))

/*******************************************************************************
Summary: Remove all elements that match the predicate in a sequential range. This occurs in place.
The predicate object should be stateless and provide a () operator that receive the element to be tested, and
 returns true if it is to be deleted. The order of the remaining elements is preserved.
Remarks: This function mimics the STL 'remove_if' function : it doesn't erase the last elements in a container, but returns
 a pointer on the new 'end' of the container. It is up to the caller to delete the ['new end', 'old end'] range in the container.
 It is needed because this function don't have a reference on the container. (It just knows about its iterator)
 

*******************************************************************************/
template <class Iter, class Pred> Iter XRemoveIf(Iter begin, Iter end, const Pred& predicate)
{
	if (begin == end) return end;
	XASSERT(begin);
	XASSERT(end);
	Iter dest = begin;
	Iter curr = begin;
	// search first candidate for deletion (avoid needless self assignement)
	while (curr != end && !predicate(*curr))
	{
		++ curr;
	}
	dest = curr;		
	++ curr;
	// now shift elements, skipping elements that are to be deleted
	while (curr < end)
	{
		if (predicate(*curr))
		{
			++ curr;
		}
		else
		{
			*dest++ = *curr++;
		}
	}			
	return dest;
}

/*******************************************************************************
Summary: Remove all elements that match the predicate in a vector. This occurs in place.
The predicate object should be stateless and provide a () operator that receive the element to be tested, and
returns true if it is to be deleted. The order of the remaining elements is preserved.
Remarks: This version relies on the 'ranged' version of remove_if, and takes care to resize the vector
 after the removal.


*******************************************************************************/
template <class Cont, class Pred> void XRemoveIf(Cont &cont, const Pred& predicate)
{	
	typename Cont::Iterator newEnd = XRemoveIf(cont.Begin(), cont.End(), predicate);
	cont.Resize(newEnd - cont.Begin());
}


#endif
