/****************************************************************************************


		MCAssert.h


		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Ian
		Date:	12/13/97

		Revision History

		when		who			what & why
		==========	==========	======================================================
		05/04/99	Nba			fixed notify in non Debug mode
		04/16/99	Nba			Added MC_DisplayMessageQuiet
		2/4/99		Ian			MC_CallNotify_() all take const char* now.
		12/3/98		Ian			Added MC_Assert namespace with DisplayingAssert() call.
		10/14/98	Ian			MCAssert and MCVerify now display the condition that
								caused the alert.
		10/5/98		Alec		added MCAssert_ActivateDialogs() so both the shell
									and the extensions can set the flag to post dialogs
		7/5/98		Ian			Yanked MCOSConfig.h.
		6/16/98		Alec		changed NULL back to 0 so ptr asserts compile
		6/5/98		Ian			MCAssertPointerCheck(): Added a test for 0xDECEA5ED,
								which is what we set our deleted memory to.
		5/2/98		Ian			Use MC_CallNotify_ for Pointer check failures.
								Added levels of Incomplete code notification.
		4/6/98		pbk			Introduced implementaion based on PB
	
*****************************************************************************************/

#ifndef __MCAssert__
#define __MCAssert__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCCompiler.h"
#include "MCBasicTypes.h"
#include <limits>

#define kMCStrUnderConstruction		"Not Yet Implemented"
#define kMCStrBadPtr				"Bad Pointer"

#undef	Assert
#undef	Verify
#undef	MCAssert
#undef	MCVerify

void MCAssert_ActivateDialogs( void );

#if Debug_

#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif

	#define Assert(e)			( (e) ? 0 : (MC_CallAssert_(__FILE__, __LINE__), 0));
	#define Verify(e)			( (e) ? 1 : (MC_CallAssert_(__FILE__, __LINE__), 0))

	#define MCAssert(e)			( (e) ? 0 : (MC_CallNotify_(__FILE__, __LINE__, #e), 0));
	#define MCAssertMCSizeCanFit(value, testType)	MCAssert((value) <= static_cast<MCSize>(std::numeric_limits<testType>::max()));
        #define MCAssertCanFit(value, testType, origType)	MCAssert((value) <= static_cast<origType>(std::numeric_limits<testType>::max()));
	#define MCVerify(e)			( (e) ? 1 : (MC_CallNotify_(__FILE__, __LINE__, #e), 0))
	#define MCVerifyNot(e)		( (e) ? (MC_CallNotify_(__FILE__, __LINE__, #e), 1) : 0)

	#define MCNotify(e)			( MC_CallNotify_(__FILE__, __LINE__, e) )	
	#define MCNotifyN(e,n)		( MC_CallNotify_(__FILE__, __LINE__, e, n) )	
	#define MCNotifyN2(e,n1,n2)	( MC_CallNotify_(__FILE__, __LINE__, e, n1, n2) )	
                             
#if BreakIncomplete_
	#define MCIncomplete()		( #error Incomplete )
#elif NotifyIncomplete_
	#define MCIncomplete()		( MC_CallNotify_(__FILE__, __LINE__, kMCStrUnderConstruction) )
#else
	#define MCIncomplete()
#endif

#define MCAssertPointerCheck(_ptr) 			( ((!(_ptr)) || MCCheckDeceased(_ptr)) ? (MC_CallNotify_(__FILE__, __LINE__, kMCStrBadPtr), 0) : 0)

#else

	#define Assert(e)			  
	#define Verify(e)			(e)
	  
	#define MCAssert(e)			  
	#define MCAssertMCSizeCanFit(value, testType)
        #define MCAssertCanFit(value, testType, origType)
	#define MCVerify(e)			(e)
	#define MCVerifyNot(e)		(e)

	#define MCNotify(e)
	#define MCNotifyN(e1,e2)
	#define MCNotifyN2(e1,e2,e3)

	#define MCIncomplete()

	#define MCAssertPointerCheck(_ptr)								

#endif

#pragma warning (push)
#pragma warning (disable: 4312)
#if defined(ARCH_X64)
static const void* kDeceasedPointerValue = (const void*)0xDECEA5EDDECEA5EDULL;
#else
static const void* kDeceasedPointerValue = (const void*)0xDECEA5ED;
#endif
#pragma warning (pop)
#define MCCheckDeceased(_ptr) 		((_ptr) == kDeceasedPointerValue)

#define MCAssertMessage(_msg)			MCNotify(_msg)
#define MCAssertIfFalse(_condition)		MCAssert(_condition)
#define MCAssertIfTrue(_condition)		MCAssert(!(_condition))


template<class T>
inline T MCPointerSignedConvert(void* ptr)
{
#ifdef _MSC_VER // GCC has a problem with MCAssert inside a template
	MCAssert((pointerdiff)ptr < std::numeric_limits<T>::max() && (pointerdiff)ptr > std::numeric_limits<T>::min());
#endif
	return (T)(pointerdiff)ptr;
}

template<class T>
inline T MCPointerUnsignedConvert(void* ptr)
{
#ifdef _MSC_VER // GCC has a problem with MCAssert inside a template
	MCAssert((uintpointer)ptr < std::numeric_limits<T>::max());
#endif
	return (T)(uintpointer)ptr;
}

template<class T>
inline void* MCSignedPointerConvert(const T& v)
{
	return (void*)(pointerdiff)v;
}

template<class T>
inline void* MCUnsignedPointerConvert(const T& v)
{
	return (void*)(uintpointer)v;
}

// =================================================================================================================
// Debug Functions
// =================================================================================================================

void MC_CallAssert_			(pointer f, uint32 l);
void MC_CallNotify_			(pointer f, uint32 l, const char* message); 
void MC_CallNotify_			(pointer f, uint32 l, const char* message, real number); 
void MC_CallNotify_			(pointer f, uint32 l, const char* message, real number1, real number2);

void MC_DisplayMessageQuiet	(const char* message);

extern boolean IsDisplayingAssert	();



#endif
