/*************************************************************************************************/
/*!
   	@file		debug.h
	@author 	Fanzo
 	@date 		2008/2/28
*/
/*************************************************************************************************/
#pragma		once

///////////////////////////////////////////////////////////////////////////////////////////////////
//include files
#ifdef cb_windows
	#include	<windows.h>
	#include	<stdio.h>
#elif defined(cb_mac) || defined(cb_linux)
	#include	<stdio.h>
	#include 	<stdarg.h>
	#include	<assert.h>
#endif


#pragma pack( push , 8 )		//set align

namespace icubic
{

///////////////////////////////////////////////////////////////////////////////////////////////////
// preprocessor deifne

#ifdef NDEBUG
	#define		cb_release
#else
	#define		cb_debug
#endif

#ifdef cb_debug
	#define		cb_verify( exp )																	\
	{																								\
		if( false == (exp) )																		\
			icubic::Assert_debug( L"verify" , cb_file , cb_line , cb_stringize( exp ) );			\
	}																
	#define		cb_assert( exp , ... )																\
	{																								\
		if( false == (exp) )																		\
			icubic::Assert_debug( L"assert" , cb_file , cb_line , __VA_ARGS__ );					\
	}
	#define		cb_trace( ... )																		\
	{																								\
		icubic::Trace_debug( __VA_ARGS__ );															\
	}			
#else
	#define		cb_verify( exp )	((void)(exp))
	#define		cb_assert( ck , ... )	
	#define		cb_trace( ... )	
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////
// type define

///////////////////////////////////////////////////////////////////////////////////////////////////
// classes define

#ifdef cb_debug
//=================================================================================================
cb_inline
bool MessageBox_debug
		(
		const wchar_t*	title , 
		const wchar_t*	mes
		)
{
#ifdef cb_windows
	if( IDCANCEL == ::MessageBoxW( NULL , mes , title , MB_RETRYCANCEL | MB_SYSTEMMODAL | MB_ICONERROR ) )
		return true;
	return false;
#else
	#error	unknown os.
#endif
}
//=================================================================================================
cb_inline
void OutputMessage_debug
		(
		const wchar_t*	mes
		)
{
#if defined(cb_mac) || defined(cb_linux)
	fwprintf( stderr , mes );
#elif defined(cb_windows)
	::OutputDebugStringW( mes );
#else
	#error unknown os.
#endif
}
//=================================================================================================
cb_inline
void Assert_debug
		(
		const wchar_t*	title , 
		const wchar_t*	file , 
		int				line , 
		const wchar_t*	format , 
		...
		)
{
	//create message
	wchar_t		mes[ 256 ];
	{
		va_list	args;
		va_start( args , format );
#if defined(cb_mac) || defined(cb_linux)
		_vsnwprintf( mes , _countof( mes ) - 1 , format , args );
#elif defined(cb_windows)
		_vsnwprintf_s( mes , _countof( mes ) - 1 , _TRUNCATE , format , args );
#endif
		va_end( args );
		mes[ _countof( mes ) - 1 ] = L'\0';
	}
	
	//create filename and line
	wchar_t	buf[ 256 ];
#if defined(cb_mac) || defined(cb_linux)
	_snwprintf( buf , _countof( buf ) - 1 , L"Assert:\n%s\nline( %d )\n%s" , file , line , mes );
#elif defined(cb_windows)
	_snwprintf_s( buf , _countof( buf ) - 1 , _TRUNCATE , L"%s\nline( %d )\n%s" , file , line , mes );
#endif
	buf[ _countof( buf ) - 1 ] = L'\0';
	
	// output message
	OutputMessage_debug( buf );
	if( true == MessageBox_debug( title , buf ) )
		exit( 0 );
}
//=================================================================================================
cb_inline
void Trace_debug
		(
		const wchar_t*	format , 
		...
		)
{
	//create string.
	wchar_t	mes[ 256 ];
	{
		va_list	args;
		va_start( args , format );
#if defined(cb_mac) || defined(cb_linux)
		_vsnwprintf( mes , _countof( mes ) - 1 , format , args );
#elif defined(cb_windows)
		_vsnwprintf_s( mes , _countof( mes ) - 1 , _TRUNCATE , format , args );
#endif
		va_end( args );
		mes[ _countof( mes ) - 1 ] = L'\0';
	}
	OutputMessage_debug( mes );
}
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////
// global variable define

///////////////////////////////////////////////////////////////////////////////////////////////////
// global functions define

};	//namespace

//using namespace icubic;		

#pragma pack( pop )			//release align
