/*****************************************************************************/
/* DumpContext.cpp                        Copyright (c) Ladislav Zezula 2015 */
/*---------------------------------------------------------------------------*/
/* Implementation of dump context                                            */
/*---------------------------------------------------------------------------*/
/*   Date    Ver   Who  Comment                                              */
/* --------  ----  ---  -------                                              */
/* 16.03.15  1.00  Lad  Created                                              */
/*****************************************************************************/

#define __CASCLIB_SELF__
#include "../CascLib.h"
#include "../CascCommon.h"

//-----------------------------------------------------------------------------
// Local functions

static TCHAR * FormatFileName(TCascStorage * hs, const TCHAR * szNameFormat)
{
    TCHAR * szFileName;
    TCHAR * szSrc;
    TCHAR * szTrg;

    // Create copy of the file name
    szFileName = szSrc = szTrg = CascNewStr(szNameFormat, 0);
    if(szFileName != NULL)
    {
        // Format the file name
        while(szSrc[0] != 0)
        {
            if(szSrc[0] == _T('%'))
            {
                // Replace "%build%" with a build number
                if(!_tcsncmp(szSrc, _T("%build%"), 7))
                {
                    szTrg += _stprintf(szTrg, _T("%u"), hs->dwBuildNumber);
                    szSrc += 7;
                    continue;
                }
            }

            // Just copy the character
            *szTrg++ = *szSrc++;
        }

        // Terminate the target file name
        szTrg[0] = 0;
    }

    return szFileName;
}

//-----------------------------------------------------------------------------
// Public functions

TDumpContext * CreateDumpContext(TCascStorage * hs, const TCHAR * szNameFormat)
{
    TDumpContext * dc;
    TCHAR * szFileName;

    // Validate the storage handle
    if(hs != NULL)
    {
        // Calculate the number of bytes needed for dump context
        dc = CASC_ALLOC(TDumpContext, 1);
        if(dc != NULL)
        {
            // Initialize the dump context
            memset(dc, 0, sizeof(TDumpContext));

            // Format the real file name
            szFileName = FormatFileName(hs, szNameFormat);
            if(szFileName != NULL)
            {
                // Create the file
                dc->pStream = FileStream_CreateFile(szFileName, 0);
                if(dc->pStream != NULL)
                {
                    // Initialize buffers
                    dc->pbBufferBegin =
                    dc->pbBufferPtr = dc->DumpBuffer;
                    dc->pbBufferEnd = dc->DumpBuffer + CASC_DUMP_BUFFER_SIZE;

                    // Success
                    CASC_FREE(szFileName);
                    return dc;
                }

                // File create failed --> delete the file name
                CASC_FREE(szFileName);
            }

            // Free the dump context
            CASC_FREE(dc);
        }
    }

    return NULL;
}

int dump_print(TDumpContext * dc, const char * szFormat, ...)
{
    va_list argList;
    char szBuffer[0x200];
    int nLength = 0;

    // Only if the dump context is valid
    if(dc != NULL)
    {
        // Print the buffer using sprintf
        va_start(argList, szFormat);
        nLength = vsprintf(szBuffer, szFormat, argList);
        assert(nLength < 0x200);
        va_end(argList);

        // Copy the string. Replace "\n" with "\n\r"
        for(int i = 0; i < nLength; i++)
        {
            // Flush the buffer, if needed
            if((dc->pbBufferPtr + 2) >= dc->pbBufferEnd)
            {
                FileStream_Write(dc->pStream, NULL, dc->pbBufferBegin, (DWORD)(dc->pbBufferPtr - dc->pbBufferBegin));
                dc->pbBufferPtr = dc->pbBufferBegin;
            }

            // Copy the char
            if(szBuffer[i] == 0x0A)
                *dc->pbBufferPtr++ = 0x0D;
            *dc->pbBufferPtr++ = szBuffer[i];
        }
    }

    return nLength;
}

int dump_close(TDumpContext * dc)
{
    // Only if the dump context is valid
    if(dc != NULL)
    {
        // Flush the dump context if there are some data
        if(dc->pbBufferPtr > dc->pbBufferBegin)
            FileStream_Write(dc->pStream, NULL, dc->pbBufferBegin, (DWORD)(dc->pbBufferPtr - dc->pbBufferBegin));
        dc->pbBufferPtr = dc->pbBufferBegin;

        // Free the file stream and the entire context
        if(dc->pStream != NULL)
            FileStream_Close(dc->pStream);
        CASC_FREE(dc);
    }

    return 0;
}
