//////////////////////////////////////////////////////////////////////////////
//
// Asura_PlatformLogfile.cpp
//
// Copyright (c) 2006 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

// Stdlib independent.
#include <stdio.h>

// Engine independent.
#include "Core/Asura_Hash.h"
#include "Core/Asura_String.h"
#include "Core/Asura_StringBuffer.h"
#include "Debugging/Asura_Assert.h"
#include "Debugging/Asura_Logfile.h"

// Engine platform-specific.
#include "FileAccess/Asura_PS3_FileSystem.h"

// C O N S T A N T S /////////////////////////////////////////////////////////

static const u_int uOUTPUT_BUFFER_SIZE  = 1024;
static const u_int uMAX_OPENED_LOGFILES = 16;

// G L O B A L S /////////////////////////////////////////////////////////////

static Asura_Hash_ID g_auOpenedLogfileHashes[uMAX_OPENED_LOGFILES];
static u_int         g_uNumOpenedLogfiles;

// P R O T O T Y P E S   A N D   I N L I N E   F U N C T I O N S /////////////

static bool WriteToFile( const char* szFilename, const char* szData, u_int uNumChars );

// F U N C T I O N   I M P L E M E N T A T I O N S ///////////////////////////

static bool Asura_LogfileClear( const char* szFilename )
{
    Asura_PS3_FileSystem::Handle xHandle;
    if( Asura_PS3_FileSystem::OpenForWriting(szFilename, &xHandle, true) )
    {
        // That will have truncated on our behalf so just close it again.
        Asura_PS3_FileSystem::Close( &xHandle );
        return true;
    }
    else
    {
		// Try creating the directory
		const Asura_String256 xFilename( szFilename );
		Asura_String256 xDir;
		xFilename.SplitFilename( &xDir, NULL, NULL );
		const bool bError = Asura_PS3_FileSystem::CreateDir( xDir.GetString() );
		if ( bError == true )
		{
			if( Asura_PS3_FileSystem::OpenForWriting(szFilename, &xHandle, true) )
			{
				// That will have truncated on our behalf so just close it again.
				Asura_PS3_FileSystem::Close( &xHandle );
				return true;
			}
		}
		return false;
    }
}

void __Asura_LogfileDebugData (const char* file, unsigned int line)
{
//  File = file;
//  Line = line;
}

void __Asura_LogfileOutput( const char* szFilename, const char* szFormat, ... )
{
    // Automatically clear this logfile if it hasn't previously been opened.
    {
        const Asura_Hash_ID uHashID = Asura_GetHashID( szFilename );

        bool bFound = false;
        for( u_int u = 0; u < g_uNumOpenedLogfiles; ++u )
        {
            if( uHashID == g_auOpenedLogfileHashes[u] )
            {
                bFound = true;
                break;
            }
        }

        if( !bFound )
        {
            Asura_LogfileClear( szFilename );

            Asura_Assert( g_uNumOpenedLogfiles < uMAX_OPENED_LOGFILES, "You need to increase uMAX_OPENED_LOGFILES." );
            if (g_uNumOpenedLogfiles < uMAX_OPENED_LOGFILES)
			{
				g_auOpenedLogfileHashes[g_uNumOpenedLogfiles++] = uHashID;
			}
        }
    }

    char szBfr[uOUTPUT_BUFFER_SIZE];

    va_list xArgs;
    va_start( xArgs, szFormat );
    u_int uLen = Asura_PrintfToBfr( szBfr, szFormat, xArgs, uOUTPUT_BUFFER_SIZE, false );
    va_end( xArgs );

    WriteToFile( szFilename, szBfr, uLen );
}

// This version of the log clear function should not make use of any globals
// with constructors or any functions that use some. In particular, this
// function can't assert or use the OpenedLogfiles tree to check if the file's
// been used before or not.
void __Asura_SimpleLogfileClear( const char* szFilename )
{
    Asura_LogfileClear( szFilename );
}

// This version of the logging function should not make use of any globals
// with constructors or any functions that use some. In particular, this
// function can't assert or use the OpenedLogfiles tree to check if the file's
// been used before or not.
void __Asura_SimpleLogfileOutput( const char* szFilename, const char* szFormat, ... )
{
    char szBfr[uOUTPUT_BUFFER_SIZE];

    va_list xArgs;
    va_start( xArgs, szFormat );
    u_int uLen = Asura_PrintfToBfr( szBfr, szFormat, xArgs, uOUTPUT_BUFFER_SIZE, false );
    va_end( xArgs );

    WriteToFile( szFilename, szBfr, uLen );
}

void __Asura_OutputToDebugger( const char* szFormat, ... )
{
    char szBfr[uOUTPUT_BUFFER_SIZE];

    va_list xArgs;
    va_start( xArgs, szFormat );
    Asura_PrintfToBfr( szBfr, szFormat, xArgs, uOUTPUT_BUFFER_SIZE, true );
    va_end( xArgs );

    // Use fputs() because puts() inserts a newline.
    fputs( szBfr, stdout );
}


bool __Asura_Logfile_CanLogYet( void )
{
    return true;    
}

void __Asura_SimpleLogfileOutput_PreFormatted( const char* szFilename, const char* szStr, u_int uLen )
{
    WriteToFile( szFilename, szStr, uLen );
}


bool __Asura_OverrideLogfilesDir( const char* szDir, bool bArchiveExisting )
{
	return false;
}


static bool WriteToFile( const char* szFilename, const char* szData, u_int uNumChars )
{
    Asura_PS3_FileSystem::Handle xHandle;
    if( Asura_PS3_FileSystem::OpenForAppending(szFilename, &xHandle, true) )
    {
        Asura_PS3_FileSystem::WriteData( xHandle, uNumChars, szData );
        Asura_PS3_FileSystem::Close( &xHandle );
        return true;
    }
    else
    {
        return false;
    }
}
