//---------------------------------------------------------------------------


#pragma hdrstop
//---------------------------------------------------------------------------

#include "ITSUtilF.h"
#include "CommLogF.h"
//---------------------------------------------------------------------------

#pragma package(smart_init)
TCommLog *CommLog = NULL;
LOG_INFO  g_LogCfg;

TCriticalSection *csLog = NULL;
//---------------------------------------------------------------------------

TCommLog::TCommLog(String ALogDir, String ALogName, String ALogDay)
{
    if (!csLog) csLog = new TCriticalSection();

    FLogDay  = ALogDay;
    FLogFile = ALogDir + ALogName;

    ForceDirectories(ALogDir.c_str());
}
//---------------------------------------------------------------------------

TCommLog::~TCommLog()
{
    if (csLog)
    {
        delete csLog;
        csLog = NULL;
    }
}
//---------------------------------------------------------------------------

void TCommLog::SendLogMessage(int AKind, char *AFmt, ...)
{
    va_list      ap;
    int          res;
    LRESULT      result;
    LOG_MESSAGE *pMsg = NULL;

    bool bLog = false;

    switch(AKind)
    {
    case eLOG_INFO:    bLog = g_LogCfg.Info;    break;
    case eLOG_DATA:    bLog = g_LogCfg.Data;    break;
    case eLOG_ERROR:   bLog = g_LogCfg.Error;   break;
    case eLOG_WARNING: bLog = g_LogCfg.Warning; break;
    case eLOG_DEBUG:   bLog = g_LogCfg.Debug;   break;
    case eLOG_DETAIL:  bLog = g_LogCfg.Detail;  break;
    }
    if (!bLog) return;

    try
    {
        csLog->Enter();

        try
        {
            pMsg = new LOG_MESSAGE;
            memset((char*)pMsg, 0x00, sizeof(LOG_MESSAGE));

            va_start(ap, AFmt);
            res = vsprintf(pMsg->Data, AFmt, ap);
            va_end(ap);

            //LogWrite(NULL, AKind, pMsg->Data);

            pMsg->Kind = AKind;
            pMsg->Len  = strlen(pMsg->Data);

#if 0
            if (TCommLog::FLog.Debug)
            {
                ITSUtil_Trace(pMsg->Data);
            }
#endif

            //result = ::PostMessage(MAINHANDLE, WM_LOG, (WPARAM)pMsg, 0);
        }
        catch(Exception &e)
        {
            SAFE_DELETE(pMsg);
        }
    }
    __finally
    {
        csLog->Leave();
    }
}
//---------------------------------------------------------------------------

FILE *TCommLog::OpenLogFile(AnsiString AFileExt/*=".log"*/)
{
    FILE	   *fp = NULL;
    AnsiString  sOpenMode = "a+";
    try
    {
        AnsiString sLogDay = Now().FormatString("dd");
        if (FLogDay != sLogDay)
        {
            sOpenMode = "w+";
            FLogDay = sLogDay;
        }

        AnsiString sLogFile = FLogFile + "_" + FLogDay + AFileExt;
        fp = fopen(sLogFile.c_str(), sOpenMode.c_str());
    }
    catch(Exception &e)
    {
    }
    return fp;
}
//---------------------------------------------------------------------------

int TCommLog::LogData(char *ASndRcv, const unsigned char *AData, int ALen, FILE *Afp/*=NULL*/)
{
    AnsiString     sTime;
    int            ii, jj, pos;
    FILE          *fp = Afp;
    bool           bFileClose = false;

    if (!g_LogCfg.Data || !AData)
    {
        return -1;
    }

    if (!fp)
    {
        fp = OpenLogFile();
        bFileClose = true;
    }
    if (!fp) return -1;

    try
    {
        sTime = AnsiString(Now().FormatString("yyyy-mm-dd hh:nn:ss"));

        fprintf(fp, "[%s] [DATA ] %d Bytes [%s]\n", sTime.c_str(), ALen, ASndRcv);

        AnsiString sLog;
        AnsiString sChar;
        AnsiString sMsg;

        for (ii = 0; ii < ALen; ii += 16)
        {
            sLog = "           ";
            sMsg.printf("%08Xh ", ii);
            sLog += sMsg;
            for (jj = 0; jj < 16; jj++)
            {
                pos = ii + jj;
                if (pos < ALen)
                    sMsg.printf(" %02X", AData[pos]);
                else
                    sMsg.printf("   ");

                sLog += sMsg;

                if (jj == 7)
                {
                    sMsg.printf("  "); sLog += sMsg;
                }
            }

            sMsg.printf("  ;"); sLog += sMsg;

            for (jj = 0; jj < 16; jj++)
            {
                pos = ii + jj;
                if (pos >= ALen)
                    break;

                uint8_t v = AData[pos];
                sMsg.printf("%c", isprint(v) ? v : '.');
                sLog += sMsg;
                if (jj == 7)
                {
                    sMsg.printf(" "); sLog += sMsg;
                }
            }
            fprintf(fp, "%s\n", sLog.c_str());
            fflush(fp);
        }
        fprintf(fp, "\n");
    }
    catch(Exception &e)
    {
    }

    if (bFileClose)
    {
        // 아규먼트로 파일디스크립터가 넘어온 경우 파일을 닫지 않는다.
        if (fp) fclose(fp);
    }

    return ALen;
}
//---------------------------------------------------------------------------

int TCommLog::LogWrite(FILE *Afp, int ALogKind, char *AFmt, ...)
{
    va_list        ap;
    int            cnt = 0;
    char           szFmtData[MAX_LOG_BUFFER+1];
    AnsiString     sLogKind = "";

    AnsiString     sTime;
    FILE          *fp = Afp;
    bool           bFileClose = false;

    bool bLog = false;
    switch(ALogKind)
    {
    case eLOG_INFO   : bLog = g_LogCfg.Info;    sLogKind = "[INFO  ]"; break;
    case eLOG_DATA   : bLog = g_LogCfg.Data;    sLogKind = "[DATA  ]"; break;
    case eLOG_ERROR  : bLog = g_LogCfg.Error;   sLogKind = "[ERROR ]"; break;
    case eLOG_WARNING: bLog = g_LogCfg.Warning; sLogKind = "[WARN  ]"; break;
    case eLOG_DEBUG  : bLog = g_LogCfg.Debug;   sLogKind = "[DEGUG ]"; break;
    case eLOG_DETAIL : bLog = g_LogCfg.Detail;  sLogKind = "[DETAIL]"; break;
    }
    if (!bLog) return -1;

    if (!fp)
    {
        fp = OpenLogFile();
        bFileClose = true;
    }
    if (!fp) return -1;

    try
    {
        va_start(ap, AFmt);
        cnt = vsprintf(szFmtData, AFmt, ap);
        va_end(ap);

        sTime = AnsiString(Now().FormatString("yyyy-mm-dd hh:nn:ss"));

        fprintf(fp, "[%s] %s %s\n", sTime.c_str(), sLogKind.c_str(), szFmtData);
    }
    catch(Exception &e)
    {
    }

    if (bFileClose)
    {
        // 아규먼트로 파일디스크립터가 넘어온 경우 파일을 닫지 않는다.
        if (fp) fclose(fp);
    }

    return cnt;
}
//---------------------------------------------------------------------------
int TCommLog::LogDbError(String ATitle, String AClass, String AError, String ASql,
                         String AFile, String AFunc, int ALine, bool AShowMsg/*=true*/)
{
    AnsiString  sTime;
    FILE       *fp;

    LogWrite(NULL, eLOG_ERROR, "[%s] DB Error Occured. FILE: %s LINE: %d FUNC: %s", AnsiString(ExtractFileName(AFile)).c_str(), ALine, AnsiString(AFunc).c_str());

    fp = OpenLogFile(".err");
    if (!fp) return -1;

    try
    {
        sTime = AnsiString(Now().FormatString("yyyy-mm-dd hh:nn:ss"));

        fprintf(fp, "[%s] DB Error Occured. FILE: %s LINE: %d FUNC: %s\n",
                    sTime.c_str(), AnsiString(ExtractFileName(AFile)).c_str(), ALine, AnsiString(AFunc).c_str());
        fprintf(fp, "Title: %s\n", AnsiString(ATitle).c_str());
        fprintf(fp, "Class: %s\n", AnsiString(AClass).c_str());
        fprintf(fp, "Error: %s\n", AnsiString(AError).c_str());
        fprintf(fp, "SQL  :\n%s\n",AnsiString(ASql).c_str());
        fprintf(fp, "\n");
    }
    catch(Exception &e)
    {
    }

    if (fp) fclose(fp);

    if (AShowMsg)
    {
        String sErrMsg = AClass + " : " + AError;
        Application->NormalizeTopMosts();
        Application->MessageBox(sErrMsg.c_str(), ATitle.c_str(), MB_OK|MB_ICONERROR|MB_APPLMODAL);
        Application->RestoreTopMosts();
    }
    return 0;
}
//---------------------------------------------------------------------------

