/**
*
* \file Asura_Logfile.h
*
* Created by Kevin Lea - 29/10/2001 16:23:34
*
* Copyright (C) 2001 Rebellion, All Rights Reserved.
*
* \brief Generic Logfile stuff. 
*
*	Using logfiles: there are just two 'functions' (obviously macros are used) to be aware of:
*
*		Asura_Logfile((const Asura_Char* logfilename, const Asura_Char* string, ...));
*
*		Asura_Logfile_Retail((const Asura_Char* logfilename, const Asura_Char* string, ...));
*
*
*		Both of these output the named file, appending data onto the end of an existing file or creating
*	a new file if necessary. The first time (per session) a file is written to it is automatically cleared.
*
*		Both of the output functions use ellipsis to provide the same functionality as printf, so you can 
*	write things like Asura_Logfile((LOGFILE,"Zarjaz %d,%f",integer,float));. 
*
*		You're probably wondering about the use of double brackets - this is so I can use #defined macros
*	with a variable number of parameters. When logfiles are disabled all the parameters are completely
*	preprocessed out, rather than relying on the compiler to figure something out later. (With other
*	systems which replace the logfile functions with empty ones on release builds, I've still seen unused
*	text strings buried in the executable, taking up precious memory.)
*
*		The Asura_Logfile messages are only compiled-in on debug builds, whereas the Asura_Logfile_Retail
*	messages are present in both debug and release builds. Use them wisely; obviously you don't want
*	lots of file access during retail builds, but it's good to have a logfile for things like serious errors.
*	
*		I'd usually suggest having a logfile name declared as a const Asura_Char* at the beginning of a
*	file, but since we're after the ability to compile things out, it's best to use a #define instead.
*	e.g. #define MYLOGFILENAME "logfiles\\log.txt"
*
*		Oh yeah, currently the test to see if a logfile has been written to before has a case sensitive
*	test of the filename...
*
*   MH addition 18.3.02 
*   Asura_SimpleLogfileClear and Asura_SimpleLogfileOutput which don't make any use of 
*   things with global constructors, for logging memory leaks etc. at shutdown.
*   Also, they don't write anything other than the logged message. 
*           
**/

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_LOGFILE_H__
#define __ASURA_LOGFILE_H__

#if defined(ASURA_LOGFILES_ENABLED) && defined(ASURA_NO_DEBUG_OUTPUT)
#error ASURA_LOGFILES_ENABLED and ASURA_NO_DEBUG_OUTPUT are mutually exclusive.
#endif

#if defined(ASURA_LOGFILES_ENABLED)

    void __Asura_LogfileDebugData( const char* szFile, u_int uLine );
    void __Asura_LogfileOutput( const char* szLogFilename, const char* szFormat, ... );

    void __Asura_SimpleLogfileClear( const char* szLogFilename );
    void __Asura_SimpleLogfileOutput( const char* szLogFilename, const char* szFormat, ... );
    void __Asura_SimpleLogfileOutput_PreFormatted( const char* szLogFilename, const char* szStr, u_int uLen );

	#if defined( ASURA_TOOLS)
	    void __Asura_SimpleLogfileClearXML( const char* szLogFilename );
	    void __Asura_SimpleLogfileOpenXML( const char* szLogFilename );
	    void __Asura_SimpleLogfileCloseXML( const char* szLogFilename );
		void __Asura_SimpleLogfileOutputXML( const char* szLogFilename, const char* szFormat, ... );
		void __Asura_SimpleLogfileConvertToXML(const Asura_Char* pszInput, Asura_Char* pszOutput, const u_int uOutputSize);
	#endif
    
    bool __Asura_Logfile_CanLogYet( void );
	bool __Asura_OverrideLogfilesDir( const char* szDir, bool bArchiveExisting );

    #ifdef NDEBUG // RELEASE BUILD

        #define Asura_Logfile_Retail(params) { __Asura_LogfileOutput params; }
        #define Asura_Logfile(ignore)

        #define Asura_SimpleLogfileClear( szLogFilename ) { __Asura_SimpleLogfileClear( szLogFilename ); }
        #define Asura_SimpleLogfileOutput(params) { __Asura_SimpleLogfileOutput params; }
        #define Asura_SimpleLogfileOutput_PreFormatted( szLogFilename, szPreFmtdStr, uLen ) { __Asura_SimpleLogfileOutput_PreFormatted( szLogFilename, szPreFmtdStr, uLen ); }

		#if defined( ASURA_TOOLS)
	        #define Asura_SimpleLogfileClearXML( szLogFilename ) { __Asura_SimpleLogfileClearXML( szLogFilename ); }
	        #define Asura_SimpleLogfileOpenXML( szLogFilename ) { __Asura_SimpleLogfileOpenXML( szLogFilename ); }
	        #define Asura_SimpleLogfileCloseXML( szLogFilename ) { __Asura_SimpleLogfileCloseXML( szLogFilename ); }
			#define Asura_SimpleLogfileOutputXML(params) { __Asura_SimpleLogfileOutputXML params; }
			#define Asura_SimpleLogfileConvertToXML( A, B, C) {__Asura_SimpleLogfileConvertToXML(A, B, C);}
		#endif
        
    #else // DEBUG BUILD

        #define Asura_Logfile_Retail(params) { __Asura_LogfileDebugData(__FILE__,__LINE__); __Asura_LogfileOutput params; }
        #define Asura_Logfile(params) { __Asura_LogfileDebugData(__FILE__,__LINE__); __Asura_LogfileOutput params; }

        #define Asura_SimpleLogfileClear( szLogFilename ) { __Asura_SimpleLogfileClear( szLogFilename ); }
        #define Asura_SimpleLogfileOutput(params) { __Asura_SimpleLogfileOutput params; }
        #define Asura_SimpleLogfileOutput_PreFormatted( szLogFilename, szPreFmtdStr, uLen ) { __Asura_SimpleLogfileOutput_PreFormatted( szLogFilename, szPreFmtdStr, uLen ); }

		#if defined( ASURA_TOOLS)
			#define Asura_SimpleLogfileClearXML( szLogFilename ) { __Asura_SimpleLogfileClearXML( szLogFilename ); }
	        #define Asura_SimpleLogfileOpenXML( szLogFilename ) { __Asura_SimpleLogfileOpenXML( szLogFilename ); }
	        #define Asura_SimpleLogfileCloseXML( szLogFilename ) { __Asura_SimpleLogfileCloseXML( szLogFilename ); }
			#define Asura_SimpleLogfileOutputXML(params) { __Asura_SimpleLogfileOutputXML params; }
			#define Asura_SimpleLogfileConvertToXML( A, B, C) {__Asura_SimpleLogfileConvertToXML(A, B, C);}
		#endif
        
    #endif // DEBUG/RELEASE BUILD

    #define Asura_Logfile_CanLogYet() (__Asura_Logfile_CanLogYet())

	// Asura_OverrideLogfilesDir() is optionally implemented on some platforms to replace "logfiles/" with 
	// another directory and also optionally back up the existing logs (so it's best called at startup).
	// This is especially useful for dedicated servers which typically run multiple instances from the same
	// folder: you can start them up with a commandline indicating a path for their logfiles
	// The platform function should return whether the action was implemented.
	#define Asura_OverrideLogfilesDir(szDir, bArchiveExisting) __Asura_OverrideLogfilesDir(szDir, bArchiveExisting)

#else // not defined(ASURA_LOGFILES_ENABLED)

    #define Asura_Logfile_Retail(ignore)
    #define Asura_Logfile(ignore)

    #define Asura_SimpleLogfileClear(ignore)
    #define Asura_SimpleLogfileOutput(ignore)
    #define Asura_SimpleLogfileOutput_PreFormatted( ignore, ignore2, ingore3 )

    #define Asura_Logfile_CanLogYet() (false)
	#define Asura_OverrideLogfilesDir(szDir, bArchiveExisting) (true)

#endif // else not defined(ASURA_LOGFILES_ENABLED)

#if defined(ASURA_NO_DEBUG_OUTPUT)

    #define Asura_OutputToDebugger_Retail( params )
    #define Asura_OutputToDebugger( params )
    #define Asura_OutputToDebuggerAssert( cond, params )
    #define Asura_OutputToDebuggerOnce( params )
    #define Asura_OutputToDebuggerAssertOnce( cond, params )

#else // not defined(ASURA_NO_DEBUG_OUTPUT)

    void __Asura_OutputToDebugger( const char* szFormat, ... );

    #if defined(NDEBUG)

        #define Asura_OutputToDebugger_Retail( params ) { __Asura_OutputToDebugger params; }
        #define Asura_OutputToDebugger( params )
        #define Asura_OutputToDebuggerAssert( cond, params )
        #define Asura_OutputToDebuggerOnce( params )
        #define Asura_OutputToDebuggerAssertOnce( cond, params )

    #else

        #define Asura_OutputToDebugger_Retail( params ) { __Asura_OutputToDebugger params; }
        #define Asura_OutputToDebugger( params ) { __Asura_OutputToDebugger params; }
        // syntax: Asura_OutputToDebuggerAssert( m_fHealth != 0.0f, ( "Guid %u has zero health.\n", m_uGuid ) );
        #define Asura_OutputToDebuggerAssert( cond, params ) \
        { \
            if ( !( cond ) ) \
            { \
                __Asura_OutputToDebugger params; \
            } \
        }
        // fires once only
        #define Asura_OutputToDebuggerOnce( params ) \
        { \
            static bool bIgnore = false; \
            if ( !bIgnore ) \
            { \
                bIgnore = true; \
                __Asura_OutputToDebugger params; \
            } \
        }
        // syntax: Asura_OutputToDebuggerAssertOnce( m_fHealth != 0.0f, ( "Guid %u has zero health.\n", m_uGuid ) );
        #define Asura_OutputToDebuggerAssertOnce( cond, params ) \
        { \
            static bool bIgnore = false; \
            if ( !bIgnore ) \
            { \
                if ( !( cond ) ) \
                { \
                    bIgnore = true; \
                    __Asura_OutputToDebugger params; \
                } \
            } \
        }

    #endif

#endif // else not defined(ASURA_NO_DEBUG_OUTPUT)

#endif//__ASURA_LOGFILE_H__
