#include "stdafx.h"
#include "CvsTrace.h"
#include "AppConsole.h"
#include <time.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//
//
//

static const char* g_sFilter = "*<>Aa";
static BOOL g_bLogUnbuffered = FALSE;

void LogSetFilter(const char* s)
{
    g_sFilter = strdup(s);
}

static inline int InFilter(char c) {
    return 0 != strchr(g_sFilter,c);
}

//
//  Important!
//
//  If using for a Win16 DLL, the log file cannot be owned by the DLL.
//

static HANDLE g_hLogFile = INVALID_HANDLE_VALUE;

#define IS_LOGGING() \
    (true)

//
//
//

static inline char* AddPrefix(char* p)
{
    // add line break
    *p++ = '\n';
    return p;
}

//
//  Log file support
//

static void LogWrite(const char* s)
{
    // skip if not logging
    if (IS_LOGGING()) {
		cvs_outstr(s,strlen(s));
    }
}

//
//
//

void LogInitialize(LPCSTR sFileName)
{
    if ('!' == *sFileName) {
        g_bLogUnbuffered = TRUE;
        ++sFileName;
    }
    time_t t = time(0);
    LogWrite(ctime(&t));
}

void LogCleanup(void)
{
}

//
//
//

static unsigned g_nLevel = 0;

static inline char* AddIndent(char* p)
{
    for (int n = 31 & g_nLevel; 0<n; --n) {
        *p++ = ' ';
        *p++ = ' ';
    }
    return p;
}

void LogString(const char* s,const char* sValue)
{
    // skip if not logging
    if (!IS_LOGGING()) {
        return;
    }
    if (256 < strlen(sValue)) {
        LogBuffer(s,sValue,strlen(sValue));
        return;
    }
    // omit if not in filter
    if (!InFilter(*s++)) {
        return;
    }
    char sBuffer[1000];
    char* p = AddPrefix(sBuffer);
        // insert leading spaces as required
    if (' ' == *s) { ++s; p = AddIndent(p); }
    // format the arguments
    wsprintf(p,"%s : \"%s\"",s,sValue);
    ASSERT(strlen((const char*)sBuffer)<sizeof(sBuffer));
    // drop into log file
    LogWrite(sBuffer);
}

void __cdecl Log_printf(const char* s,...)
{
    // skip if not logging
    if (!IS_LOGGING()) {
        return;
    }
    // omit if not in filter
    if (!InFilter(*s++)) {
        return;
    }
    char sBuffer[1000];
    char* p = AddPrefix(sBuffer);
        // insert leading spaces as required
    if (' ' == *s) { ++s; p = AddIndent(p); }
    // format the arguments
    va_list a;
    va_start(a,s);
    wvsprintf(p,s,a);
    va_end(a);
    ASSERT(strlen((const char*)sBuffer)<sizeof(sBuffer));
    // drop into log file
    LogWrite(sBuffer);
}

static const char sHex[] = "0123456789ABCDEF";

void LogBuffer(const char* sName,const char* sBuffer,unsigned cbBuffer)
{
    // skip if not logging
    if (!IS_LOGGING()) {
        return;
    }
    // omit if not in filter
    if (!InFilter(*sName++)) {
        return;
    }
    // mark start of buffer
    Log_printf("*[BUFFER %s (%u bytes)]",sName,cbBuffer);
    // dump contents of buffer
    for (unsigned i=0; i<cbBuffer;) {
        char sLine[256];
        char* s1 = sLine;
        wsprintf(s1,"\n%05x:",i);
        s1 += strlen(s1);
        memset(s1,' ',50);
        char* s2 = s1 + 50;
        while (i<cbBuffer) {
            unsigned b = *(unsigned char*)(sBuffer+i);
            ++s1;
            *s1++ = sHex[15&(b>>4)];
            *s1++ = sHex[15&b];
            *s2++ = (char)(((31<b) && (b<127)) ? b : '.');
            ++i;
            if (!(15&i)) break;
        }
        *s2 = 0;
        LogWrite(sLine);
    }
    // mark end of buffer
    Log_printf("*[END BUFFER %s]",sName);
}

//
//
//

static const char* g_sCurrent = "(BASE)";

CvsTrace::CvsTrace(const char* s)
:   m_sOuter(0)
{
    // skip if not logging
    if (!IS_LOGGING()) {
        return;
    }
    Log_printf("> > %s",s);
    {
        m_sOuter = g_sCurrent;
        g_sCurrent = s;
        ++g_nLevel;
    }
}

CvsTrace::~CvsTrace()
{
    // skip if not logging
    if (!IS_LOGGING()) {
        return;
    }
    const char* s;
    {
        --g_nLevel;
        s = g_sCurrent;
        g_sCurrent = m_sOuter;
    }
    Log_printf("< < %s",s);
}
