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

#define WIN32_LEAN_AND_MEAN
#include <DateUtils.hpp>
#include "ITSNetF.h"
#include <vcl.h>
#pragma hdrstop
#include <psapi.h>
#include <windows.h>
#include <stdio.h>
#include <time.h>
//---------------------------------------------------------------------------

#include "AppGlobalF.h"
#include "VmsUtilsF.h"
#include "FrmMainF.h"
#include "MainCommF.h"
#include "FrmOptionF.h"
#include "FrmSysLogF.h"
#include "FrmCommLogF.h"
#include "FrmControllerInfoF.h"
#include "FrmNetworkF.h"
#include "LogThreadF.h"
#include "DbmThreadF.h"
#include "JobThreadF.h"
#include "DMAdoDbF.h"
#include "PacketHandllingF.h"
#include "ClientSessionManagerF.h"

//---------------------------------------------------------------------------
#include "CDSProcessF.h"
#include "CDSCtlrF.h"
#include "CDSImageF.h"
#include "CDSFormF.h"
#include "CDSIfscF.h"
#include "CDSFontF.h"
#include "CDSColorF.h"
#include "CDSAtmpF.h"
#include "CDSParkF.h"
#include "CDSManagerF.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "IdAntiFreeze"
#pragma link "IdAntiFreezeBase"
#pragma link "IdBaseComponent"
#pragma link "IdComponent"
#pragma link "IdUDPBase"
#pragma link "IdUDPServer"
#pragma resource "*.dfm"

TItsMap<int, TItsThread*> G_Threads;
typedef std::map<int, TItsThread*>::iterator thrIterator;

TFrmMain *FrmMain;
//---------------------------------------------------------------------------

__fastcall TFrmMain::TFrmMain(TComponent* Owner)
    : TForm(Owner)
{
    Application->OnException = OnAppException;

    ::CoInitialize(NULL);

    FServerRun = false;
    FTickState = 0;
    g_AppCfg.bAppLoad  = false;
    g_AppCfg.bAppClose = false;

    Caption = "  " + g_AppCfg.sTitle + " - " + Now().FormatString("yyyy-MM-dd hh:nn:ss");

    ClientSessionManager = new TClientSessionManager();

    CDSProcessManager = new TCDSProcessManager();
    CDSCtlrManager    = new TCDSCtlrManager();
    CDSFormManager    = new TCDSFormManager();
    CDSImageManager   = new TCDSImageManager();
    CDSIfscManager    = new TCDSIfscManager();
    CDSFontManager    = new TCDSFontManager();
#if 0
    CDSAtmpManager    = new TCDSAtmpManager();
    CDSParkManager    = new TCDSParkManager();
#endif
    CDSManager        = new TCDSManager();
#if 0
    CDSVmsIfscTrafManager = new TCDSVmsIfscTrafManager();
#endif

    FCurrMin = StrToInt(Now().FormatString("nn"));;
    FCur1MinComm = FCurrMin;
    FCur1MinRun  = FCurrMin;
    FCur5Min = FCurrMin;
    FCurrHour = -1;
    FCurrSec  = -1;

    FTimeSyncDay   = -1;
    FTimeSyncMin   = -1;
    FUnitSttsHsMin = -1;
    FCtlrSttsHsMin = -1;
    FProvideRemain = -1;

    FOneMinCycle = false;
    FFirstRunning = true;

    m_dtChkDbAive = Now();

    FrmCommLog = new TFrmCommLog(Application);
    FrmNetwork = new TFrmNetwork(Application);
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::OnAppException(TObject *Sender, Exception *exception)
{
    AnsiString sClassName = (NULL != Sender)        ? AnsiString(Sender->ClassName())    : AnsiString("Unknown_Class");
    AnsiString sErrCls    = (NULL != exception)     ? AnsiString(exception->ClassName()) : AnsiString("Unknown_Error");
    AnsiString sErrMsg    = (NULL != exception)     ? AnsiString(exception->Message)     : AnsiString("Unknown_Error");

	if (g_AppCfg.bAppClose)
    {
        LOGERROR("Program Close Exception Terminated. %s.%s.%s", sClassName.c_str(), sErrCls.c_str(), sErrMsg.c_str());
    }
    else
    {
        LOGERROR("Program Exception Terminated. %s.%s.%s", sClassName.c_str(), sErrCls.c_str(), sErrMsg.c_str());
    }
    Close();
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::FormCreate(TObject *Sender)
{
    Application->ShowMainForm = false;

    try {
        Application->Icon->LoadFromResourceName(((unsigned int)HInstance), "MAINICON");
    } catch(...) { ShowMessage("LoadFromResourceName failed"); }

    g_AppCfg.lMainWinHandle = (long)Handle;

    FrmSysLog = new TFrmSysLog(pnlLog);
    FrmSysLog->Parent = pnlLog;
    FrmSysLog->Show();

    FrmControllerInfo = new TFrmControllerInfo(pnlController);
    FrmControllerInfo->Parent = pnlController;
    FrmControllerInfo->Show();

    char szLogMsg[MAX_LOG_BUFFER];
    if (!g_logQ.Create("vmsLog", MAX_LOGQ_BUFF))
    {
        sprintf(szLogMsg, "Log Q Create failed. Program abnormal terminate.");
        AbnormalTerminate(szLogMsg);
        Close();
        Close();
    }

    if (!g_dbmQ.Create("vmsDbm", MAX_DBMQ_BUFF))
    {
        sprintf(szLogMsg, "Dbm Q Create failed. Program abnormal terminate.");
        AbnormalTerminate(szLogMsg);
        Close();
        Close();
    }

    if (!g_jobQ.Create("vmsJob", MAX_JOBQ_BUFF))
    {
        sprintf(szLogMsg, "Job Q Create failed. Program abnormal terminate.");
        AbnormalTerminate(szLogMsg);
        Close();
        Close();
    }

    Application->ShowMainForm = true;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::FormShow(TObject *Sender)
{
    FProvideRemain = SecondOfTheDay(Now());
    FProvideRemain %= g_AppCfg.nTrafficCycleTime;
    FProvideRemain = g_AppCfg.nTrafficCycleTime - FProvideRemain + g_AppCfg.nTrafficBasisTime;

    CheckResource((g_AppCfg.MaxMemory * 1024), g_AppCfg.MaxHandle, g_AppCfg.MaxThread, g_AppCfg.MaxGdi);
    Refresh();
    tmrAppState->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::FormCloseQuery(TObject *Sender, bool &CanClose)
{
    if (!g_AppCfg.bAppClose)
    {
        String strMsg;
        strMsg = Caption + "\r\n\r\nAre you sure you want to exit the program?\r\nIf the Process Manager is running the program will be restarted automatically!!!";

        //if (Application->MessageBox(strMsg.c_str(), L"Confirm program exit", MB_YESNO|MB_ICONQUESTION) == IDYES)
        {
            FServerRun = false;
            g_AppCfg.bAppClose = true;
        }
        CanClose = false;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::FormClose(TObject *Sender, TCloseAction &Action)
{
    CommClose();

    ::CoUninitialize();

    Action = caFree;
    FrmMain = NULL;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::CommClose()
{
    try
    {
        g_AppCfg.bAppClose = true;

        APP_WriteConfigInfo("LOG", "LOGDAY", Now().FormatString("dd"), g_AppCfg.sConfigFile);

        if (IdUDPCenterServer->Active == true)
        {
            IdUDPCenterServer->Active = false;
            for (int ii = 0; ii < IdUDPCenterServer->Bindings->Count; ii++)
            {
                IdUDPCenterServer->Bindings->Items[ii]->Free();
            }
        }
#if 0
        if (FrmCommLog) FrmCommLog->Close();
        if (FrmNetwork)
        {
            FrmNetwork->Stop();
            FrmNetwork->Close();
        }
#endif
    }
    catch(Exception &e)
    {
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::AbnormalTerminate(char* AMsg)
{
    for (int ii = 0; ii < 5; ii++)
    {
        ITSLog->LogWrite(NULL, eLOG_ERROR, AMsg);
        FrmSysLog->reMsg->Lines->Add(Now().FormatString("hh:nn:ss") + String(AMsg));
        Refresh();
        Sleep(1000);
    }
}
//---------------------------------------------------------------------------

bool __fastcall TFrmMain::InitApplication()
{
    int nResult;
    String sTitle, sMsg;
    char szLogMsg[MAX_LOG_BUFFER];

    Application->ProcessMessages();

    if (JobThreadStart() == false)
    {
        memset(szLogMsg, 0x00, sizeof(szLogMsg));
        sprintf(szLogMsg, "Job Thread Create failed. Program abnormal terminate.");
        AbnormalTerminate(szLogMsg);
        return false;
    }

    MINFO("MAIN Program initialize start...");  // Q 생성후 메시지 출력함

    TDMAdoDb *FDb = new TDMAdoDb(NULL);
    try
    {
        MINFO("MAIN Database connect...");
        if (!FDb->Connect(g_AppCfg.db.sConnectStr))
        {
            memset(szLogMsg, 0x00, sizeof(szLogMsg));
            sprintf(szLogMsg, "MAIN Database connect failed. Program abnormal terminate.");
            AbnormalTerminate(szLogMsg);
            return false;
        }

        if (CDSProcessManager)
        {
            MINFO("MAIN Process Information initialize...");
            if (CDSProcessManager->LoadUnitInfo(FDb->GetConnection()) < 0)
            {
                memset(szLogMsg, 0x00, sizeof(szLogMsg));
                sprintf(szLogMsg, "MAIN Process Information initialize failed. Program abnormal terminate.");
                AbnormalTerminate(szLogMsg);
                return false;
            }
        }

        if (CDSCtlrManager)
        {
            MINFO("MAIN Controller Information initialize...");
            if (CDSCtlrManager->LoadCtlrInfo(FDb->GetConnection()) < 0)
            {
                memset(szLogMsg, 0x00, sizeof(szLogMsg));
                sprintf(szLogMsg, "MAIN Controller Information initialize failed. Program abnormal terminate.");
                AbnormalTerminate(szLogMsg);
                return false;
            }
        }

        if (CDSFontManager)
        {
            MINFO("MAIN VMS Font Information initialize...");
            if (CDSFontManager->LoadFontInfo(FDb->GetConnection()) < 0)
            {
                memset(szLogMsg, 0x00, sizeof(szLogMsg));
                sprintf(szLogMsg, "MAIN VMS Font Information initialize failed. Program abnormal terminate.");
                AbnormalTerminate(szLogMsg);
                return false;
            }
        }

        if (CDSIfscManager)
        {
            MINFO("MAIN VMS Scetion Information initialize...");
            if (CDSIfscManager->LoadVmsIfscInfo(FDb->GetConnection()) < 0)
            {
                memset(szLogMsg, 0x00, sizeof(szLogMsg));
                sprintf(szLogMsg, "MAIN VMS Scetion Information initialize failed. Program abnormal terminate.");
                AbnormalTerminate(szLogMsg);
                return false;
            }
        }

        if (CDSImageManager)
        {
            MINFO("MAIN VMS Form Information initialize...");
            if (CDSImageManager->LoadVmsSymbolInfo(FDb->GetConnection()) < 0)
            {
                memset(szLogMsg, 0x00, sizeof(szLogMsg));
                sprintf(szLogMsg, "MAIN VMS Form Information initialize failed. Program abnormal terminate.");
                AbnormalTerminate(szLogMsg);
                return false;
            }
        }

        if (CDSAtmpManager)
        {
            MINFO("MAIN VMS ATMP Information initialize...");
            if (CDSAtmpManager->LoadAtmpInfo(FDb->GetConnection()) < 0)
            {
                memset(szLogMsg, 0x00, sizeof(szLogMsg));
                sprintf(szLogMsg, "MAIN VMS ATMP Information initialize failed. Program abnormal terminate.");
                AbnormalTerminate(szLogMsg);
                return false;
            }
        }

        if (CDSFormManager)
        {
            MINFO("MAIN VMS Form Information initialize...");
            if (CDSFormManager->LoadVmsFormInfo(FDb->GetConnection()) < 0)
            {
                memset(szLogMsg, 0x00, sizeof(szLogMsg));
                sprintf(szLogMsg, "MAIN VMS Form Information initialize failed. Program abnormal terminate.");
                AbnormalTerminate(szLogMsg);
                return false;
            }
        }

        if (CDSVmsIfscTrafManager)
        {
            MINFO("MAIN VMS IFSC TRAF Information initialize...");
            if (CDSVmsIfscTrafManager->InitVmsIfscTraffic(FDb->GetConnection()) < 0)
            {
                memset(szLogMsg, 0x00, sizeof(szLogMsg));
                sprintf(szLogMsg, "MAIN VMS IFSC TRAF Information initialize failed. Program abnormal terminate.");
                AbnormalTerminate(szLogMsg);
                return false;
            }
        }

    }
    __finally
    {
        if (FDb)
        {
            FDb->Close();
        }
        SAFE_DELETE(FDb);
    }

    ClientSessionManager->Init(CDSCtlrManager->FLists.Size()*2);
    FrmControllerInfo->UpdateCtlrList();

    MINFO("MAIN Center communication initialize...");
    TCDSProcess *pPrcs = CDSProcessManager->FLists.Find(g_AppCfg.sSystemId);
    if (!pPrcs)
    {
        sMsg.printf(L"MAIN Center process information not found: %s, error %d", g_AppCfg.sSystemId.c_str(), nResult);
        MERROR(AnsiString(sMsg).c_str());
        return false;
    }
    g_AppCfg.comm.nCenterPort = pPrcs->PRGM_PORT.ToIntDef(g_AppCfg.comm.nCenterPort);

    //통신초기화를 최초 수행한 후 디비읽어서 처리
    nResult = CComm_Initialize((long)FrmMain->Handle, g_AppCfg.sSystemId, "VMS", g_AppCfg.comm.nCenterPort, g_AppCfg.sLogDay);
    if (VERR_NONE != nResult)
    {
        sMsg.printf(L"MAIN Center communication initialize failed: error %d", nResult);
        MERROR(AnsiString(sMsg).c_str());
        return false;
    }
    FOR_STL(TCDSProcess*, pObj, CDSProcessManager->FLists)
    {
        if (pObj->DEL_YN == "Y") continue;

        if (g_AppCfg.sSystemId == pObj->SYST_ID)
        {
            //자기자신은 목록에 추가하지 않는다...
            continue;
        }
        if (CComm_AddProcess(pObj->SYST_ID, pObj->SYST_TYPE, pObj->SYST_IP_1, pObj->PRGM_PORT) >= 0)
        {
            if ("UOT" == pObj->SYST_TYPE)
            {
                int nPort = pObj->PRGM_PORT.ToIntDef(0);
                CComm_AddProcess(pObj->SYST_ID, pObj->SYST_TYPE, pObj->SYST_IP_1, AnsiString(nPort+1));   /* VMS  운영단말 */
#if 0
                CComm_AddProcess(pObj->SYST_ID, pObj->SYST_TYPE, pObj->SYST_IP_1, AnsiString(nPort+2));   /* CCTV 운영단말 */
                CComm_AddProcess(pObj->SYST_ID, pObj->SYST_TYPE, pObj->SYST_IP_1, AnsiString(nPort+3));   /* VDS  운영단말 */
#endif
            }
        }
    }

    if (VERR_NONE != CComm_Open())
    {
        sMsg.printf(L"MAIN Center communication open failed: error %d", nResult);
        MERROR(AnsiString(sMsg).c_str());
        return false;
    }

    g_SysInfo->RunSts = state_normal;
    g_SysInfo->ComSts = state_error;
    g_SysInfo->DbmSts = state_normal;

    FTickState = 0;
    FServerRun = true;

    m_dtChkDbAive = Now();          // 데이터베이스 연결 체크 타이머
    m_dtChkVmsJob = Now();          // VMS 작업 및 주기작업
    m_dtProvider  = Now()-1;        // 정보제공 타이머

    COMM_MakeBasisTime(m_tTimer, g_AppCfg.nTrafficCycleTime, g_AppCfg.nTrafficBasisTime);

    //APP_PostDbThreadMessage(dbm_save_unit_stts);
    APP_PostDbThreadMessage(dbm_dnld_form_init);

    //통신서버 시작
    Sleep(500);
    tbConnectClick(this);

    MINFO("MAIN Program initialize success...[Completed]");
    return true;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::tmrAppStateTimer(TObject *Sender)
{
    tmrAppState->Enabled = false;
    plTime->Caption = Now().FormatString("yyyy-MM-dd hh:nn:ss");

    if (!g_AppCfg.bAppLoad)
    {
        if (!InitApplication())
        {
            g_AppCfg.bAppClose = true;
            Close();
            return;
        }
        // 초기화작업완료

        CheckResource((g_AppCfg.MaxMemory * 1024), g_AppCfg.MaxHandle, g_AppCfg.MaxThread, g_AppCfg.MaxGdi);

        g_AppCfg.bAppLoad     = true;   // 프로그램이 로딩되었음을 확인
        tmrAppState->Interval = 980;   // 프로그램 상태점검주기=1초
        tmrAppState->Enabled  = true;
        return;
    }

    if (g_AppCfg.bAppClose)
    {
        // 응용프로그램 종료
        TerminateApplication();
        JobThreadStop();
        Close();
        return;
    }

    g_AppCfg.lMainWinHandle = (long)Handle;

    if (!(++FTickState % 5))
    {
        CheckCommState();   //통신상태정보 체크
    }

    UpdateProcessStatePanel();

    FCurrDay  = StrToInt(Now().FormatString("dd"));
    FCurrHour = StrToInt(Now().FormatString("hh"));
    FCurrMin  = StrToInt(Now().FormatString("nn"));
    FCurrSec  = StrToInt(Now().FormatString("ss"));

    // 0시 3분에 시각 동기화 명령을 전송하자
    if (FCurrDay != FTimeSyncDay
     && FCurrMin != FTimeSyncMin
     && FCurrMin  == 3
     && FCurrHour == 0)
    {
        FTimeSyncDay = FCurrDay;
        FTimeSyncMin = FCurrMin;
        SendTimeSync();
    }

    // 프로세스 상태정보 이력 DB 입력
    if (FCurrSec > 1)
    {
        //매 1분마다 상태정보 업데이트 하고 상태정보 업데이트 하는 곳에서 5분주기로 이력정보를 저장한다.
        if (FUnitSttsHsMin != FCurrMin)
        {
            FUnitSttsHsMin = FCurrMin;
            APP_PostDbThreadMessage(dbm_save_unit_stts);
        }
    }

    // 제어기 상태정보 이력  DB 입력
    if (FCurrSec > 3)
    {
        //매 1분마다 상태정보 업데이트 하고 상태정보 업데이트 하는 곳에서 5분주기로 이력정보를 저장한다.
        if (FCtlrSttsHsMin != FCurrMin)
        {
            FCtlrSttsHsMin = FCurrMin;
            APP_PostDbThreadMessage(dbm_save_ctlr_stts_all);
        }
    }

    if (FCurrSec > 5)
    {
        if (g_SysInfo->RunSts == state_normal && COMM_TimeDiff(m_dtChkDbAive) > 120)
        {
            //서버가 연결상태이고 DB 작업이 1분이상 경과된 경우 디비 연결상태를 체크한다.
            MINFO("MAIN *** Check Database Alive");
            APP_PostDbThreadMessage(dbm_check_db_alive);
            m_dtChkDbAive = Now();
        }
    }

#if 0
    if (FCurrSec > 8)
    {
        if (g_SysInfo->RunSts == state_normal && COMM_TimeDiff(m_dtChkVmsJob) > 60)
        {
            //VMS 주기적인 작업을 데이터베이스에서 조회
            MINFO("MAIN *** Check VMS Job Schedule");
            APP_PostDbThreadMessage(dbm_load_onoff_time);
            APP_PostDbThreadMessage(dbm_load_download_job);
            m_dtChkVmsJob = Now();
        }
    }
#endif

    plRemain->Caption = String(FProvideRemain--);

    if (FFirstRunning)
    {
        if ( (FCurrHour*3600 + FCurrMin*60) % g_AppCfg.nTrafficCycleTime == 0 &&
             FCurrSec >= g_AppCfg.nTrafficBasisTime )
        //if (CheckBasisTime(m_tTimer, g_AppCfg.nTrafficCycleTime, g_AppCfg.nTrafficBasisTime))
        {
            if (COMM_TimeDiff(m_dtProvider) > g_AppCfg.nTrafficCycleTime)
            {
                SendVmsTrafficProvide(1);
            }
        }
    }

    CheckProvideTimeout();

    if (!(FTickState % 60))
    {
#if 0
        if (CheckResource((g_AppCfg.MaxMemory * 1024), g_AppCfg.MaxHandle, g_AppCfg.MaxThread, g_AppCfg.MaxGdi))
        {
            MERROR("MAIN Resource error");
            //AutoClose();
        }
#endif
    }

    JobThreadCheck();

#if 0
    g_logQ.PushBlocking(Q_TICK);
    g_dbmQ.PushBlocking(Q_TICK);
#endif
    g_jobQ.PushBlocking(Q_TICK);    //접속한 클라이언트 작업을 위해 스레드를 깨운다.

    tmrAppState->Enabled  = true;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::AutoClose()
{
    g_AppCfg.bAppClose = true;
    //Close();
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::tbConnectClick(TObject *Sender)
{
    g_AppCfg.bThrExit = false;

    //FrmNetwork->Show();
    if (FrmNetwork->Start())
    {
        FServerRun = true;
        tbConnect->Enabled = false;
        tbDisconnect->Enabled = true;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::tbDisconnectClick(TObject *Sender)
{
    FServerRun = false;

    g_jobQ.PushBlocking(eTcpCloseAll);

    FrmNetwork->Stop();
    tbDisconnect->Enabled = false;
    tbConnect->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::tbOptionsClick(TObject *Sender)
{
    FrmOption = new TFrmOption(this);
    FrmOption->Left = FrmMain->Left + 80;
    FrmOption->Top = FrmMain->Top + 80;
    FrmOption->ShowModal();
    if (FrmOption->FUpdate)
    {
        try
        {
            ITSLog->FLogCfg = g_LogCfg;

            CtlrItr it;
            for(it=CDSCtlrManager->FLists.FObjects.begin(); it != CDSCtlrManager->FLists.FObjects.end(); ++it)
            {
                TCDSCtlr *pObj = (TCDSCtlr*)it->second;
                if (!pObj->FDispLog)
                {
                    pObj->FCLog->FLogCfg = g_LogCfg;
                    pObj->FSLog->FLogCfg = g_LogCfg;
                }
            }
        }
        catch(Exception &e)
        {
        }
    }
    delete FrmOption;
    FrmOption = NULL;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::CheckCommState()
{
    //g_SysInfo->RunSts = (FServerRun && DMManager->TcpServer->Active) ? state_normal : state_error;
    g_SysInfo->RunSts = (FServerRun) ? state_normal : state_error;

    if (g_SysInfo->RunSts == state_normal)
    {
        if (CDSCtlrManager->Total == CDSCtlrManager->Normal) g_SysInfo->ComSts = state_normal;
        else                                                 g_SysInfo->ComSts = state_error;
    }
    else
    {
        g_SysInfo->ComSts = state_error;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::UpdateProcessStatePanel()
{
    plStateAction->Color = (g_SysInfo->RunSts == state_normal) ? clGreen : clRed;
    plStateComm->Color   = (g_SysInfo->ComSts == state_normal) ? clGreen : clRed;
    plStateDb->Color     = (g_SysInfo->DbmSts == state_normal) ? clGreen : clRed;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::OnWMDbThreadMessage(TMessage &Msg)
{
    int nCommand = (int)Msg.WParam;
    int nResult  = (int)Msg.LParam;

    ReplyMessage(0);

    switch(nCommand)
    {
    case dbm_status:
        g_SysInfo->DbmSts = nResult >= 0 ? state_normal : state_error;
        break;
    case dbm_dnld_form_init:
        MINFO("MAIN VMS Message     init start event");
        MakeVmsProvideForm();
        break;
    case dbm_dnld_form_cycle:
    case dbm_dnld_form_mode:
        MINFO("MAIN VMS Message   create start event");
        MakeVmsProvideForm();
        APP_PostDbThreadMessage(dbm_save_form_download);
        break;
    case dbm_save_form_download:
        MINFO("MAIN VMS Message download start event");
        //클라이언트로 VMS폼 스케쥴이 저장되었다는 이벤트를 전송
        CDSManager->SendVmsDownloadForm();

        //VMS 제어기에 VMS폼 스케쥴을 다운로드 하도록 이벤트 전송
        g_jobQ.PushBlocking(eVmsFormDownload);
        CheckResource((g_AppCfg.MaxMemory * 1024), g_AppCfg.MaxHandle, g_AppCfg.MaxThread, g_AppCfg.MaxGdi);
        break;
    case dbm_initialize:
        break;
    }

    m_dtChkDbAive = Now();  // 데이터베이스 작업 성공/실패 여부와 상관없이 체크타이머 초기화
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::OnWMUserMessage(TMessage &Msg)
{
    ReplyMessage(0);

    if ((int)Msg.WParam == WM_WINDOW_RESTORE)
    {
        Application->Restore();
        Application->BringToFront();
        return;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::OnTcpThreadMessage(TMessage &Msg)
{
    TCDSCtlr *pObj = (TCDSCtlr*)Msg.LParam;
    CTLR_STTS stts;
    switch(Msg.WParam)
    {
    case WM_TCP_SERVER_STTS:    // 클라이언트의 연결 또는 연결종료시 수신 메시지
        try
        {
            if (pObj->Server.commState == comm_open)
            {
                pObj->dwConnectCnt++;
                MINFO("MAIN VMS Connect Event: %s", pObj->CTLR_NMBR.c_str());
            }
            else
            {
                MINFO("MAIN VMS  Closed Event: %s", pObj->CTLR_NMBR.c_str());
            }
        } catch(Exception &e) {}

        FrmControllerInfo->UpdateServerState((int)pObj);
        stts.Type = 1;
        stts.ObjPtr = (void*)pObj;
        APP_PostDbThreadMessage(dbm_save_ctlr_stts, sizeof(stts), &stts);
        break;
    case WM_CTLR_STATE_STTS:    // 연결된 제어기로 부터 상태정보를 수신할시
        try
        {
           MINFO("MAIN VMS   State Event: %s", pObj->CTLR_NMBR.c_str());
        } catch(Exception &e) {}

        FrmControllerInfo->UpdateClientState((int)pObj);
        stts.Type = 0;
        stts.ObjPtr = (void*)pObj;
        APP_PostDbThreadMessage(dbm_save_ctlr_stts, sizeof(stts), &stts);
        break;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::OnUdpDataRecvMessage(TMessage &Msg)
{
    int             nResult;
    IPC_MSG_DATA   *RcvData = (IPC_MSG_DATA*)Msg.LParam;
    INT_SENDER     *Sender  = &RcvData->Sender;
    INT_PACKET     *Pkt     = &RcvData->Pkt;
    INT_HEAD       *head    = &Pkt->head;
    INT_DATA       *data    = &Pkt->data;
    char           *pData   = &Pkt->data.Data[0];
    BYTE            OpCode  = head->OpCode;

    MINFO("MAIN Center Msg: %s.%d, OpCode: %02X, From: %02X, To: %02X", CComm_ulong2ip(Sender->IP), Sender->Port, OpCode, head->SendId, head->RecvId);

    switch(OpCode)
    {
    case INT_OP_TRAFFIC_CHANGE:
        MINFO("MAIN INT_OP_TRAFFIC_CHANGE");
        CDSManager->FIsStaticCycle = true;  //정주기 정보제공주기 플래그 설정
        SendVmsTrafficProvide(0);
        break;
    case INT_OP_VMS_PARAM_REQ:
        {
            INT_VMS_PARAM_REQ *pReq = (INT_VMS_PARAM_REQ*)pData;
            MINFO("MAIN INT_OP_VMS_PARAM_REQ: %d", pReq->Count);
            for (int ii = 0; ii < pReq->Count && ii < INT_MAX_IMDT_SCN_DNLD_MAX; ii++)
            {
                TCDSCtlr *pCDSCtlr = CDSCtlrManager->FLists.Find(AnsiString(pReq->VMS_CTLR_NMBR[ii]));
                if (!pCDSCtlr) continue;
                if (!pCDSCtlr->FSession) continue;

                IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
                pMsg->Type   = eVmsParamReq;
                pMsg->ObjPtr = (DWORD)pCDSCtlr->FSession;
                g_jobQ.PushBlocking((DWORD)pMsg);
            }
        }
        break;
    case INT_OP_VMS_POWER_CTL:  //전광판 On/Off
        {
            INT_VMS_POWER_CTL_REQ *pReq = (INT_VMS_POWER_CTL_REQ*)pData;
            MINFO("MAIN INT_OP_VMS_POWER_CTL: %.*s %d, %s, %d", INT_VMS_MAX_DATETIME, pReq->CmdTime, pReq->VMS_CTLR_NMBR, pReq->OperId, pReq->Command);
            TCDSCtlr *pCDSCtlr = CDSCtlrManager->FLists.Find(AnsiString(pReq->VMS_CTLR_NMBR));
            if (!pCDSCtlr) break;
            if (!pCDSCtlr->FSession) break;

            IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
            pMsg->Type    = eVmsLedPowerControl;
            pMsg->ObjPtr  = (DWORD)pCDSCtlr->FSession;
            pMsg->Buff[0] = pReq->Command;
            g_jobQ.PushBlocking((DWORD)pMsg);
        }
        break;
    case INT_OP_VMS_LUMINANCE_CTL:  //휘도설정
        {
            INT_VMS_LUMINANCE_REQ *pReq = (INT_VMS_LUMINANCE_REQ*)pData;
            MINFO("MAIN INT_OP_VMS_LUMINANCE_CTL: %.*s %d, %s, %02X", INT_VMS_MAX_DATETIME, pReq->CmdTime, pReq->VMS_CTLR_NMBR, pReq->OperId, pReq->BrghMode);
            TCDSCtlr *pCDSCtlr = CDSCtlrManager->FLists.Find(AnsiString(pReq->VMS_CTLR_NMBR));
            if (!pCDSCtlr) break;
            if (!pCDSCtlr->FSession) break;

            SIGNT_BRGH_SET set;
            set.VMS_CTLR_NMBR = pReq->VMS_CTLR_NMBR;
            set.BrghMode      = pReq->BrghMode;
            set.BrghCurrStep  = pReq->BrghCurrStep;
            set.BrghWeekStep  = pReq->BrghWeekStep;
            set.BrghNghtStep  = pReq->BrghNghtStep;

            IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
            pMsg->Type    = eVmsBrghSet;
            pMsg->ObjPtr  = (DWORD)pCDSCtlr->FSession;
            memcpy(pMsg->Buff, (char*)&set, sizeof(SIGNT_BRGH_SET));
            g_jobQ.PushBlocking((DWORD)pMsg);
        }
        break;
    case INT_OP_VMS_RESET:
        {
            INT_VMS_RESET_REQ *pReq = (INT_VMS_RESET_REQ*)pData;
            MINFO("MAIN INT_OP_VMS_RESET: %.*s %d, %s, %d", INT_VMS_MAX_DATETIME, pReq->CmdTime, pReq->VMS_CTLR_NMBR, pReq->OperId, pReq->Mode);
            TCDSCtlr *pCDSCtlr = CDSCtlrManager->FLists.Find(AnsiString(pReq->VMS_CTLR_NMBR));
            if (!pCDSCtlr) break;
            if (!pCDSCtlr->FSession) break;

            IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
            pMsg->Type    = eVmsReset;
            pMsg->ObjPtr  = (DWORD)pCDSCtlr->FSession;
            pMsg->Buff[0] = pReq->Mode;  //리셋모드
            g_jobQ.PushBlocking((DWORD)pMsg);
        }
        break;
    case INT_OP_VMS_PARA_SET:   //환경설정 정보 설정
        {
            INT_VMS_PARA_SET_REQ *pReq = (INT_VMS_PARA_SET_REQ*)pData;
            MINFO("MAIN INT_OP_VMS_PARA_SET: %.*s %d, %s", INT_VMS_MAX_DATETIME, pReq->CmdTime, pReq->VMS_CTLR_NMBR, pReq->OperId);
            TCDSCtlr *pCDSCtlr = CDSCtlrManager->FLists.Find(AnsiString(pReq->VMS_CTLR_NMBR));
            if (!pCDSCtlr) break;
            if (!pCDSCtlr->FSession) break;

            SIGNT_CONFIG_SET set;
            set.VMS_CTLR_NMBR = pCDSCtlr->CTLR_NMBR.ToIntDef(0);
            set.FanRunTmpr    = pReq->FanRunTmpr;
            set.HetrRunTmpr   = pReq->HetrRunTmpr;
            memcpy(set.PanlOnTime,  pReq->DispStrTm, 4);
            memcpy(set.PanlOffTime, pReq->DispEndTm, 4);

            IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
            pMsg->Type    = eVmsConfigSet;
            pMsg->ObjPtr  = (DWORD)pCDSCtlr->FSession;
            memcpy(pMsg->Buff, (char*)&set, sizeof(SIGNT_CONFIG_SET));
            g_jobQ.PushBlocking((DWORD)pMsg);
        }
        break;
    case INT_OP_VMS_IMMEDIATE_SCN_DNLD:
        {
            INT_VMS_IMMEDIATE_SCENARIO_DNLD_REQ *pReq = (INT_VMS_IMMEDIATE_SCENARIO_DNLD_REQ*)pData;
            MINFO("MAIN INT_OP_VMS_IMMEDIATE_SCN_DNLD: %.*s, %s", INT_VMS_MAX_DATETIME, pReq->CmdTime, pReq->OperId);
            for (int ii = 0; ii < pReq->Count && ii < INT_MAX_IMDT_SCN_DNLD_MAX; ii++)
            {
                TCDSCtlr *pObj = CDSCtlrManager->FLists.Find(AnsiString(pReq->VMS_CTLR_NMBR[ii]));
                if (!pObj) continue;
                if (!pObj->FSession) continue;

                CDSCtlrManager->InitProvide(pObj);

#if 0
                IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
                pMsg->Type   = eVmsScenarioDownload;
                pMsg->ObjPtr = (DWORD)pObj->FSession;
                g_jobQ.PushBlocking((DWORD)pMsg);
#endif
            }
            APP_PostDbThreadMessage(dbm_dnld_form_cycle);
            //APP_PostDbThreadMessage(dbm_dnld_form_mode);
        }
        break;
    case INT_OP_VMS_MODE:
        {
            INT_VMS_MODE_REQ *pReq = (INT_VMS_MODE_REQ*)pData;
            MINFO("MAIN INT_OP_VMS_MODE: %.*s %s, %s, %d EA", INT_VMS_MAX_DATETIME, pReq->CmdTime, pReq->OperId, pReq->Count);

            //모든 VMS에 메시지다운로드 플래그 비활성화 시킴
            //CDSCtlrManager->InitProvide(false);

            //수신한 VMS에 대하여 다운로드 플래그 활성화 시킴
            for(int ii = 0; ii < pReq->Count && ii < INT_VMS_MAX_MODE; ii++)
            {
                TCDSCtlr *pObj = CDSCtlrManager->FLists.Find(AnsiString(pReq->Unit[ii].VMS_CTLR_NMBR));
                if (!pObj) continue;
                if (pObj->Server.useFlag != use_enable) continue;

                if (pObj->CTRLMODE->Control == pReq->Unit[ii].Mode)
                    pObj->FModeChange = false;
                else
                    pObj->FModeChange = true;

                pObj->CTRLMODE->Control = pReq->Unit[ii].Mode;
                pObj->DSTATE.OprMode = pObj->CTRLMODE->Control;
                pObj->RSTATE.OprMode = pObj->CTRLMODE->Control;
                if      (pObj->CTRLMODE->Control == 'A') pObj->OPER_MODE = "A";
                else if (pObj->CTRLMODE->Control == 'B') pObj->OPER_MODE = "B";
                else                                     pObj->OPER_MODE = "F";

                //pObj->FProvide = true;
                CDSCtlrManager->InitProvide(pObj);
            }
            FrmControllerInfo->UpdateCtlrList();
            APP_PostDbThreadMessage(dbm_dnld_form_mode);
        }
        break;
    case INT_OP_VMS_STATE_REQ:
        MINFO("MAIN INT_OP_VMS_STATE_REQ");
        CDSCtlrManager->SendCtlrSttsAll();
        break;
    case INT_OP_VMS_IMAGE_SYMBOL:
        MINFO("MAIN INT_OP_VMS_IMAGE_SYMBOL");
        APP_PostDbThreadMessage(dbm_master_symbol_image);
        break;
    case INT_OP_VMS_IMAGE_TRAFFIC:
        MINFO("MAIN INT_OP_VMS_IMAGE_TRAFFIC");
        APP_PostDbThreadMessage(dbm_master_symbol_traffic);
        break;
    case INT_OP_VMS_FORM_UPDATE:
        MINFO("MAIN INT_OP_VMS_FORM_UPDATE");
        APP_PostDbThreadMessage(dbm_master_form);
        break;
    case INT_OP_VMS_IFSC_UPDATE:
        MINFO("MAIN INT_OP_VMS_IFSC_UPDATE");
        APP_PostDbThreadMessage(dbm_master_vms_ifsc);
        break;
    default:
        MINFO("MAIN INT_UNKNOWN: %02X", OpCode);
        break;
    }
}
//---------------------------------------------------------------------------

#if 0
void __fastcall TFrmMain::ClientResponse(int Flag, REQ_INFO_STRUCT *pReq, int error, void *pData)
{
#ifdef CENTERCOMM
    BYTE ErrCode;
    int sResult;

    switch(error)
    {
    case SYS_ERR_NONE:                 break;
    case SYS_ERR_OTHER:                ErrCode = INT_ERROR_OTHER; break;
    case SYS_ERR_INTERNAL:             ErrCode = INT_ERROR_SYSTEM; break;
    case SYS_ERR_MEMORY:               ErrCode = INT_ERROR_SYSTEM; break;
    case SYS_ERR_DATABASE:             ErrCode = INT_ERROR_SYSTEM; break;
    case SYS_ERR_RESET:                ErrCode = INT_ERROR_SYSTEM; break;
    case SYS_ERR_START:                ErrCode = INT_ERROR_SYSTEM; break;
    case SYS_ERR_OFFLINE:              ErrCode = INT_ERROR_OFFLINE; break;
    case SYS_ERR_NO_RES:               ErrCode = INT_ERROR_NO_RESPONSE; break;
    case SYS_ERR_ACCESS:               ErrCode = INT_ERROR_PROCESS; break;
    case SYS_ERR_INVALID:              ErrCode = INT_ERROR_OTHER; break;
    case SYS_ERR_UNKNOWN:              ErrCode = INT_ERROR_UNKNOWN_CODE; break;
    case SYS_ERR_WRITE_LENGTH:         ErrCode = INT_ERROR_OTHER; break;
    case SYS_ERR_PACKET_SIZE_LARGE:    ErrCode = INT_ERROR_OTHER; break;
    case SYS_ERR_INVALID_TAG:          ErrCode = INT_ERROR_OTHER; break;
    case SYS_ERR_CRC:                  ErrCode = INT_ERROR_OTHER; break;
    case SYS_ERR_LENGTH:               ErrCode = INT_ERROR_LENGTH; break;
    case SYS_ERR_ADDRESS:              ErrCode = INT_ERROR_ADDRESS; break;
    case SYS_ERR_HEADER_OPTIONS:       ErrCode = INT_ERROR_HEADER; break;
    case SYS_ERR_UNKNOWN_COMMAND:      ErrCode = INT_ERROR_UNKNOWN_OPCODE; break;
    case SYS_ERR_RECEIVE_TIMEOUT:      ErrCode = INT_ERROR_OTHER; break;
    case SYS_ERR_DATA_SIZE:            ErrCode = INT_ERROR_DISCORD; break;
    case SYS_ERR_MISMATCH:             ErrCode = INT_ERROR_OTHER; break;
    case SYS_ERR_INVALID_PARA:         ErrCode = INT_ERROR_INVALID_DATA; break;
    case SYS_ERR_MOVEMENT:             ErrCode = INT_ERROR_MOVEMENT; break;
    case SYS_ERR_UNAUTHORIZED:         ErrCode = INT_ERROR_UNAUTHORIZED; break;
    default:                           ErrCode = INT_ERROR_OTHER; break;
    }

    if (Flag == SEND_ACK)
    {
        INT_ACK_RES Ack;

        memset(&Ack, 0x00, sizeof(Ack));

        Ack.OPCode.Type = INT_TYPE(pReq->OpCode);
        Ack.OPCode.Kind = INT_KIND(pReq->OpCode);
        Ack.MsgSeq = pReq->MsgSeq;

        if ((sResult = AckRes(&Ack, pReq->ProcessID)) != UDP_ERR_NONE)
        {
            MERROR("MAIN AckRes fail %d", sResult);
        }
    }
    else
    if (Flag == SEND_NACK)
    {
        INT_NACK_RES Nack;

        memset(&Nack, 0x00, sizeof(Nack));

        Nack.OPCode.Type = INT_TYPE(pReq->OpCode);
        Nack.OPCode.Kind = INT_KIND(pReq->OpCode);
        Nack.MsgSeq = pReq->MsgSeq;
        Nack.ErrCode = ErrCode;

        if ((sResult = NackRes(&Nack, pReq->ProcessID)) != UDP_ERR_NONE)
        {
            MERROR("MAIN NackRes fail %d", sResult);
        }
    }
#endif
}
//---------------------------------------------------------------------------
#endif

bool __fastcall TFrmMain::CheckBasisTime(char *p, int Cycle, int Basis)
{
    char cTime[15];

    COMM_MakeBasisTime(cTime, Cycle, Basis);

    if (memcmp(p, cTime, 14) != 0)
    {
        memcpy(p, cTime, 14);
        return true;
    }

    return false;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::CheckProvideTimeout()
{
    VMS_PROVIDE_RESULE ProvideSave;
    VMS_PROVIDE_RESULE DownLoadSave;

    memset(&ProvideSave,  0x00, sizeof(ProvideSave));
    memset(&DownLoadSave, 0x00, sizeof(DownLoadSave));

    ProvideSave.Type  = provide_form;
    ProvideSave.Count = 0;

    DownLoadSave.Type  = provide_download;
    DownLoadSave.Count = 0;

    CtlrItr it;
    for(it=CDSCtlrManager->FLists.FObjects.begin(); it != CDSCtlrManager->FLists.FObjects.end(); ++it)
    {
        TCDSCtlr *pObj = (TCDSCtlr*)it->second;

        if (pObj->Server.useFlag != use_enable) continue;

        if ((pObj->DOWNLOAD->SaveFlag == false) &&
            (COMM_TimeDiff(pObj->DOWNLOAD->dTimer) > VMS_DOWNLOAD_TIMEOUT))
        {
             DownLoadSave.pObj[DownLoadSave.Count++] = (void *)pObj;
             pObj->DOWNLOAD->SaveFlag = true;
        }

		if ((pObj->CTRLMODE->SaveFlag == false) &&
			(COMM_TimeDiff(pObj->CTRLMODE->pTimer) > VMS_PROVIDE_TIMEOUT))
		{
			ProvideSave.pObj[ProvideSave.Count++] = (void *)pObj;
			pObj->CTRLMODE->SaveFlag = true;
		}

        // 패킷크기가 채워졌으면 DB 작업스레드로 전송
        if (ProvideSave.Count >= MAX_VMS_PROVIDE_RESULT)
        {
            APP_PostDbThreadMessage(dbm_provide_result, sizeof(ProvideSave), &ProvideSave);
        }
        if (DownLoadSave.Count >= MAX_VMS_PROVIDE_RESULT)
        {
            APP_PostDbThreadMessage(dbm_provide_result, sizeof(DownLoadSave), &DownLoadSave);
        }
    }

    // 실패작업이 존재하면 DB 작업스레드로 전송
    if (ProvideSave.Count > 0)
    {
        APP_PostDbThreadMessage(dbm_provide_result, sizeof(ProvideSave), &ProvideSave);
    }
    if (DownLoadSave.Count > 0)
    {
        APP_PostDbThreadMessage(dbm_provide_result, sizeof(DownLoadSave), &DownLoadSave);
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::SendTimeSync()
{
    CtlrItr it;
    for(it=CDSCtlrManager->FLists.FObjects.begin(); it != CDSCtlrManager->FLists.FObjects.end(); ++it)
    {
        TCDSCtlr *pCDSCtlr = (TCDSCtlr*)it->second;

        if (pCDSCtlr->Server.useFlag != use_enable) continue;
        if (pCDSCtlr->FSession)
        {
            IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
            pMsg->Type    = eVmsTimeControl;
            pMsg->ObjPtr  = (DWORD)pCDSCtlr->FSession;
            memcpy(pMsg->Buff, AnsiString(Now().FormatString("yyyymmddhhnnss")).c_str(), MAX_SYS_TIME);
            g_jobQ.PushBlocking((DWORD)pMsg);

            // 제어기가 연결되어 있으면 전송
            MINFO("MAIN SendTimeSync command send: %s", pCDSCtlr->CTLR_NMBR.c_str());
        }
    }
}
//---------------------------------------------------------------------------

bool __fastcall TFrmMain::CheckResource(size_t MaxMemory, DWORD MaxHandle, DWORD MaxThread, DWORD MaxGdi)
{
    bool result;
    HANDLE hProcess;
    PROCESS_MEMORY_COUNTERS pmc;
    size_t uSize;
    DWORD HandleCount, ThreadCount, GdiCount;
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;
    DWORD ProcessId;

    result = false;
    uSize = 0;
    HandleCount = 0;
    ThreadCount = 0;
    GdiCount = 0;

    hProcess = GetCurrentProcess();

    if (hProcess != NULL)
    {
        if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) )
        {
            uSize = pmc.WorkingSetSize/1024;

            if ((MaxMemory != 0) && (uSize > MaxMemory))
            {
                MERROR("MAIN Memory usage exceeds standards!!!...[%d][%d]", MaxMemory, uSize);
                result = true;
            }
        }

        if ( GetProcessHandleCount( hProcess, &HandleCount) )
        {
            if ((MaxHandle != 0) && (HandleCount > MaxHandle))
            {
                MERROR("MAIN Window handle exceed standards!!!...[%d][%d]", MaxHandle, HandleCount);
                result = true;
            }
        }

        ProcessId = GetCurrentProcessId();

        if ((hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 )) != INVALID_HANDLE_VALUE)
        {
            pe32.dwSize = sizeof( PROCESSENTRY32 );

            if ( Process32First( hProcessSnap, &pe32 ) )
            {
                do
                {
                    if (pe32.th32ProcessID == ProcessId)
                    {
                        ThreadCount = pe32.cntThreads;

                        if ((MaxThread != 0) && (ThreadCount > MaxThread))
                        {
                            MERROR("MAIN Criteria exceeded thread!!!...[%d][%d]", MaxThread, ThreadCount);
                            result = true;
                        }
                        break;
                    }
                } while( Process32Next( hProcessSnap, &pe32 ) );
            }

            CloseHandle( hProcessSnap );
        }

        GdiCount = GetGuiResources( hProcess, GR_GDIOBJECTS);

        if ((MaxGdi != 0) && (GdiCount > MaxGdi))
        {
            MERROR("MAIN GDI Objects exceeding standards!!!...[%d][%d]", MaxGdi, GdiCount);
            result = true;
        }
        CloseHandle( hProcess );
    }

    try
    {
FMemSize = uSize;
        plMemory->Caption = FormatFloat("##,##0", uSize)      ;// + " KB";
        plHandle->Caption = FormatFloat("##,##0", HandleCount);// + " EA";
        plThread->Caption = FormatFloat("##,##0", ThreadCount);// + " EA";
        plGdi->Caption    = FormatFloat("##,##0", GdiCount)   ;// + " EA";

        MINFO("MAIN Memory: %s, Haldle: %s, Thread: %s, GDI: %s",
                         AnsiString(plMemory->Caption).c_str(),
                         AnsiString(plHandle->Caption).c_str(),
                         AnsiString(plThread->Caption).c_str(),
                         AnsiString(plGdi->Caption).c_str()
                         );
    } catch (Exception &e) {}

    return result;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::Panel16DblClick(TObject *Sender)
{
    CheckResource((g_AppCfg.MaxMemory * 1024), g_AppCfg.MaxHandle, g_AppCfg.MaxThread, g_AppCfg.MaxGdi);
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::plStateDbDblClick(TObject *Sender)
{
APP_PostDbThreadMessage(dbm_master_symbol_image);
APP_PostDbThreadMessage(dbm_master_form);
APP_PostDbThreadMessage(dbm_master_vms_ifsc);
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::plStateCommDblClick(TObject *Sender)
{
    AnsiString VMS_IFSC_ID;
    int        SECT_LNGT;

    TItsMap<int,        TObjectId*>    FLists;
    TItsMap<AnsiString, TVmsIfscGrad*> FGrads;

    VMS_TRAF   traf;

    int        SPED;            //	N	NUMBER(3)	Y	0		속도
    int        TRVL_HH;         //	N	NUMBER(6)	Y	0		통행 시간
    AnsiString CMTR_GRAD_CD;    //	N	VARCHAR2(7)	Y			소통 등급 코드

    if (!CDSVmsIfscTrafManager) return;

    FOR_STL(TCDSVmsIfscTraf*, pObj, CDSVmsIfscTrafManager->FVmsIfscLists)
    {
        int objValid = pObj->IsValid == false ? 0 : 1;
        MINFO("VMS_IFSC_ID: %s, SECT_LNGT: %5d, VALID: %d, Objects: %d, SPED: %3d, TRVL_HH: %4d, GRAD_CD: %s",
              pObj->VMS_IFSC_ID, pObj->SECT_LNGT, objValid, pObj->FLists.Size(), pObj->traf.SPED, pObj->traf.TRVL_HH, pObj->traf.CMTR_GRAD_CD);

        FOR_STL(TVmsIfscGrad*, pGrad, pObj->FGrads)
        {
            int gradValid = pGrad->IsValid == false ? 0 : 1;
            MINFO("   GRAD_CD: %s, VALID: %d, LWSTSPED: %3d, HGHSSPED: %3d", pGrad->CMTR_GRAD_CD, gradValid, pGrad->LWSTSPED, pGrad->HGHSSPED);
        }

        int ii = 1;
        FOR_STL(TObjectId*, pID, pObj->FLists)
        {
            int idValid = pID->IsValid == false ? 0 : 1;
            TCDSIfscTraf* pIfsc = CDSVmsIfscTrafManager->FIfscTrafLists.Find(pID->ID);
            if (pIfsc)
            {
                MINFO("           %2d: IFSC_ID: %s, SECT_LNGT: %5d, VALID: %d, SPED: %3d, TRVL_HH: %4d", ii, pIfsc->IFSC_ID, pIfsc->SECT_LNGT, idValid, pIfsc->SPED, pIfsc->TRVL_HH);
            }
            else
            {
                MINFO("           %2d: IFSC_ID: %s, Not Found", ii, pID->ID);
            }
            ii++;
        }
        MINFO("");
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::plStateActionDblClick(TObject *Sender)
{
    plStateAction->Enabled = false;
    tmrRunProvide->Enabled = false;
    tmrRunProvide->Enabled = true;
    CDSManager->FIsStaticCycle = true;  //정주기 정보제공주기 플래그 설정
    CtlrItr it;
    for(it=CDSCtlrManager->FLists.FObjects.begin(); it != CDSCtlrManager->FLists.FObjects.end(); ++it)
    {
        TCDSCtlr *pObj = (TCDSCtlr*)it->second;
        if (!pObj->FSession) continue;
        CDSCtlrManager->InitProvide(pObj);
    }
    APP_PostDbThreadMessage(dbm_dnld_form_cycle);
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::tmrRunProvideTimer(TObject *Sender)
{
    tmrRunProvide->Enabled = false;
    plStateAction->Enabled = true;
}
//---------------------------------------------------------------------------

bool __fastcall TFrmMain::JobThreadStart()
{
    int nThreadCnt = 0;

    if (true)
    {
        LogThread = new TLogThread();
        if (!LogThread) return false;
        LogThread->FPnlState = plStateLog;
        LogThread->Name = "LogThread";
        LogThread->Execute();
        G_Threads.Push(nThreadCnt++, LogThread);
    }

    if (true)
    {
        DbmThread = new TDbmThread();
        if (!DbmThread) return false;
        DbmThread->FPnlState = plStateDbm;
        DbmThread->Name = "DbmThread";
        DbmThread->Execute();
        G_Threads.Push(nThreadCnt++, DbmThread);
    }

    if (true)
    {
        JobThread = new TJobThread();
        if (!JobThread) return false;
        JobThread->FPnlState = plStateJob;
        JobThread->Name = "JobThread";
        JobThread->Execute();
        G_Threads.Push(nThreadCnt++, JobThread);
    }

    return true;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::JobThreadCheck()
{
    int nTermCnt = 0;
    for (thrIterator it=G_Threads.FObjects.begin(); it != G_Threads.FObjects.end(); ++it)
    {
        TItsThread *pObj = (TItsThread*)it->second;
        if (pObj->IsTerm())
        {
            pObj->Execute();
            nTermCnt++;
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::JobThreadStop()
{
    g_AppCfg.bThrExit  = true;
    g_jobQ.PushBlocking(Q_CLOSE);
    g_dbmQ.PushBlocking(Q_CLOSE);
    g_logQ.PushBlocking(Q_CLOSE);

    HANDLE handles[50];
    int    nWaits = 0;
    for (thrIterator it=G_Threads.FObjects.begin(); it != G_Threads.FObjects.end(); ++it)
    {
        TItsThread *pObj = (TItsThread*)it->second;
        if (!pObj->IsTerm())
        {
            //pObj->Terminate(2000);
            handles[nWaits++] = pObj->Handle;
        }
    }
    WaitForMultipleObjects(nWaits, handles, true, 1000);
    G_Threads.RemoveAll();
}
//---------------------------------------------------------------------------
void __fastcall TFrmMain::TerminateApplication()
{
    MERROR("MAIN Program terminated start");

    SendTerminal();

    CComm_Close();

    MERROR("MAIN Program terminated end");

    g_logQ.PushBlocking(Q_CLOSE);
    for (int ii = 0; ii < 50; ii++)
    {
        Sleep(30);
        Application->ProcessMessages();
        if (g_AppCfg.bThrJobExit) break;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::SendTerminal()
{
    int result;

    MINFO("MAIN SendTerminal");

    // 동작, 통신, DB 모두 이상 처리
    g_SysInfo->RunSts = state_error;
    g_SysInfo->ComSts = state_error;
    g_SysInfo->DbmSts = state_error;

    // 모든 시설물 통신 오프라인 처리
    CtlrItr it;
    for(it=CDSCtlrManager->FLists.FObjects.begin(); it != CDSCtlrManager->FLists.FObjects.end(); ++it)
    {
        TCDSCtlr *pObj = (TCDSCtlr*)it->second;

        if (!pObj->Used) continue;
        pObj->Server.thrState = thr_stop;
        pObj->Client.thrState = thr_stop;
        pObj->Server.commState = comm_close;
        pObj->Client.commState = comm_close;
    }

    INT_PG_STATE_RES PgState;

    memset(&PgState, 0x00, sizeof(PgState));

    PgState.Count = 1;
    PgState.Unit[0].Type    = INT_ID_VMS_SERVER;
    PgState.Unit[0].DB      = g_SysInfo->DbmSts;
    PgState.Unit[0].Comm    = g_SysInfo->ComSts;
    PgState.Unit[0].Action  = g_SysInfo->RunSts;

    result = CComm_CmmProcessStateNotify(&PgState);

    TDMAdoDb *FDb = new TDMAdoDb(NULL);
    try
    {
        if (FDb->Connect(g_AppCfg.db.sConnectStr))
        {
            CDSProcessManager->SaveUnitStts(FDb->GetConnection());
            CDSCtlrManager->SaveCtlrSttsAll(FDb->GetConnection());
        }

    }
    __finally
    {
        if (FDb)
        {
            FDb->Close();
        }
        SAFE_DELETE(FDb);
    }
}
//---------------------------------------------------------------------------

int __fastcall TFrmMain::SendVmsThreadMessage(BYTE *AVmsId, IPC_MSG_DATA *ARcvData, BYTE AOpCode, char *AData)
{
#if 0
    AnsiString    sVmsId;
    IPCUDPPACKET *pPI = NULL;

    sVmsId.sprintf("%.*s", INT_VMS_MAX_ID, (char*)AVmsId);

    TCDSCtlr *pObj = CDSCtlrManager->FLists.Find(sVmsId);
    if (!pObj)
    {
        return VERR_NOTFOUND_VMS;
    }

    if (pObj->Server.commState != comm_close)
    {
        return VERR_OFFLINE;
    }

    if (!pObj->pPackQueue)
    {
        return VERR_INTERNAL;
    }

    pPI = new IPCUDPPACKET;
    if (pPI == NULL) return VERR_MEMORY_ALLOC;

    pPI->Sender.IP   = ARcvData->Sender.IP;
    pPI->Sender.Port = ARcvData->Sender.Port;
    pPI->RecvId      = ARcvData->Pkt.head.SendId;
    pPI->OPCode      = AOpCode;
    pPI->Size        = (int)ARcvData->Pkt.head.Length;
    if (pPI->Size > 0)
    {
        pPI->Data = new char[pPI->Size];
        if (!pPI->Data)
        {
            delete pPI;
            return VERR_INTERNAL;
        }
        CopyMemory(pPI->Data, AData, pPI->Size);
    }
    pObj->pPackQueue->Add((void*)pPI);
#endif
    return VERR_NONE;
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::plTimeDblClick(TObject *Sender)
{
    if (!FrmNetwork->Showing)
    {
        FrmNetwork->Show();
    }

}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::tmrProvideTimer(TObject *Sender)
{
    SendVmsTrafficProvide(2);
}
//---------------------------------------------------------------------------

void __fastcall TFrmMain::SendVmsTrafficProvide(int AType)
{
#if 0
    tmrProvide->Enabled = false;

    MINFO("MAIN *** VMS Traffic Event Acitve, %d", AType);
    APP_PostDbThreadMessage(dbm_dnld_form_cycle);
	m_dtProvider = Now();         // 정보제공 타이머

    if (AType == 0)
    {
        tmrProvide->Interval = (g_AppCfg.nTrafficCycleTime)*1000 + (g_AppCfg.nTrafficBasisTime*1000);
        plRemain->Color = clBlack;
    }
    else
    {
        tmrProvide->Interval = (g_AppCfg.nTrafficCycleTime)*1000;   //분단위 주기만큼 타이머가동해야 함(소통정보 이벤트 처리가 없는 경우)
        plRemain->Color = clGreen;
    }
    FFirstRunning = false;
    FProvideRemain = tmrProvide->Interval / 1000;
    tmrProvide->Enabled = true;
#else
    tmrProvide->Enabled = false;

    MINFO("MAIN *** VMS Traffic Event Acitve, %d", AType);
    APP_PostDbThreadMessage(dbm_dnld_form_cycle);
	m_dtProvider = Now();         // 정보제공 타이머

    int nProvideRemain = 0;
    nProvideRemain = SecondOfTheDay(Now());
    nProvideRemain %= g_AppCfg.nTrafficCycleTime;
    nProvideRemain = g_AppCfg.nTrafficCycleTime - nProvideRemain;
    nProvideRemain += g_AppCfg.nTrafficBasisTime;

    if (AType == 0)
    {
        tmrProvide->Interval = nProvideRemain*1000;
        //tmrProvide->Interval = (g_AppCfg.nTrafficCycleTime)*1000 + (g_AppCfg.nTrafficBasisTime*1000);
        plRemain->Color = clBlack;
    }
    else
    {
        //tmrProvide->Interval = (g_AppCfg.nTrafficCycleTime)*1000;   //분단위 주기만큼 타이머가동해야 함(소통정보 이벤트 처리가 없는 경우)
        tmrProvide->Interval = nProvideRemain*1000;   //분단위 주기만큼 타이머가동해야 함(소통정보 이벤트 처리가 없는 경우)
        plRemain->Color = clGreen;
    }
    FFirstRunning = false;
    //FProvideRemain = tmrProvide->Interval / 1000;
    FProvideRemain = nProvideRemain;
    tmrProvide->Enabled = true;
#endif
}
//---------------------------------------------------------------------------

