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

#include <vcl.h>
#include "ITSSkinF.h"
#include "ITSUtilF.h"
#include "ITSLangTransF.h"
#include "CDSProcessF.h"
#include "CDSCctvCtlrF.h"
#pragma hdrstop

#include "FrmCctvCtrlF.h"

//---------------------------------------------------------------------------
#include "CTV0500MF.h"
//---------------------------------------------------------------------------
#ifndef ULONG_PTR
#define ULONG_PTR unsigned long *
#endif

#include <stdio.h>
#include <string.h>
#include <list>
#include <map>

#define STRICT
#include <windows.h>
#include <algorithm>
using std::min;
using std::max;
#include "gdiplus.h"
#include "GdiplusBase.h" //항상 넣어 둔다.

class CGdiPlusStarter
{
private:
	ULONG_PTR m_gpToken;

public:
	bool m_bSuccess;
	CGdiPlusStarter()
    {
        ::CoInitialize(NULL);
		Gdiplus::GdiplusStartupInput gpsi;
		m_bSuccess = (Gdiplus::GdiplusStartup(&m_gpToken, &gpsi, NULL) == Gdiplus::Ok);
	}
	~CGdiPlusStarter()
    {
		Gdiplus::GdiplusShutdown(m_gpToken);
        ::CoUninitialize();
	}
};
CGdiPlusStarter g_gps;


//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "cxClasses"
#pragma link "cxContainer"
#pragma link "cxControls"
#pragma link "cxEdit"
#pragma link "cxGraphics"
#pragma link "cxHint"
#pragma link "cxLabel"
#pragma link "cxLookAndFeelPainters"
#pragma link "cxLookAndFeels"
#pragma link "cxMaskEdit"
#pragma link "cxPC"
#pragma link "cxPCdxBarPopupMenu"
#pragma link "cxSpinEdit"
#pragma link "cxTextEdit"
#pragma link "dxBar"
#pragma link "dxCustomHint"
#pragma link "dxRibbon"
#pragma link "dxRibbonGallery"
#pragma link "dxRibbonSkins"
#pragma link "dxRibbonStatusBar"
#pragma link "dxScreenTip"
#pragma link "dxSkinBlack"
#pragma link "dxSkinBlue"
#pragma link "dxSkinCaramel"
#pragma link "dxSkinChooserGallery"
#pragma link "dxSkinCoffee"
#pragma link "dxSkinDarkRoom"
#pragma link "dxSkinDarkSide"
#pragma link "dxSkinFoggy"
#pragma link "dxSkinGlassOceans"
#pragma link "dxSkiniMaginary"
#pragma link "dxSkinLilian"
#pragma link "dxSkinLiquidSky"
#pragma link "dxSkinLondonLiquidSky"
#pragma link "dxSkinMcSkin"
#pragma link "dxSkinMoneyTwins"
#pragma link "dxSkinOffice2007Black"
#pragma link "dxSkinOffice2007Blue"
#pragma link "dxSkinOffice2007Green"
#pragma link "dxSkinOffice2007Pink"
#pragma link "dxSkinOffice2007Silver"
#pragma link "dxSkinOffice2010Black"
#pragma link "dxSkinOffice2010Blue"
#pragma link "dxSkinOffice2010Silver"
#pragma link "dxSkinsCore"
#pragma link "dxSkinscxPCPainter"
#pragma link "dxSkinsdxBarPainter"
#pragma link "dxSkinsdxRibbonPainter"
#pragma link "dxSkinSeven"
#pragma link "dxSkinsForm"
#pragma link "dxSkinSharp"
#pragma link "dxSkinSilver"
#pragma link "dxSkinStardust"
#pragma link "dxStatusBar"
#pragma link "dxTabbedMDI"
#pragma link "IdAntiFreeze"
#pragma link "IdAntiFreezeBase"
#pragma link "IdBaseComponent"
#pragma link "cxButtons"
#pragma link "cxGroupBox"
#pragma link "ImageBtn"
#pragma link "XNSSDKDEVICELib_OCX"
#pragma link "XNSSDKWINDOWLib_OCX"
#pragma resource "*.dfm"

TFrmCctvCtrl *FrmCctvCtrl = NULL;
//---------------------------------------------------------------------------

__fastcall TFrmCctvCtrl::TFrmCctvCtrl(TComponent* Owner)
    : TForm(Owner)//TdxCustomRibbonForm(Owner)//TForm(Owner)
{
    //DoubleBuffered = true;

    g_AppCfg.lMainWinHandle = (long)Handle;
#if 0
    StartJobThread();
    while(!PostJobMessage(WM_THREAD, WP_PING)) ;
#endif

    Application->OnException = OnAppException;

    ::CoInitialize(NULL);

    LangTrans->Translate(this, ITSDb_GetConnection());
    ITSSkin_Initialize(Application, g_AppCfg.sLang, true, true);
    ITSSkin_Load(this);
    CMM_LoadForm(g_sFormsDir, this);

#if 0
    String sCaption = "";
    ReadConfigInfo(g_AppCfg.sConfigFile, "APPLICATION", "CAPTION", sCaption);
    ITSSkin_Caption(sCaption == "1" ? true : false);
#endif

    SetColorScheme(g_AppCfg.sSkinName);

    FCctvServerState = cctv_normal;

    ItsProcessManager = new TItsProcessManager();
    CctvCtlrManager = new TCctvCtlrManager();

	TmrOnShow->Enabled = false;
    TmrAppState->Enabled = false;
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::FormCreate(TObject *Sender)
{
    /* 레지스터리 등록 IE 최신버전 */
    String sExeName = ExtractFileName(Application->ExeName);
    UpdateExplorerEmulatorVersion(sExeName);

    Application->ShowMainForm = false;

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

    //DeleteLogFiles((PTCHAR)g_sLogDir.c_str(), 30, (PTCHAR)"*.*");


    //WindowState = wsMaximized;

    // 종료조건이 있는경우..
    //Application->Terminate();
    //return;
    ItsProcessManager->LoadFromDb();
    CctvCtlrManager->LoadFromDb();
    CctvCtlrManager->LoadStatusFromDb();

    CTV0500M = new TCTV0500M(PnlBack);
    CTV0500M->FTmrShow = false;;
    CTV0500M->Parent   = PnlBack;
    CTV0500M->Show();

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

bool __fastcall TFrmCctvCtrl::UpdateExplorerEmulatorVersion(String AAppName)
{
    TRegistry *reg = new TRegistry(KEY_READ|KEY_WRITE|KEY_WOW64_64KEY);
    if (reg == NULL) return false;

    String sKey = "SOFTWARE\\Wow6432Node\\Microsoft\\Internet Explorer\\MAIN\\FeatureControl\\FEATURE_BROWSER_EMULATION";

    reg->RootKey = HKEY_LOCAL_MACHINE;
    if (!reg->KeyExists(sKey))
    {
        //MessageDlg("Key not found! Created now.", mtInformation, TMsgDlgButtons() << mbOK, 0);
        bool bOpenKey = reg->CreateKey(sKey);
        //return false;
    }
    reg->Access = KEY_WRITE;

    bool openResult = reg->OpenKey(sKey, true);
    if(!openResult)
    {
        //MessageDlg("Unable to create key! Exiting.", mtError, TMsgDlgButtons() << mbOK, 0);
        return false;
    }

    if (!reg->KeyExists(AAppName))
    {
        reg->WriteInteger(AAppName, 10000);
    }

    reg->CloseKey();
    reg->Free();

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

/*
 * Form을 보여줄때 호출되는 event 메서드이다.
 *  arguments
 *      Sender : event handler 객체
 *  return
 *      void
 */
void __fastcall TFrmCctvCtrl::FormShow(TObject *Sender)
{
    Refresh();
    Application->ProcessMessages();
    g_AppCfg.lMainWinHandle = (long)Handle;

	if (g_pLOGIN)
    {
        GetUserMenuRight(g_pLOGIN->sUserId, g_pLOGIN->sUserRightId);
    }

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

/*
 * 프로그램 기동후 최초에 수행된다.
 *  arguments
 *
 *  return
 *      void
 */
void __fastcall TFrmCctvCtrl::TmrOnShowTimer(TObject *Sender)
{
    Refresh();
	TmrOnShow->Enabled = false;
	Application->ProcessMessages();

    CTV0500M->TmrShow->Enabled = true;

    UpdateCctvCommStatus(true);

    int nPort = 4602;
    TItsProcess *pPrcs = ItsProcessManager->FLists.Find(g_AppCfg.sProcessId);
    if (!pPrcs)
    {
        if (g_AppCfg.sLang == "kr")
        {
            Application->MessageBox(L"통신프로세스를 초기화 하지 못하였습니다.\r\n환경설정에서 시스템ID를 확인하세요.\r\n프로그램을 종료합니다.",
                                    L"프로그램 통신오류_1", MB_OK|MB_ICONERROR|MB_APPLMODAL);
        }
        else
        {
            Application->MessageBox(L"Failed to initialize communication process.\r\nPlease check your system ID in preferences.\r\nExit the program.",
                                    L"Program communication error_1", MB_OK|MB_ICONERROR|MB_APPLMODAL);
        }
        g_AppCfg.bAppClose = true;
        Close();
        return;
    }

    nPort = pPrcs->PRGM_PORT.ToIntDef(4602);
    nPort += 1; //VMS운영단말은 DB에 저장되어 있지 않기 때문에 포트번호를 1 증가시켜 통신한다.
    int nResult = CComm_Initialize((long)Handle, g_AppCfg.sProcessId, "UOT", nPort, g_AppCfg.sLogDay);
    if (VERR_NONE != nResult)
    {
        if (g_AppCfg.sLang == "kr")
        {
            Application->MessageBox(L"통신프로세스를 초기화 하지 못하였습니다.\r\n환경설정에서 시스템ID를 확인하세요.\r\n프로그램을 종료합니다.",
                                    L"프로그램 통신오류_1", MB_OK|MB_ICONERROR|MB_APPLMODAL);
        }
        else
        {
            Application->MessageBox(L"Failed to initialize communication process.\r\nPlease check your system ID in preferences.\r\nExit the program.",
                                    L"Program communication error_1", MB_OK|MB_ICONERROR|MB_APPLMODAL);
        }
        g_AppCfg.bAppClose = true;
        Close();
        return;
    }
    FOR_STL(TItsProcess*, pObj, ItsProcessManager->FLists)
    {
        if (pObj->DEL_YN == "Y") continue;
        AnsiString sProcessId = AnsiString(pObj->SYST_ID);
        AnsiString sSystemTp  = AnsiString(pObj->SYST_TYPE);
        AnsiString sIpAddress = AnsiString(pObj->SYST_IP_1);
        AnsiString sUdpPort   = AnsiString(pObj->PRGM_PORT);
        if (CComm_AddProcess(sProcessId, sSystemTp, sIpAddress, sUdpPort) >= 0)
        {
            if ("UOT" == sSystemTp)
            {
                nPort = sUdpPort.ToIntDef(0);
                CComm_AddProcess(sProcessId, sSystemTp, sIpAddress, AnsiString(nPort+2));
            }
        }
    }
    if (VERR_NONE != CComm_Open())
    {
        if (g_AppCfg.sLang == "kr")
        {
            Application->MessageBox(L"통신프로세스를 초기화 하지 못하였습니다.\r\n환경설정에서 시스템ID를 확인하세요.\r\n프로그램을 종료합니다.",
                                    L"프로그램 통신오류_3", MB_OK|MB_ICONERROR|MB_APPLMODAL);
        }
        else
        {
            Application->MessageBox(L"Failed to initialize communication process.\r\nPlease check your system ID in preferences.\r\nExit the program.",
                                    L"Program communication error_3", MB_OK|MB_ICONERROR|MB_APPLMODAL);
        }
        g_AppCfg.bAppClose = true;
        Close();
        return;
    }

    UpdateInterCommStatus(true);

	Application->ProcessMessages();

#if 0
    if (g_AppCfg.AutoLogout.LogoutExit)
    {
        Application->MessageBox(L"이전 프로그램은 자동로그아웃으로 종료되었습니다.\r\n프로그램을 실행합니다.",
                                L"프로그램 실행정보", MB_OK|MB_ICONQUESTION|MB_APPLMODAL);
    }
#endif
    g_AppCfg.AutoLogout.LogoutExit = false;

    TmrAppState->Enabled = true;
    TmrPolling->Enabled = true;
    TmrCommTimeout->Enabled = true;

    INT_VMS_STATE_REQ Req;
    memset((char*)&Req, 0x00, sizeof(Req));
    Req.Count = 0;
    Req.Type  = vms_state_all;
    CComm_VmsStateReq(&Req);
}
//---------------------------------------------------------------------------

bool  __fastcall TFrmCctvCtrl::StartJobThread()
{
#if 0
    TThreadPolling *pPollingThread = new TThreadPolling(false);
    if (pPollingThread)
    {
        pPollingThread->OnTerminate = OnPollingThreadDone;
        g_AppCfg.thr.pThread    = (TThread *)pPollingThread;
        g_AppCfg.thr.dwThreadId = pPollingThread->ThreadID;
        g_AppCfg.thr.nHandle    = pPollingThread->Handle;
        //pPollingThread->Resume();
        return true;
    }
#endif
    return false;
}
//---------------------------------------------------------------------------

void  __fastcall TFrmCctvCtrl::TerminateJobThread()
{
#if 0
    if (g_AppCfg.thr.bRunning)
    {
        PostJobMessage(WM_THREAD, WM_QUIT);
    }

    Sleep(500);
    try
    {
        if (g_AppCfg.thr.bRunning)
        {
            TThreadPolling *pThread = (TThreadPolling *)g_AppCfg.thr.pThread;
            pThread->Terminate();
            //pThread->WaitFor();
        }
        g_AppCfg.thr.pThread    = NULL;
        g_AppCfg.thr.dwThreadId = 0;
        g_AppCfg.thr.nHandle    = 0;
        g_AppCfg.thr.bRunning   = false;
    }
    catch(...)
    {
    }
#endif
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::FormClose(TObject *Sender, TCloseAction &Action)
{
    CommClose();
    Action = caFree;
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::CommClose()
{
    try
    {
        CComm_Close();
        ITSSkin_Term();
        CMM_SaveForm(g_sFormsDir, this);
        ::CoUninitialize();
    }
    catch(...)
    {
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::TmrAppStateTimer(TObject *Sender)
{
    /*
    *  타이머가 1초간격으로 응용프로그램의 상태를 체크하고
    * 응용프로그램의 상태를 주기적으로 체크하여 필요한 조치를 수행한다.
    */
	if (g_AppCfg.bAppClose)
    {
        TmrAppState->Enabled = false;
        TmrPolling->Enabled = false;

        UserLogout(); // 로그아웃

        TerminateJobThread();

        ITSDb_Close();
        Close();                // 응용프로그램 종료
    }
    else
    {
        TmrAppState->Enabled = false;
        TmrAppState->Enabled = true;
	}
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::UpdateInterCommStatus(bool AOk)
{
    int nImgIdx = 8;
    if (AOk == false) nImgIdx = 7;
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::UpdateCctvCommStatus(bool ADb)
{
    if (ADb)
    {
        FOR_STL(TItsProcess*, pPrcs, ItsProcessManager->FLists)
        {
            if (pPrcs->SYST_TYPE == "VMS")
            {
                if (pPrcs->FCommStatus == "1")
                {
                    FCctvServerState = cctv_normal;
                }
                else
                {
                    FCctvServerState = cctv_error;
                }
                break;
            }
        }
    }

    int nImgIdx = 8;
    if (FCctvServerState == cctv_error) nImgIdx = 7;
}
//---------------------------------------------------------------------------

bool __fastcall TFrmCctvCtrl::GetUserMenuRight(String AUserId, String AUserRight)
{
#if 0
    String sQry;
    TADOQuery *pADO = NULL;
    try
    {
        sQry = "SELECT OPERSYST_MENU_ID                  \r\n"
               "  FROM TB_USER_GROP_MENU_ATHR            \r\n"
               " WHERE ATHR_YN = 'N'                     \r\n"
               "   AND GROP_ID = (SELECT GROP_ID         \r\n"
               "                    FROM TB_USER_INFR    \r\n"
               "                   WHERE USER_ID = :p01) \r\n";

        try
        {
            pADO = new TADOQuery(NULL);
			pADO->Close();
            pADO->Connection = ITSDb_GetConnection();

            ITSDb_SQLText(pADO, sQry);
            ITSDb_SQLBind(pADO, "p01", AUserId);
            ITSDb_SQLOpen(pADO);

            for( ; !pADO->Eof; pADO->Next())
            {
                String sMenuId = pADO->FieldByName("OPERSYST_MENU_ID")->AsString;

                try
                {
                    int nCompnentCnt = this->ComponentCount;
                    for (int ii = 0; ii < nCompnentCnt; ii++)
                    {
                        String sClassName = this->Components[ii]->ClassName();
                        if(sClassName == "TdxBarLargeButton")
                        {
                            TdxBarLargeButton *pMenu = (TdxBarLargeButton *)this->Components[ii];
                            if (pMenu->Name == sMenuId)
                            {
                                pMenu->Enabled = false;
                                break;
                            }
                        }
                    }
                }
                catch(...)
                {
                }
            }
        }
        catch(EDatabaseError &E)
        {
            DBERRORLOG("TFrmCctvCtrl::GetUserMenuRight", String(E.ClassName()), E.Message, sQry);
            throw Exception(String(E.ClassName()) + E.Message);
        }
        catch(Exception &e)
        {
            DBERRORLOG("TFrmCctvCtrl::GetUserMenuRight", String(e.ClassName()), e.Message, sQry);
            throw Exception(String(e.ClassName()) + e.Message);
        }
	}
	__finally
	{
        if (pADO)
        {
            pADO->Close();
            delete pADO;
        }
	}
#endif
    return true;
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::TmrPollingTimer(TObject *Sender)
{
    TmrPolling->Enabled = false;

    DWORD dwTick = GetTickCount();

    if (!g_AppCfg.bAppClose) TmrPolling->Enabled = true;
}
//---------------------------------------------------------------------------

/*
 * 작업스레드로 작업 메시지를 전송한다.
 *  arguments
 *
 *  return
 *      void
 */
bool  __fastcall TFrmCctvCtrl::PostJobMessage(UINT nMsg, int WParam/*=0*/, int LParam/*=0*/)
{
    int nRes;
    
//if (g_AppCfg.bDebug) ITSUtil_Trace("PostJobMessage: Msg: %02X, WParam: %02X, LParam: %02X", nMsg, WParam, LParam);

    if (g_AppCfg.thr.dwThreadId)
    {
        for (int ii = 0; ii < 3; ii++)
        {
            if (PostThreadMessageW(g_AppCfg.thr.dwThreadId, nMsg, WParam, LParam))
            {
                nRes = 0;
                return true;
            }
            else
            {
                nRes = GetLastError();
                if (ERROR_INVALID_THREAD_ID == nRes) 
                {
                    Sleep(500);
                    continue;
                }
            }
        }
    }
    return false;
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::SetColorScheme(String ASkinName)
{
    dxSkinController1->SkinName = ASkinName;
    dxSkinController1->Refresh();
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::TermItsProgram(String AClassName, String AExeName)
{
	HWND hExeForm = FindWindow(AClassName.c_str(), NULL);
	if (hExeForm)
	{
        POST_MSG(hExeForm, WM_CLOSE, 0, 0);
	}
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::OnAppHint(TObject *Sender)
{
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::OnAppException(TObject *Sender, Exception *exception)
{
if (g_AppCfg.bDebug) ITSUtil_Trace("OnAppException");

    String sClassName = (NULL != Sender)        ? Sender->ClassName() : String("Unknown_Class");
    String sErrMsg    = (NULL != exception)     ? exception->Message  : String("Unknown_Error");
    String sError     = sClassName + " : " + sErrMsg;

    //Application->ShowException(&exception);

    Application->NormalizeTopMosts();
    Application->MessageBox(sError.c_str(), L"System Error", MB_OK|MB_ICONERROR|MB_APPLMODAL);
    Application->RestoreTopMosts();
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::ApplicationEvents1Message(tagMSG &Msg, bool &Handled)
{
    switch(Msg.message)
    {
    case WM_THREAD:
        switch(Msg.wParam)
        {
        case WP_PING:
            break;
        case WP_PARAM_TRAFFIC:
            break;
        case WP_DB_SELECT_START:
            break;
        case WP_DB_SELECT_OK:
        case WP_DB_SELECT_ERROR:
        case WP_DB_SELECT_CANCEL:
            if (Msg.wParam == WP_DB_SELECT_OK)
            {
                OnRefreshMessage(Msg.wParam, Msg.lParam);
            }
            break;
        }
        break;
    case WM_DATABASE_REFRESH:
        OnDatabaseMessage(Msg.wParam, Msg.lParam);
        break;
    case WM_PLUGINFORM:
        OnRefreshMessage(Msg.wParam, Msg.lParam);
        break;
    case WM_MOUSEMOVE:
    case WM_KEYDOWN:
    case WM_KEYUP:
        break;
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::OnRefreshMessage(WPARAM AWParam, LPARAM ALParam)
{
#if 0
    HWND hWnd;

    if (AWParam == WP_DB_SELECT_OK)
    {
        DWORD dwTick = GetTickCount();
#if 0
        switch(ALParam)
        {
        case LP_MSG_00: DebugMsg("<<< Process Status Request Completed."/*"<<< 프로세스 상태 조회 완료"*/);       FPollPrcsState.Polling = dwTick; break;
        case LP_MSG_01: DebugMsg("<<< VMS Status Request Completed."/*"<<< VMS 상태 조회 완료"*/);                FPollVmsState.Polling  = dwTick; break;
        case LP_MSG_02: DebugMsg("<<< VMS Display Message Request Completed."/*"<<< VMS 표출메시지 조회 완료"*/); FPollVmsMsg.Polling    = dwTick; break;
        case LP_MSG_03: DebugMsg("<<< Traffic Request Completed."/*"<<< 소통정보 조회 완료"*/);                   FPollTraffic.Polling   = dwTick; break;
        case LP_MSG_05: DebugMsg("<<< Incident Request Completed."/*"<<< 돌발정보 조회 완료"*/);                  FPollIncident.Polling  = dwTick; break;
        }
#endif

        if (ALParam == LP_MSG_00)
        {
            UpdateCctvCommStatus(true);
        }
        else
        if (ALParam == LP_MSG_02)
        {
            //RefreshVmsMessage(WM_VMS_FORM_REFRESH);
        }
        else
        if (ALParam == LP_MSG_05)
        {
            //RefreshVmsMessage(WM_VMS_INCIDENT_REFRESH);
        }
        else
        {
            //RefreshVmsMessage(WM_VMS_STATE_REFRESH);
        }
    }
    else
    {
        LOGERROR("DB Thread failed: %02X[%02X]", ALParam, AWParam);
    }
#endif
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::OnDatabaseMessage(WPARAM AWParam, LPARAM ALParam)
{
}
//---------------------------------------------------------------------------

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

    LOGINFO("*** OPR Client Req: %s.%d", CComm_ulong2ip(Sender->IP), Sender->Port);

    String sMsg     = "";
    String sVmsNmbr = "";

    TmrCommTimeout->Enabled = false;

    //FCctvServerState = cctv_normal;

    UpdateCctvCommStatus(false);
    UpdateInterCommStatus(true);

    if (head->OPCode == INT_OP_COMM_COMMON)
    {
        switch(OpCode)
        {
        case INT_OP_PG_STATE_RES:
            {
                //DebugMsg("*** VMS Process Stauts Recvieved");//"*** VMS 프로세스 상태정보 수신");
                INT_PG_STATE_RES *ARes = (INT_PG_STATE_RES*)pData;
                for (int ii = 0; ii < ARes->Count && ii < INT_MAX_PG_STATE; ii++)
                {
                    if (ARes->Unit[ii].Type == INT_ID_VMS_SERVER)
                    {
                        FCctvServerState = ARes->Unit[ii].Action;
                        UpdateCctvCommStatus(false);
                        FPollPrcsState.Polling = GetTickCount();  //프로세스상태정보 조회 타이머 리셋
                        break;
                    }
                }
            }
            break;
        case INT_OP_VMS_PARAM_RES:
            {
                INT_VMS_PARAM_RES *ARes = (INT_VMS_PARAM_RES*)pData;

                sMsg = "";
                sMsg.printf(L"*** VMS Controller Parameter Received: %d EA", ARes->Count);
                //DebugMsg(sMsg);

                for (int ii = 0; ii < ARes->Count && ii < INT_MAX_VMS_PARAM; ii++)
                {
                    INT_VMS_PARAM *pVms = &ARes->Unit[ii];
                    TVmsCtlr *pObj = VmsManager->FLists.Find(String(pVms->VMS_CTLR_NMBR));
                    if (pObj)
                    {
                        pObj->PANL_PWER_MODE = pVms->led;     //	N	NUMBER(3)	Y	2		전광판 전원 모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
                        pObj->FAN_MODE       = pVms->fan;           //	N	NUMBER(3)	Y	2		FAN 동작모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
                        pObj->FAN_RUN_TMPR   = pVms->fanTmpr;       //	N	NUMBER(3)	Y	30		팬 동작 온도
                        pObj->HETR_MODE      = pVms->hetr;          //	N	NUMBER(3)	Y	2		히터 동작모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
                        pObj->HETR_RUN_TMPR  = pVms->hetrTmpr;      //	N	NUMBER(3)	Y	0		히터 동작 온도
                        pObj->BRGH_MODE      = pVms->brgh;          //	N	NUMBER(3)	Y	2		휘도 모드(0x00:주간,0x01:야간,0x00:자동,0x09:알수없음)
                        pObj->BRGH_CURR_STEP = pVms->brghVal;     //	N	NUMBER(3)	Y	40		휘도 현재 단계(0~100)
                        pObj->BRGH_WEEK_STEP = pVms->brghDay;     //	N	NUMBER(3)	Y	64		휘도 주간 단계(0~100)
                        pObj->BRGH_NGHT_STEP = pVms->brghNight;     //	N	NUMBER(3)	Y	48		휘도 야간 단계(0~100)
                        pObj->ParamResTime.printf(L"%s", pVms->time);
                    }
                    else
                    {
                        sMsg.printf(L"INT_OP_VMS_PARAM_RES VMS not found: %s", String(pVms->VMS_CTLR_NMBR).c_str());
                        //DebugMsg(sMsg);
                    }
                }
            }
            break;
        case INT_OP_VMS_STATE_RES:
            {
                char szVmsNmbr[INT_VMS_MAX_ID+1];
                INT_VMS_STATE_RES *ARes = (INT_VMS_STATE_RES*)pData;

                sMsg = "";
                //sMsg.printf(L"*** VMS 제어기 상태정보 수신: %d EA", ARes->Count);
                sMsg.printf(L"*** VMS Controller Status Received: %d EA", ARes->Count);
                //DebugMsg(sMsg);

                for (int ii = 0; ii < ARes->Count && ii < INT_MAX_VMS_STATE; ii++)
                {
                    sMsg = "";
                    INT_VMS_STATE *pVms = &ARes->Unit[ii];
                    sVmsNmbr = String(pVms->VMS_CTLR_NMBR);
                    TVmsCtlr *pObj = VmsManager->FLists.Find(sVmsNmbr);
                    if (pObj)
                    {
                        VmsStatusCopy(&pObj->WSTATE, pVms);
                        if      (pObj->WSTATE.OprMode == 'A') pObj->OPER_MODE = "A";
                        else if (pObj->WSTATE.OprMode == 'B') pObj->OPER_MODE = "B";
                        else                                  pObj->OPER_MODE = "F";

                        //pObj->VMS_PHSE_CHNG_CYCL    = pObj->WSTATE.ScheduledMessageOperatingTime;
#if 0
                        pObj->VMS_CMNC_ERR_BASS_VAL = pObj->WSTATE.ModuleOperatingTemperature;
                        pObj->FAN_MTNS_TMPR         = pObj->WSTATE.FanOperatingTemperature;
                        pObj->HETR_MTNS_TMPR        = pObj->WSTATE.HeaterOperatingTemperature;
                        pObj->VMS_MODL_ERR_RATE     = pObj->WSTATE.ModuleBasicFailureRate;

                        pObj->CheckRunState();
#endif

                        if (pObj->WSTATE.Comm != vms_normal)
                        {
                            pObj->VmsMsg->OFFER_YN = false;
                        }
                    }
                    else
                    {
                        sMsg.printf(L"INT_OP_VMS_STATE_RES VMS not found: %s", sVmsNmbr.c_str());
                        //DebugMsg(sMsg);
                    }
                }
                //RefreshVmsMessage(WM_VMS_STATE_REFRESH);

                FPollVmsState.Polling = GetTickCount();
            }
            break;
        case INT_OP_VMS_FORM_SAVE:
            {
                FPollVmsMsg.Reset();    //VMS메시지 조회 타이머 리셋

                char szDateTime[INT_VMS_MAX_DATETIME+1];
                INT_VMS_FORM_SAVE_REQ *AReq = (INT_VMS_FORM_SAVE_REQ*)pData;

                sprintf(szDateTime, "%.*s", INT_VMS_MAX_DATETIME, (char*)AReq->Date);

                String sDateTime = String(szDateTime);

                sMsg = "";
                //sMsg.printf(L"*** VMS 폼생성 완료 메시지 수신: %s", sDateTime.c_str());
                sMsg.printf(L"*** VMS Form Create Message Received: %s", sDateTime.c_str());
                //DebugMsg(sMsg);
            }
            break;
        case INT_OP_VMS_FORM_DOWNLOAD:
            {
                char szDateTime[INT_VMS_MAX_DATETIME+1];
                char szVmsNmbr[INT_VMS_MAX_ID+1];
                INT_VMS_FORM_DOWNLOAD_REQ *AReq = (INT_VMS_FORM_DOWNLOAD_REQ*)pData;

                //sMsg.printf(L"*** VMS 폼 다운로드 메시지 수신: %d EA", AReq->Count);
                sMsg.printf(L"*** VMS Form Download Recieved: %d EA", AReq->Count);
                //DebugMsg(sMsg);

                for (int ii = 0; ii < AReq->Count && ii < INT_MAX_VMS_FORM_DOWNLOAD; ii++)
                {
                    sMsg = "";

                    INT_VMS_FORM_DOWNLOAD *pVms = &AReq->Unit[ii];
                    sprintf(szVmsNmbr, "%.*s", INT_VMS_MAX_ID, (char*)pVms->VmsId);
                    sprintf(szDateTime, "%.*s", INT_VMS_MAX_DATETIME, (char*)pVms->Date);

                    sVmsNmbr = String(szVmsNmbr);
                    String sDateTime = String(szDateTime);

                    TVmsCtlr *pObj = VmsManager->FLists.Find(sVmsNmbr);
                    if (pObj)
                    {
                        bool bDnLd = (pVms->Result == vms_download_succ) ? true : false;
                        String sResult = bDnLd ? "Succ" : "Fail";

                        pObj->VmsMsg->OFFER_DT = sDateTime;
                        pObj->VmsMsg->OFFER_YN = bDnLd;

                        for (int kk = 0; kk < pObj->VmsMsg->Total && kk < INT_MAX_VMS_FORM; kk++)
                        {
                            pObj->VmsMsg->PHASE[kk].DNLD_YN = bDnLd ? "Y" : "N";
                        }

                        //sMsg.printf(L"*** ===> VMS Msg download: %s, %s", pObj->VMS_CTLR_ID.c_str(), sResult.c_str());
                        //DebugMsg(sMsg);
                    }
                    else
                    {
                        sMsg.printf(L"*** INT_OP_VMS_FORM_DOWNLOAD VMS not found: %s", sVmsNmbr.c_str());
                        //DebugMsg(sMsg);
                    }
                }
                //RefreshVmsMessage(WM_VMS_STATE_REFRESH);
                //RefreshVmsMessage(WM_VMS_FORM_REFRESH);
            }
            break;
        }
    }
    TmrCommTimeout->Enabled = true;
#endif
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::RefreshCctvMessage(int AMsg, WPARAM AWParam/*=0*/, LPARAM ALParam/*=0*/)
{
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::OnPollingThreadDone(TObject *Sender)
{
    LOGINFO("*** Polling thead terminated ***");
    g_AppCfg.thr.bRunning = false;
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::TmrCommTimeoutTimer(TObject *Sender)
{
    //통신타임아웃
    TmrCommTimeout->Enabled = false;
    UpdateInterCommStatus(false);
    FCctvServerState = cctv_error;
    UpdateCctvCommStatus(false);
    LOGINFO("xxx CCTV Communication Time out xxx");
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::ApplicationEvents1Restore(TObject *Sender)
{
    //화면 재생
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::ApplicationEvents1Minimize(TObject *Sender)
{
    //화면 정지
}
//---------------------------------------------------------------------------


void __fastcall TFrmCctvCtrl::ApplicationEvents1SettingChange(TObject *Sender, int Flag,
          const UnicodeString Section, int &Result)
{
    DateSeparator = '-';
    TimeSeparator = ':';
    ShortDateFormat = "yyyy-MM-dd";
    ShortTimeFormat = "HH:NN:SS";
    LongTimeFormat  = "HH:NN:SS";

    cxFormatController()->BeginUpdate();
    cxFormatController()->UseDelphiDateTimeFormats = true;
    cxFormatController()->EndUpdate();
    cxFormatController()->GetFormats();
    cxFormatController()->NotifyListeners();
}
//---------------------------------------------------------------------------


void __fastcall TFrmCctvCtrl::BtnCloseClick(TObject *Sender)
{
    Close();
}
//---------------------------------------------------------------------------

