//////////////////////////////////////////////////////////////////////////////
//
// Asura_Assert.h
//
// Copyright (c) 2001 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#define ASURA_PLATFORM_ASSERT_OVERRIDES_INDEPENDENT_CODE

#ifndef __ASURA_PLATFORM_ASSERT_H__
#define __ASURA_PLATFORM_ASSERT_H__ 1

// D E F I N E S /////////////////////////////////////////////////////////////

#ifdef _MSC_VER
    #define ASURA_PS2_DEBUG_BREAK() { }
#else
    #if _DEBUG
        // The debugger is a bit broken wrt scope with break instructions so
        // in debug builds insert a NOP to fix it.
        #define ASURA_PS2_DEBUG_BREAK() \
        { \
            asm __volatile__( "break 1" ); \
            asm __volatile__( "nop" ); \
        }
    #else
        #define ASURA_PS2_DEBUG_BREAK() { asm __volatile__( "break 1" ); }
    #endif
#endif

#ifdef _lint
// (MP - 16.09.2002) Shut Lint up about code like Asura_Assert( false, "" );
// and similar.
//lint -emacro(774, Asura_Assert) // Boolean always evaluates to true / false.
//lint -emacro(778, Asura_Assert) // Constant expression evaluates to 0.
//lint -emacro(774, Asura_Assertf) // Boolean always evaluates to true / false.
//lint -emacro(778, Asura_Assertf) // Constant expression evaluates to 0.

// (MP - 01.10.2002) Shut Lint up about asserts in inline functions in
// headers.
//lint -emacro(1534,Asura_Assert)
//lint -emacro(1534,Asura_Assertf)
#endif

#ifndef __SN_FILE__
#define __SN_FILE__ __FILE__
#endif

// (MP - 01.02.2002) Note that ASURA_ASSERT is #defined in the compiler
// command line on a per-configuration basis.
// (MP - 27.03.2003) Now using new __SN_FILE__ preprocessor define to reduce
// executable sizes.
#ifdef ASURA_ASSERT

	extern u_char g_ucAssertIgnoreCounter;

    #if _DEBUG

        #define Asura_Assert( __cond, __desc ) \
        { \
			static u_char ucIgnore = 0; \
			if( ucIgnore != g_ucAssertIgnoreCounter ) \
	        { \
		        if( !(__cond) ) \
		        { \
			        if( Asura_AssertFired(__SN_FILE__, __LINE__, #__cond, __desc, &ucIgnore) ) \
			        { \
                        ASURA_PS2_DEBUG_BREAK(); \
			        } \
		        } \
	        } \
        } 

        #define Asura_Assertf( __cond, __params ) \
        { \
			static u_char ucIgnore = 0; \
			if( ucIgnore != g_ucAssertIgnoreCounter ) \
	        { \
		        if( !(__cond) ) \
		        { \
                    Asura_AssertfSetup(__SN_FILE__, __LINE__, #__cond, &ucIgnore); \
			        if( Asura_AssertfFired __params ) \
			        { \
                        ASURA_PS2_DEBUG_BREAK(); \
			        } \
		        } \
	        } \
        } 

    #else // else not _DEBUG

        // (MP - 26.03.2003) To reduce the size of the artist executable,
        // we'll

        #define Asura_Assert( __cond, __ignored ) \
        { \
			static u_char ucIgnore = 0; \
			if( ucIgnore != g_ucAssertIgnoreCounter ) \
	        { \
		        if( !(__cond) ) \
		        { \
					if( Asura_AssertFired(__SN_FILE__, __LINE__, NULL, NULL, &ucIgnore) ) \
			        { \
                        ASURA_PS2_DEBUG_BREAK(); \
			        } \
		        } \
	        } \
        } 

        #define Asura_Assertf( __cond, __params ) \
        { \
            Asura_Assert( __cond, NULL ); \
        }

    #endif // end else not _DEBUG

	//supresses all the assert dialogs , just leaving a single entry in the logfile per assert RAR 02/06/03
	void AsuraAssert_SetIgnoreAll(bool bIgnore);
	bool AsuraAssert_GetIgnoreAll();

	void AsuraAssert_ReEnableAll();	// Turn all asserts which have been skipped with "Ignore All" back on
	bool AsuraAssert_ConsoleCmd_EnableAsserts( bool bHelp );

#else // else ndef ASURA_ASSERT
    #define Asura_Assert( __cond, __desc ) {}
    #define Asura_Assertf( __cond, __params ) {}
   
	#define AsuraAssert_SetIgnoreAll(bIgnore)
	#define AsuraAssert_GetIgnoreAll(bIgnore) true
	#define AsuraAssert_ReEnableAll()
	#define AsuraAssert_ConsoleCmd_EnableAsserts(bHelp) true
#endif // #ifdef ASURA_ASSERT

// P R O T O T Y P E S ///////////////////////////////////////////////////////

#ifdef ASURA_ASSERT

bool Asura_AssertFired( const char* szFile, int iLine, const char* szCondition, const char* szDesc, bool* pbIgnore );
void Asura_AssertfSetup( const char* szFile, int iLine, const char* szCondition, bool* pbIgnore);
bool Asura_AssertfFired( const char* szFormat, ... );

bool Asura_PS2_IsInAssert( void );

#else

static inline bool Asura_PS2_IsInAssert( void ) { return false; }

#endif


// KJFL - 22 March 2006 - Static, i.e. compile-time, assertions
// For documentation see http://asurawiki.rebellion.co.uk/twiki/bin/viewauth/Programming/AsuraStaticAssert

template<bool b> struct ASURA_STATIC_ASSERTION_FAILURE;
template <> struct ASURA_STATIC_ASSERTION_FAILURE<true> {};

#define ASURA_COMBINE_LITERALS( a, b ) a ## b
#define ASURA_STATIC_ASSERT_UNIQUENAME( a ) ASURA_COMBINE_LITERALS( ASURA_STATIC_ASSERT_FAILED_AT_LINE_, a )

#define ASURA_STATIC_ASSERT( bCondition ) static ASURA_STATIC_ASSERTION_FAILURE<(bCondition != 0)> ASURA_STATIC_ASSERT_UNIQUENAME(__LINE__) 


// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef __ASURA_PLATFORM_ASSERT_H__
