//
// Asura_Platform_Assert.cpp
//
// Created by Kevin Lea		- 12/06/2001 11:14:17
// Renamed by Simon Watson	- 11/05/2009 14:31
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

#ifdef ASURA_ASSERT

// This file's header.
#include "Debugging/Asura_Platform_Assert.h"

// Engine independent.
#ifdef ASURA_MAIN
	#include "Core/Asura_Core.h"
	#include "Core/Asura_UserInput.h"
#endif
#include "Core/Asura_CallStack.h"
#include "Core/Asura_String.h"
#include "Debugging/Asura_Debug_Timers.h"
#include "Debugging/Asura_Logfile.h"
#include "Debugging/Asura_Version.h"

// Engine platform-specific.
#include "Core/Asura_Windows.h"

// Stdlib independent.
#include <time.h>
#include "resource.h"

// Assert timeouts?
#ifndef ASURA_ASSERT_TIMEOUT
	#define ASURA_ASSERT_TIMEOUT				30	// 30 seconds timeout by default
#endif // ASURA_ASSERT_TIMEOUT

#ifndef ASURA_ASSERT_TIMEOUT_BUTTON
	#define ASURA_ASSERT_TIMEOUT_BUTTON			IDC_ASSERT_IGNOREALWAYS	// default to "Ignore Always" IDC_ASSERT_IGNOREALWAYS
#endif // ASURA_ASSERT_TIMEOUT_BUTTON


#if ( ASURA_ASSERT_TIMEOUT_BUTTON == IDC_ASSERT_BREAK )
	#define ASURA_ASSERT_TIMEOUT_BUTTON_TEXT	"Break"
#elif ( ASURA_ASSERT_TIMEOUT_BUTTON == IDC_ASSERT_IGNOREONCE )
	#define ASURA_ASSERT_TIMEOUT_BUTTON_TEXT	"Ignore Once"
#elif ( ASURA_ASSERT_TIMEOUT_BUTTON == IDC_ASSERT_IGNOREALWAYS )
	#define ASURA_ASSERT_TIMEOUT_BUTTON_TEXT	"&Ignore Always"
#elif ( ASURA_ASSERT_TIMEOUT_BUTTON == IDC_ASSERT_DISABLE )
	#define ASURA_ASSERT_TIMEOUT_BUTTON_TEXT	"Disable Asserts"
#else
	#pragma message( __FILE__ ": #define ASURA_ASSERT_TIMEOUT_BUTTON is unknown button - choices are IDC_ASSERT_BREAK, IDC_ASSERT_IGNOREONCE, IDC_ASSERT_IGNOREALWAYS (default), IDC_ASSERT_DISABLE." )
	#undef	ASURA_ASSERT_TIMEOUT_BUTTON
	#define ASURA_ASSERT_TIMEOUT_BUTTON			IDC_ASSERT_IGNOREALWAYS
	#define ASURA_ASSERT_TIMEOUT_BUTTON_TEXT	"&Ignore Always"
#endif

#ifndef ASURA_ASSERT_LOGONLY
static void CopyAssertToClipboard( const char* szText );
#ifdef NDEBUG
static bool DisplayReleaseAbortDialog( void );
#endif
#endif

static bool g_bShuttingDown = false;

static const char ASSERTION_LOGFILE_TXT[ MAX_PATH] = "logfiles\\Assert!.txt";

const u_int ASSERT_BUFFER_SIZE = 8*1024;

bool g_bInitedCS;
static CRITICAL_SECTION g_xAssertCritSec;
class CriticalSectionHolder
{
	CRITICAL_SECTION &m_xAssertCritSec;
public:
	CriticalSectionHolder(CRITICAL_SECTION &xAssertCritSec) : m_xAssertCritSec(xAssertCritSec)
	{
		EnterCriticalSection(&m_xAssertCritSec);
	}
	~CriticalSectionHolder()
	{
		LeaveCriticalSection(&m_xAssertCritSec);
	}
};



////////////////////////////////////////////////////////////////////////////////////////////////
/*--------------------**
** Asura_AssertDialog **
**--------------------*/
class Asura_AssertDialog
{
public :
	//returns id of button pressed (IDC_ASSERT_BREAK,IDC_ASSERT_IGNOREONCE,IDC_ASSERT_IGNOREALWAYS,IDC_ASSERT_DISABLE)
	static int DoModal(const char* pszText);

private :
	Asura_AssertDialog(const char* pszText)
#if( ASURA_ASSERT_TIMEOUT > 0 )
	: m_iTimeoutCountdown( ASURA_ASSERT_TIMEOUT )
#endif //( ASURA_ASSERT_TIMEOUT > 0 )
	{
		m_pszText = pszText;
	}

	static INT_PTR CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	void OnInitDialog(HWND hWnd);

	const char* m_pszText;
#if( ASURA_ASSERT_TIMEOUT > 0 )
	int m_iTimeoutCountdown;
	void SetTimeoutText( HWND hWnd );
#endif // ( ASURA_ASSERT_TIMEOUT > 0 )
	void ClearDialog( HWND hWnd );
};

int Asura_AssertDialog::DoModal(const char* pszText)
{
	Asura_AssertDialog xDialog(pszText);

	HINSTANCE hInstance = Asura_Windows::GetWindowhInstance();
	#ifdef ASURA_MAIN
	HWND hWnd = (Asura_Core::IsMainThread()) ? Asura_Windows::GetWindowHandle() : NULL;
	#else
	HWND hWnd = Asura_Windows::GetWindowHandle();
	#endif
	DLGPROC pxDlgProc = WindowProc;
	INT_PTR iRet = DialogBoxParam
		(
		hInstance,
		MAKEINTRESOURCE(IDD_ASSERT),
		hWnd,
		pxDlgProc,
		(LPARAM)&xDialog
		);

	return( static_cast< int>( iRet));
}

INT_PTR CALLBACK Asura_AssertDialog::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	Asura_AssertDialog *pxThis = (Asura_AssertDialog*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
	if (!pxThis && uMsg!=WM_INITDIALOG) return FALSE;


	switch(uMsg)
	{
	case WM_INITDIALOG:	
		{
			// Update class pointer
			pxThis = (Asura_AssertDialog*)lParam;
			SetWindowLongPtr(hWnd,GWLP_USERDATA,lParam);

			pxThis->OnInitDialog(hWnd);
			return FALSE;
		}

	case WM_DESTROY:
		return TRUE;

	case WM_COMMAND:
		{
			int iControlID = LOWORD(wParam);

			switch (iControlID)
			{
			case IDC_ASSERT_BREAK:
			case IDC_ASSERT_IGNOREONCE:
			case IDC_ASSERT_IGNOREALWAYS:
			case IDC_ASSERT_DISABLE:
#if( ASURA_ASSERT_TIMEOUT > 0 )
				if( pxThis->m_iTimeoutCountdown != 0 )
				{
					KillTimer( hWnd, 1 );
				}
#endif //( ASURA_ASSERT_TIMEOUT > 0 )

				pxThis->ClearDialog( hWnd );
				EndDialog(hWnd,iControlID);
				return TRUE;
			}
			break;
		}				
#if( ASURA_ASSERT_TIMEOUT > 0 )
	case WM_TIMER:
		if( wParam == 1 )
		{
		#if( defined( IDC_CHECK_PAUSE_TIMEOUT ) )
			HWND hWndControl = GetDlgItem( hWnd, IDC_CHECK_PAUSE_TIMEOUT );
			if( ( hWndControl == NULL ) || 
				( SendMessage( hWndControl, BM_GETCHECK, 0, 0 ) != BST_CHECKED ) )
		#endif // ( defined( IDC_CHECK_PAUSE_TIMEOUT ) )
			{
				pxThis->m_iTimeoutCountdown--;
			}
			pxThis->SetTimeoutText( hWnd );
			if( pxThis->m_iTimeoutCountdown == 0 )
			{
				KillTimer( hWnd, 1 );
				pxThis->ClearDialog( hWnd );
				EndDialog( hWnd, ASURA_ASSERT_TIMEOUT_BUTTON );
				return TRUE;
			}
		}
		return TRUE;
#endif //( ASURA_ASSERT_TIMEOUT > 0 )
	}
	return FALSE;
}

void Asura_AssertDialog::OnInitDialog(HWND hWnd)
{
	
	#ifdef ASURA_MAIN
	bool bApplicationIsActive = Asura_Windows::IsApplicationActive();
	#endif
	
	//set the assert text
	if(m_pszText)
	{
		//The edit controls expects all \n's to have a \r before them , so copy the text
		//and update any lone \n's
		char szText[ASSERT_BUFFER_SIZE];

		const char* pcFrom = m_pszText;
		char* pcTo = szText;

		//('-3' is to make sure there is room for 2 characters and a terminator)
		for(int iPos=0;iPos<ASSERT_BUFFER_SIZE-3 && *pcFrom;)
		{
			if(*pcFrom == '\n')
			{
				*pcTo++ = '\r';
				*pcTo++ = '\n';
				pcFrom++;
				iPos+=2;
			}
			else if(*pcFrom == '\r')
			{
				//ignore , will be added if needed
				*pcFrom++;
			}
			else
			{
				//copy as is
				*pcTo++ = *pcFrom++;
				iPos++;
			}
		}
		//add terminator
		*pcTo++ = 0;


		HWND hWndControl = GetDlgItem(hWnd,IDC_ASSERT_TEXT);
		if(hWndControl)
		{
			SetWindowText(hWndControl,szText);
		}
	}

	//set focus on the ignore always button
	HWND hWndControl = GetDlgItem(hWnd, IDC_ASSERT_IGNOREALWAYS );
	if(hWndControl)
	{
		SetFocus(hWndControl);
	}

#ifndef ASURA_ALLOW_DISABLE_ASSERTS
	hWndControl = GetDlgItem(hWnd,IDC_ASSERT_DISABLE);
	if(hWndControl)
	{
		//disable disable asserts
		EnableWindow(hWndControl,FALSE);
		ShowWindow(hWndControl,SW_HIDE);
	}

#endif

#if( ASURA_ASSERT_TIMEOUT > 0 )
	SetTimer( hWnd, 1, 1000, NULL );
	SetTimeoutText( hWnd );
#else // ( ASURA_ASSERT_TIMEOUT > 0 )
	#if( defined( IDC_CHECK_PAUSE_TIMEOUT ) )
	hWndControl = GetDlgItem( hWnd, IDC_CHECK_PAUSE_TIMEOUT );
	if( hWndControl != NULL )
	{
		//disable the pause timeout
		EnableWindow( hWndControl, FALSE );
		ShowWindow( hWndControl, SW_HIDE );
	}
	#endif //( defined( IDC_CHECK_PAUSE_TIMEOUT ) )
#endif // ( ASURA_ASSERT_TIMEOUT > 0 )

	//Cause the assert dialog box to take focus, if the application isn't minimised or in the background
	//Asura_Windos::IsApplicationActive() is checked at the start of the function , since it becomes
	//true when the ignore button is given focus.
	//RAR 14//11/2007
	#ifdef ASURA_MAIN
	if(bApplicationIsActive)
	#endif
	{
		SetForegroundWindow( hWnd );
	}
	SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE );

	//Remove the topmost flag , so that the dialog box should remain
	//in front of everything , while allowing it to be moved into the background.
	//RAR 14/11/2007
	SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE );

}

#if( ASURA_ASSERT_TIMEOUT > 0 )

void Asura_AssertDialog::SetTimeoutText( HWND hWnd )
{
	HWND hWndControl = GetDlgItem( hWnd, ASURA_ASSERT_TIMEOUT_BUTTON );
	if( hWndControl != NULL )
	{
		char szTimer[ 256 ];
		Asura_PrintfToBfr( szTimer, ASURA_ASSERT_TIMEOUT_BUTTON_TEXT " (%d)", sizeof( szTimer ), true, m_iTimeoutCountdown );
		SetWindowText( hWndControl, szTimer );
	}
}

#endif //( ASURA_ASSERT_TIMEOUT > 0 )

void Asura_AssertDialog::ClearDialog( HWND hWnd )
{
	// DLH - Clears the contents of the dialog so an image is not left on screen and fooling people that an assert is waiting to be dealt with
	HDC hDC = GetDC( hWnd);
	if( NULL != hDC)
	{
		RECT xClientRect;
		HBRUSH hBrush = GetStockBrush( LTGRAY_BRUSH);
		GetClientRect( hWnd, &xClientRect);
		FillRect( hDC, &xClientRect, hBrush);
		ReleaseDC( hWnd, hDC);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////

bool Asura_AssertFired(const char* file, int line, const char* condition, const char* desc, u_char* pucIgnore)
{
	ASURA_CPU_PROFILE_SCOPED_TIMER( "Asura_AssertFired");
	if (!g_bInitedCS)
	{
		g_bInitedCS = true;
		InitializeCriticalSection(&g_xAssertCritSec);
	}

	CriticalSectionHolder CritSec(g_xAssertCritSec);

	if(g_bShuttingDown)
	{
		return false;
	}

	char text[ASSERT_BUFFER_SIZE];

	const u_int TIME_AND_DATE_BUFFER_SIZE = 100;
	char buffer[TIME_AND_DATE_BUFFER_SIZE];
	char buffer2[TIME_AND_DATE_BUFFER_SIZE];
	{
		SYSTEMTIME time_of_day;
		GetLocalTime(&time_of_day);

		GetDateFormat(GetThreadLocale(), DATE_LONGDATE, &time_of_day,NULL,buffer,TIME_AND_DATE_BUFFER_SIZE - 1);
		GetTimeFormat(GetThreadLocale(), 0, &time_of_day,NULL,buffer2,TIME_AND_DATE_BUFFER_SIZE - 1);
	}

	if(!strcmp(condition,"0")) condition = "";
	
	static const u_int uCallStackBufferSizeMax = ASSERT_BUFFER_SIZE;
	char szCallStackBuffer[ uCallStackBufferSizeMax + 1] = {0};
	#if defined( ASURA_TOOLS)
		char szCallStackXMLBuffer[ uCallStackBufferSizeMax + 1] = {0};
	#endif
	
	{
		void* pCallStack = Asura_CallStack::Platform_CreateStackDump( 2);
		if( NULL != pCallStack)
		{
			Asura_CallStack::Platform_GetHumanReadableStackDump( pCallStack, szCallStackBuffer, uCallStackBufferSizeMax);
			#if defined( ASURA_TOOLS)
				Asura_CallStack::Platform_GetXMLStackDump( pCallStack, szCallStackXMLBuffer, uCallStackBufferSizeMax);
			#endif
			Asura_CallStack::Platform_DeallocStackDump( pCallStack);
		}
	}


	int iBufferPos = 0;
	//Add header to text buffer
	Asura_PrintfToBfr(&text[iBufferPos], 
						"Assertion failed%s: %s\r\n\r\n%s\r\n\r\nIn file: \"%s\"\r\nAt line: %d\r\n", 
						ASSERT_BUFFER_SIZE - iBufferPos, true,
						#ifdef ASURA_MAIN
						Asura_Core::IsMainThread() ? "(Main Thread)" : "(Not Main Thread)",
						#else
						"",
						#endif
						condition, desc, file, line);

	iBufferPos += strlen(&text[iBufferPos]);

	//add stack information to text buffer if available
	if(szCallStackBuffer[0])
	{
		Asura_PrintfToBfr(&text[iBufferPos], 
							"\r\nStack:\r\n\r\n%s\r\n\r\n",
							ASSERT_BUFFER_SIZE - iBufferPos, true,
							szCallStackBuffer);

		iBufferPos += strlen(&text[iBufferPos]);
	}

	//Add time stamps to text buffer
	Asura_PrintfToBfr(&text[iBufferPos],
						 "\r\nBuild timestamp: %s\r\nError timestamp: %s, %s.\r\n",
						 ASSERT_BUFFER_SIZE - iBufferPos, true,
						 Asura_BuildTimeAndDate,buffer2,buffer);
	iBufferPos += strlen(&text[iBufferPos]);




	// (MH - 06.06.2002) use simple logfile to avoid manipulating asura strings.
	//Asura_Logfile_Retail(("logfiles\\Assert!.txt",text2));
#ifdef ASURA_MAIN
//	static bool bFirstTimeAssertFired = true;
	AsuraAssert_LogClearLog();

	Asura_SimpleLogfileOutput((ASSERTION_LOGFILE_TXT, "--------------------------------------------------------------------------------\n\n" ));
	Asura_SimpleLogfileOutput((ASSERTION_LOGFILE_TXT, text));
	Asura_SimpleLogfileOutput((ASSERTION_LOGFILE_TXT, "\n--------------------------------------------------------------------------------\n\n\n" ));

	Asura_OutputToDebugger_Retail(("------------------------------------------------------------------------------------------------\n"));
	Asura_OutputToDebugger_Retail(("Assertion failed: \"%s\"\n%s\n\n%s(%d)\n", condition, desc, file, line));
	Asura_OutputToDebugger_Retail(("------------------------------------------------------------------------------------------------\n\n"));

	#if defined( ASURA_TOOLS)
	if( AsuraAssert_ShouldLogToXML() )
	{
		char dateXMLbuffer[TIME_AND_DATE_BUFFER_SIZE];
		char timeXMLbuffer[TIME_AND_DATE_BUFFER_SIZE];
		
		SYSTEMTIME time_of_day;
		GetLocalTime(&time_of_day);

		GetDateFormat(GetThreadLocale(), 0, &time_of_day, "yyyy-MM-dd",dateXMLbuffer,TIME_AND_DATE_BUFFER_SIZE - 1);
		GetTimeFormat(GetThreadLocale(), 0, &time_of_day, "HH:mm:ss",timeXMLbuffer,TIME_AND_DATE_BUFFER_SIZE - 1);
		
		static const u_int textXMLSize = 2 * ASSERT_BUFFER_SIZE;
		char textXML[ textXMLSize + 1];
		
		char textFilenameXML[ textXMLSize + 1];
		char textConditionXML[ textXMLSize + 1];
		char textDescriptionXML[ textXMLSize + 1];
		
		Asura_SimpleLogfileConvertToXML( file, textFilenameXML, textXMLSize);
		Asura_SimpleLogfileConvertToXML( condition, textConditionXML, textXMLSize);
		Asura_SimpleLogfileConvertToXML( desc, textDescriptionXML, textXMLSize);
		
		u_int uTextXMLSize = Asura_PrintfToBfr( textXML,
			"<assert filename=\"%s\" fileline=\"%d\"><condition>%s</condition><description>%s</description>"
			"%s"
			"<buildtime value=\"%s\"/><errortime value=\"%sT%s\"/></assert>",
			
			textXMLSize, true,
			textFilenameXML, line,
			textConditionXML, textDescriptionXML,
			szCallStackXMLBuffer,
			Asura_BuildTimeAndDate, dateXMLbuffer, timeXMLbuffer);

		if( (textXMLSize-1) <= uTextXMLSize)
		{
				uTextXMLSize = Asura_PrintfToBfr( textXML,
				"<assert filename=\"%s\" fileline=\"%d\"><condition>%s</condition><description>%s</description>"
				"<buildtime value=\"%s\"/><errortime value=\"%sT%s\"/></assert>",

				textXMLSize, true,
				textFilenameXML, line,
				textConditionXML, textDescriptionXML,
				Asura_BuildTimeAndDate, dateXMLbuffer, timeXMLbuffer);
		}
		if( uTextXMLSize < (textXMLSize-1))
		{
			Asura_SimpleLogfileOutputXML( (AsuraAssert_GetXMLLogFilename(), textXML));
		}
	}
	#endif
#endif

#ifdef ASURA_ASSERT_LOGONLY

	// only log first hit for each assert
	*pucIgnore = g_ucAssertIgnoreCounter;
	return false;

#else

	int value;
	if( AsuraAssert_GetIgnoreAll() )
	{
		AsuraAssert_RecordAssertHitWhileIgnoringAll();
		value = IDC_ASSERT_IGNOREALWAYS;
	}

	// Windows specific!
#ifndef ASURA_MAIN
	if(!AsuraAssert_GetIgnoreAll())
	{
		value = Asura_AssertDialog::DoModal(text);
	}
#else	



	if(!AsuraAssert_GetIgnoreAll())
	{
		Asura_Windows::PreShowDialogBox();
		value = Asura_AssertDialog::DoModal(text);
		Asura_Windows::PostShowDialogBox();
	}
#endif


	switch(value)
	{
	default:
	case IDC_ASSERT_BREAK:
		{
			CopyAssertToClipboard( text );

#ifdef NDEBUG
			if( IsDebuggerPresent() )
			{
				return true;
			}
			else
			{
				return DisplayReleaseAbortDialog();
			}
#else
			return true;
#endif
		}

	case IDC_ASSERT_DISABLE :
		{
			//ignore all subsequence asserts
			AsuraAssert_SetIgnoreAll(true);
			//and ignore this one
			*pucIgnore = g_ucAssertIgnoreCounter;
			return false;
		}

	case IDC_ASSERT_IGNOREALWAYS:
		{
			*pucIgnore = g_ucAssertIgnoreCounter;
			return false;
		}

	case IDC_ASSERT_IGNOREONCE:
		{
			return false;
		}
	}

#endif // #else not #ifdef ASURA_ASSERT_LOGONLY

}

// (MH - 01.11.2002) paramaterised assert
static const char*  g_szAsuraAssertfFile;
static int          g_iAsuraAssertfLine;
static const char*  g_szAsuraAssertfCondition;
static u_char*      g_pucAsuraAssertfIgnore;
static const int    ASURAASSERTF_OUTPUT_BUFFER_SIZE = 2048;
static char         g_szOutputBuffer[ASURAASSERTF_OUTPUT_BUFFER_SIZE];

bool Asura_AssertfSetup( const char* szFile, int iLine, const char* szCondition, u_char* pucIgnore)
{
	//Make sure another Assertf isn't already in progress. RAR 26/10/2006
	if(g_pucAsuraAssertfIgnore) return false;

	g_szAsuraAssertfFile = szFile;
	g_iAsuraAssertfLine = iLine;
	g_szAsuraAssertfCondition = szCondition;
	g_pucAsuraAssertfIgnore = pucIgnore;
	return true;
}

bool Asura_AssertfFired( const Asura_Char* szFormat, ... )
{
	va_list xArgs;
	va_start( xArgs, szFormat );
	Asura_PrintfToBfr( g_szOutputBuffer, szFormat, xArgs, ASURAASSERTF_OUTPUT_BUFFER_SIZE, true );
	va_end( xArgs );

	bool bRetVal = Asura_AssertFired(g_szAsuraAssertfFile, g_iAsuraAssertfLine, 
		g_szAsuraAssertfCondition, g_szOutputBuffer, g_pucAsuraAssertfIgnore);

	g_szAsuraAssertfFile = 0;
	g_iAsuraAssertfLine = 0;
	g_szAsuraAssertfCondition = 0;
	g_pucAsuraAssertfIgnore = 0;

	return bRetVal;
}

const char* Asura_Platform_Assert_GetLogFileName()
{
	return ASSERTION_LOGFILE_TXT;
}

#ifndef ASURA_ASSERT_LOGONLY
static void CopyAssertToClipboard( const char* szText )
{
	if( OpenClipboard(NULL) )
	{
		HGLOBAL hMem = GlobalAlloc( GMEM_MOVEABLE, strlen(szText) + 1 );
		if( hMem )
		{
			char* szOut = reinterpret_cast<char*>( GlobalLock(hMem) );
			strcpy( szOut, szText );
			GlobalUnlock( hMem );

			EmptyClipboard();
			SetClipboardData( CF_TEXT, hMem );
		}

		CloseClipboard();
	}
}

#ifdef NDEBUG
static bool DisplayReleaseAbortDialog( void )
{
	const char* szText  = "Would you like to quit now?";
	const char* szTitle = "Assertion recovery";
	u_int       uType   = MB_YESNO | MB_ICONQUESTION;

#ifdef ASURA_MAIN
	Asura_Windows::PreShowDialogBox();
	int iSelectedButton = MessageBox( Asura_Windows::GetWindowHandle(), szText, szTitle, uType | MB_APPLMODAL | MB_SETFOREGROUND );
	Asura_Windows::PostShowDialogBox();
#else
	int iSelectedButton = MessageBox( NULL, szText, szTitle, uType );
#endif

	if( IDYES == iSelectedButton )
	{
#ifdef ASURA_MEMORYMANAGEMENT_ENABLED
		//Disable memory leak reporting so we don't get a huge file with all current
		//memory allocations being generated... RAR 03/08/04
		Asura_MemoryManagement_System::SetReportMemoryLeaksOnShutdown(false);
#endif
		// ignore all asserts from now on.
		AsuraAssert_SetIgnoreAll(true);
		g_bShuttingDown = true;
		exit( EXIT_FAILURE );
	}

	return false;
}
#endif // #ifdef NDEBUG
#endif // #ifndef ASURA_ASSERT_LOGONLY


#endif
