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

#include <vcl.h>
#include "ITSSkinF.h"
#include "ITSUtilF.h"
#include "AppGlobalF.h"
#include "CommFlashF.h"
#pragma hdrstop

#include "BDS0000MF.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "cxButtons"
#pragma link "cxContainer"
#pragma link "cxControls"
#pragma link "cxEdit"
#pragma link "cxGraphics"
#pragma link "cxGroupBox"
#pragma link "cxLookAndFeelPainters"
#pragma link "cxLookAndFeels"
#pragma link "dxSkinBlack"
#pragma link "dxSkinBlue"
#pragma link "dxSkinCaramel"
#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 "dxSkinSeven"
#pragma link "dxSkinSharp"
#pragma link "dxSkinSilver"
#pragma link "dxSkinStardust"
#pragma link "FRAME_NodeListF"
#pragma link "cxLabel"
#pragma link "cxTextEdit"
#pragma link "cxProgressBar"
#pragma link "IdAntiFreeze"
#pragma link "IdAntiFreezeBase"
#pragma link "IdBaseComponent"
#pragma link "IdComponent"
#pragma link "IdExplicitTLSClientServerBase"
#pragma link "IdFTP"
#pragma link "IdTCPClient"
#pragma link "IdTCPConnection"
#pragma link "AXVLC_TLB"
#pragma link "ShockwaveEx"
#pragma link "ShockwaveFlashObjects_TLB"
#pragma resource "*.dfm"

TBDS0000M *BDS0000M = NULL;
//---------------------------------------------------------------------------
__fastcall TBDS0000M::TBDS0000M(TComponent* Owner)
    : TForm(Owner)
{
    ITSSkin_Load(this);
    CMM_LoadForm(g_sFormsDir, this);

    DoubleBuffered = false;

    MapInit    = false;
    MapStart   = false;
    ShockwaveFlash1->Align = alClient;

    InitControl();
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::InitControl()
{
    FDownloadDir  = "";
    FDownloadFile = "";
    FAviFile      = "";

    LblCam[0] = lblCam1;
    LblCam[1] = lblCam2;
    LblCam[2] = lblCam3;
    PnlCam[0] = Panel1;
    PnlCam[1] = Panel2;
    PnlCam[2] = Panel3;

    PlayerFile[0] = "";
    PlayerFile[1] = "";
    PlayerFile[2] = "";

    VlcPlayer[0] = VLCPlugin21;
    VlcPlayer[1] = VLCPlugin22;
    VlcPlayer[2] = VLCPlugin23;

    for (int ii = 0; ii < MAX_PLAYER; ii++)
    {
        LblCam[ii]->Caption = "";
        LblCam[ii]->Visible = false;

        PnlCam[ii]->ParentColor = false;
        PnlCam[ii]->Color = clBlack;
        PnlCam[ii]->Caption = "";
        //PnlCam[ii]->Caption = "영상 " + String(ii+1);

        VlcPlayer[ii]->DoubleBuffered = false;
        VlcPlayer[ii]->Toolbar = false;
        VlcPlayer[ii]->Align = alClient;
        VlcPlayer[ii]->Visible = false;
        //VlcPlayer[ii]->Hide();
        PnlCam[ii]->Refresh();
    }
}
//---------------------------------------------------------------------------

/*
 * 닫기버튼 이나 x버튼 클릭시 공통으로 처리하는 로직이들어간다..
 * Form과 DataModule class를 delete시킨다.
 *  arguments
 *
 *  return
 *      void
 */
void __fastcall TBDS0000M::CommClose()
{
    try
    {
        CMM_SaveForm(g_sFormsDir, this);

        DisconnectFtp();
    }
    catch(...)
    {
    }
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::FormShow(TObject *Sender)
{
    EdFocus->SetFocus();

    eBDS_MNGM_NMBR->Text = BDS_MNGM_NMBR;
    eTRMN_ID->Text = TRMN_ID;
    eIMGN_PATH->Text = IMGN_PATH;
    eOCRR_DT->Text = ITSUtil_StrToDateTime(OCRR_DT).FormatString(STR_DATETIME);

    Refresh();
    TmrShow->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::TmrShowTimer(TObject *Sender)
{
    TmrShow->Enabled = false;

    try {
        ShockwaveFlash1->Stop();
        String sFileName = g_AppCfg.flashmap.sMainMap;
        ShockwaveFlash1->Movie = sFileName;
        ShockwaveFlash1->Play();

        MapInit = true;
    } catch(...) {}

    BtnDownloadClick((TObject*)BtnDownload);
}
//---------------------------------------------------------------------------


void __fastcall TBDS0000M::RefreshData()
{
}
//---------------------------------------------------------------------------

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

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

bool __fastcall TBDS0000M::SplitStream()
{
    bool bRes = false;
    bool bLoop = true;

    try
    {
        STARTUPINFO             StartupInfo;
        PROCESS_INFORMATION     ProcessInfo;
        ULONG                   ret;
        TMsg                    msg;
        SECURITY_ATTRIBUTES     sa;

        sa.bInheritHandle = true;
        sa.lpSecurityDescriptor = NULL;
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);

        String sAppName = g_sAppDir + "\\ffmpeg.exe";

        PlayerFile[0]  = FDownloadDir + FAviFile + "_1.avi";
        PlayerFile[1]  = FDownloadDir + FAviFile + "_2.avi";
        PlayerFile[2]  = FDownloadDir + FAviFile + "_3.avi";

        String sExeName;
        sExeName.printf(L"%s -i %s -map 0:0 -vcodec copy -y %s -map 0:1 -vcodec copy -y %s -map 0:2 -vcodec copy -y %s", sAppName, FDownloadFile, PlayerFile[0], PlayerFile[1], PlayerFile[2]);

        ZeroMemory(&StartupInfo, sizeof(StartupInfo));

        StartupInfo.cb = sizeof(StartupInfo);
        StartupInfo.dwFlags = STARTF_USESHOWWINDOW;//STARTF_USESTDHANDLES;//STARTF_USESHOWWINDOW;
        StartupInfo.wShowWindow = SW_HIDE;
        StartupInfo.hStdInput=NULL;
        StartupInfo.hStdOutput=NULL;
        StartupInfo.hStdError=NULL;

        if (!CreateProcess(
            (LPCTSTR)NULL,
            (LPTSTR)WideString(sExeName).c_bstr(),          // { pointer to command line string }
             &sa,                      // { pointer to process security attributes }
             &sa,                      // { pointer to thread security attributes }
             true,                      // { handle inheritance flag }
             CREATE_NEW_CONSOLE |
             NORMAL_PRIORITY_CLASS,     // { creation flags }
             NULL,                      // { pointer to new environment block }
             NULL,                      // { pointer to current directory name }
             &StartupInfo,              // { pointer to STARTUPINFO }
             &ProcessInfo))             // { pointer to PROCESS_INF }
        {
            return bRes;
        }
        else
        {
            do
            {
                ret = WaitForMultipleObjects(1, (CONST HANDLE*)&ProcessInfo.hProcess, true, 1000);
                if (ret == WAIT_FAILED)
                {
                    bLoop = false;
                    break;
                }
                else
                if (ret == (WAIT_OBJECT_0))
                {
                    bRes = true;
                    bLoop = false;
                    break;
                }
                else
                {
                    //wait timeout
                }
            } while(bLoop);

            try {
                GetExitCodeProcess(ProcessInfo.hProcess, &ret);
                CloseHandle(ProcessInfo.hProcess);
                CloseHandle(ProcessInfo.hThread);
            } catch(...) {}
        }
    }
    catch (Exception &e)
    {
        String sErrMsg;
        sErrMsg = e.Message;
        sErrMsg = StringReplace(sErrMsg, "\r\n", " ", TReplaceFlags() << rfReplaceAll);
        Application->MessageBox(sErrMsg.c_str(), L"블랙박스 서버 연결시도 실패", MB_OK|MB_ICONERROR|MB_APPLMODAL);
    }

    return bRes;
}
//---------------------------------------------------------------------------

bool __fastcall TBDS0000M::DownloadAviFile()
{
    String sErrMsg;
    bool bRes = false;

    FDownloadDir  = "";
    FDownloadFile = "";
    FAviFile      = "";

    if (!ConnectFtp(true, g_AppCfg.blackbox.server, g_AppCfg.blackbox.port, g_AppCfg.blackbox.user, g_AppCfg.blackbox.pswd))
    {
        return bRes;
    }

    if (!ChangeDir(g_AppCfg.blackbox.dir))
    {
        return bRes;
    }

    FDownloadDir = g_sBlackBox;
    FAviFile = ChangeFileExt(ExtractFileName(IMGN_PATH), "");
    FDownloadDir = FDownloadDir + "\\" + BDS_MNGM_NMBR + "\\" + FAviFile + "\\";
    ForceDirectories(FDownloadDir.c_str());

    FDownloadFile = FDownloadDir + IMGN_PATH;

    try
    {
    	IdFtp->Get(IMGN_PATH, FDownloadFile, true, false);
        eIMGN_PATH_RES->Text = FDownloadFile;
        bRes = true;
    }
    catch (EIdSocketError &exSock)
    {
        sErrMsg = exSock.Message;
        sErrMsg = StringReplace(sErrMsg, "\r\n", " ", TReplaceFlags() << rfReplaceAll);
        Application->MessageBox(sErrMsg.c_str(), L"블랙박스 영상 다운로드 실패", MB_OK|MB_ICONERROR|MB_APPLMODAL);
    }
    catch (Exception &e)
    {
        sErrMsg = e.Message;
        sErrMsg = StringReplace(sErrMsg, "\r\n", " ", TReplaceFlags() << rfReplaceAll);
        Application->MessageBox(sErrMsg.c_str(), L"블랙박스 영상 다운로드 실패", MB_OK|MB_ICONERROR|MB_APPLMODAL);
    }

    DisconnectFtp();

    return bRes;
}
//---------------------------------------------------------------------------

bool __fastcall TBDS0000M::ChangeDir(String sDir)
{
    String sErrMsg;
    bool   bRes = false;

    try
    {
        IdFtp->ChangeDir(sDir);
        bRes = true;
    }
    catch (EIdConnClosedGracefully &exClose)
    {
        sErrMsg = exClose.Message;
        sErrMsg = StringReplace(sErrMsg, "\r\n", " ", TReplaceFlags() << rfReplaceAll);
        Application->MessageBox(sErrMsg.c_str(), L"블랙박스 서버 경로변경 실패", MB_OK|MB_ICONERROR|MB_APPLMODAL);
    }
    catch (Exception &e)
    {
        sErrMsg = e.Message;
        sErrMsg = StringReplace(sErrMsg, "\r\n", " ", TReplaceFlags() << rfReplaceAll);
        Application->MessageBox(sErrMsg.c_str(), L"블랙박스 서버 경로변경 실패", MB_OK|MB_ICONERROR|MB_APPLMODAL);
    }

    return bRes;
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::DisconnectFtp()
{
    try
    {
        if (IdFtp->Connected())
        {
            IdFtp->Abort();
            IdFtp->Quit();
            IdFtp->Disconnect();
        }
    }
    catch(Exception &e)
    {
#if 0
        sErrMsg = e.Message;
        sErrMsg = StringReplace(sErrMsg, "\r\n", " ", TReplaceFlags() << rfReplaceAll);
        Application->MessageBox(sErrMsg.c_str(), L"블랙박스 서버 연결해제 실패", MB_OK|MB_ICONERROR|MB_APPLMODAL);
#endif
    }
}
//---------------------------------------------------------------------------

bool __fastcall TBDS0000M::ConnectFtp(bool bPassive, String sHost, int nPort, String sUser, String sPswd)
{
    String sErrMsg;
    bool   bRes = false;

    IdFtp->Host = sHost;
    IdFtp->Port = nPort;
    IdFtp->Username = sUser;
    IdFtp->Password = sPswd;
    IdFtp->Passive = bPassive;

    try
    {
        IdFtp->Connect();
        bRes = true;
    }
    catch (EIdSocketError &exSock)
    {
        sErrMsg = exSock.Message;
        sErrMsg = StringReplace(sErrMsg, "\r\n", " ", TReplaceFlags() << rfReplaceAll);
        Application->MessageBox(sErrMsg.c_str(), L"블랙박스 서버 연결시도 실패", MB_OK|MB_ICONERROR|MB_APPLMODAL);
    }
    catch (Exception &e)
    {
        sErrMsg = e.Message;
        sErrMsg = StringReplace(sErrMsg, "\r\n", " ", TReplaceFlags() << rfReplaceAll);
        Application->MessageBox(sErrMsg.c_str(), L"블랙박스 서버 연결시도 실패", MB_OK|MB_ICONERROR|MB_APPLMODAL);
    }

    return bRes;
}
//---------------------------------------------------------------------------


void __fastcall TBDS0000M::IdFtpStatus(TObject *ASender, const TIdStatus AStatus,
          const UnicodeString AStatusText)
{
    switch(AStatus)
    {
    case hsConnected:
        grpStatus->Caption = "▶ 영상정보 - " + AStatusText;
        //eIMGN_PATH_RES->Visible = false;
        //cxProgress->Visible = true;
        break;
    case hsDisconnected:
        grpStatus->Caption = "▶ 영상정보";
        //cxProgress->Visible = false;
        //eIMGN_PATH_RES->Visible = true;
    default:
        grpStatus->Caption = "▶ 영상정보 - " + AStatusText;
        break;
    }

    grpStatus->Refresh();
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::BtnDownloadClick(TObject *Sender)
{
    BtnDownload->Enabled = false;

    InitControl();

    Application->ProcessMessages();

    if (DownloadAviFile())
    {
        BtnDownload->Visible = false;

        if (SplitStream())
        {
            BtnPlay->Enabled = true;
            BtnStop->Enabled = false;

            BtnPlayClick((TObject*)BtnPlay);
        }
        else
        {
            BtnDownload->Visible = true;
            BtnPlay->Enabled = false;
            BtnStop->Enabled = false;
        }
    }
    else
    {
        BtnDownload->Visible = true;
    }
    BtnDownload->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::BtnPlayClick(TObject *Sender)
{
//    PlayerFile[0] = FDownloadFile;//"D:\\FTP_IMAGE\\20180103_122435_E_M3.avi";
//    PlayerFile[1] = "D:\\FTP_IMAGE\\a.avi";

    BtnPlay->Enabled = false;
    for (int ii = 0; ii < MAX_PLAYER; ii++)
    {
        try
        {
            OleVariant ovar1 = OleVariant("active");
            OleVariant ovar2 = OleVariant(":noaudio");
            //OleVariant ovar2 = OleVariant(":noaudio:crop=1500:500:brightness=2");
            //OleVariant ovar2 = OleVariant(":rtsp-tcp");
            int        res;

            int nPlayLists;
            VlcPlayer[ii]->playlist->Get_itemCount(nPlayLists);
            if (nPlayLists > 0)
            {
                try {
                    if (VlcPlayer[ii]->playlist->isPlaying)
                    {
                        VlcPlayer[ii]->playlist->stop();
                    }
                } catch(...) {}
            }
            VlcPlayer[ii]->playlist->clear();
            VlcPlayer[ii]->AutoPlay = true;

            if (PlayerFile[ii] == "") continue;

            String sUrl = "file:///" + PlayerFile[ii];

            //VlcPlayer[ii]->playlist->add(sUrl, ovar1, ovar2, res);
            VlcPlayer[ii]->playlist->add(sUrl, "", ovar2, res);
            VlcPlayer[ii]->MRL = sUrl;
            VlcPlayer[ii]->playlist->playItem(1);
            VlcPlayer[ii]->playlist->play();
        } catch(...) {}
    }
    BtnStop->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::BtnStopClick(TObject *Sender)
{
    BtnStop->Enabled = false;
    try
    {
        for (int ii = 0; ii < MAX_PLAYER; ii++)
        {
            //if (VlcPlayer[ii]->playlist->isPlaying)
            {
                VlcPlayer[ii]->playlist->stop();
            }
            VlcPlayer[ii]->playlist->clear();
            VlcPlayer[ii]->Visible = false;
            //VlcPlayer[ii]->Hide();

            LblCam[ii]->Caption = "";
            LblCam[ii]->Visible = false;
            LblCam[ii]->Refresh();
            PnlCam[ii]->Refresh();
        }
    } catch(...) {}
    BtnPlay->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::VLCPlugin21MediaPlayerBuffering(TObject *ASender, int cache)
{
    int nTag = dynamic_cast<TComponent *>(ASender)->Tag;
    switch(nTag)
    {
    case 0:
    case 1:
    case 2:
        break;
    default: return;
    }

    if (VlcPlayer[nTag]->Visible == false)
    {
        //VlcPlayer[nTag]->Visible = true;
        //VlcPlayer[nTag]->Hide();
    }
    if (LblCam[nTag]->Visible == false)
    {
        LblCam[nTag]->Visible = true;
    }
    LblCam[nTag]->Caption = "Buffering ...: " + String(cache);
    LblCam[nTag]->Visible = true;
    LblCam[nTag]->Refresh();
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::VLCPlugin21MediaPlayerTimeChanged(TObject *ASender, int Time)
{
    int nTag = dynamic_cast<TComponent *>(ASender)->Tag;
    switch(nTag)
    {
    case 0:
    case 1:
    case 2:
        break;
    default: return;
    }
    if (BtnStop->Enabled && VlcPlayer[nTag]->Visible == false)
    {
        VlcPlayer[nTag]->Visible = true;
        //VlcPlayer[nTag]->Show();
    }
    if (BtnStop->Enabled && LblCam[nTag]->Visible == false)
    {
        LblCam[nTag]->Visible = true;
    }
    LblCam[nTag]->Caption = FormatFloat("##,##0", Time);
    //LblCam[nTag]->Visible = false;
    LblCam[nTag]->Refresh();
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::VLCPlugin21MediaPlayerEncounteredError(TObject *Sender)
{
    int nTag = dynamic_cast<TComponent *>(Sender)->Tag;
    switch(nTag)
    {
    case 0:
    case 1:
    case 2:
        break;
    default: return;
    }

    PnlCam[nTag]->Caption = "";

    if (VlcPlayer[nTag]->Visible == true)
    {
        VlcPlayer[nTag]->Visible = false;
        //VlcPlayer[nTag]->Hide();
        PnlCam[nTag]->Refresh();
    }
    LblCam[nTag]->Caption = "Player Error";
    LblCam[nTag]->Refresh();
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::VLCPlugin21MediaPlayerEndReached(TObject *Sender)
{
    int nTag = dynamic_cast<TComponent *>(Sender)->Tag;
    switch(nTag)
    {
    case 0:
    case 1:
    case 2:
        break;
    default: return;
    }
    LblCam[nTag]->Caption = "End...";
    LblCam[nTag]->Visible = false;
    LblCam[nTag]->Refresh();

    if (nTag == 0)
    {
        BtnStopClick((TObject*)BtnStop);
    }
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::ShockwaveFlash1FlashCall(TObject *ASender, const WideString request)
{
    try
    {
        String sTemp;
        String sFunc;
        String sArgs;

        //<invoke name="Debug" returntype="xml"><arguments><string>KKK|LinkMap 1</string></arguments></invoke>
        sTemp = request;

        int nFuncStrIdx = sTemp.Pos("\"");
        int nFuncEndIdx = sTemp.Pos("\" returntype");
        int nArgsStrIdx = sTemp.Pos("string>");
        int nArgsEndIdx = sTemp.Pos("</string");

        sFunc = sTemp.SubString(nFuncStrIdx + 1, nFuncEndIdx - (nFuncStrIdx + 1));
        sArgs = sTemp.SubString(nArgsStrIdx + 7, nArgsEndIdx - (nArgsStrIdx + 7));

        if (sFunc == "OnMapStart")
        {
            MapStart = true;

            String sFacility = "";
            sFacility += FAC_EVENT;

            TCommFlash::CallFunc(ShockwaveFlash1, "AddFacilityKind", sFacility);

            AddPos();
        }
    }
    catch(Exception &exception)
    {
    }
}
//---------------------------------------------------------------------------

void __fastcall TBDS0000M::AddPos()
{
    String sFacility;
    String sShowIcon;
    String sShowInfo;
    String sObjList = "";
    int nStatus = 1;
    try
    {
        String sTitle = TCommFlash::ReplaceName(TRMN_ID);
        String sInfo = EventID + "$" + sTitle + "$" + EVT_TYPE + "$" + ITSUtil_StrToDateTime(OCRR_DT).FormatString(STR_DATETIME);

        sObjList += (EventID + "," + String(nStatus) + "," + sTitle + "," + X_CRDN + "," + Y_CRDN + "," + sInfo + "|");
    }
    __finally
    {
        sFacility = FAC_EVENT;
        sShowIcon = "1";
        sShowInfo = "0";
        TCommFlash::CallFunc(ShockwaveFlash1, "RemoveFacility", sFacility);
        if (sObjList != "")
        {
            sObjList = sObjList.SubString(1, sObjList.Length()-1);
            TCommFlash::CallFunc(ShockwaveFlash1, "AddFacility", sFacility + "|" + sShowIcon + "|" + sShowInfo + "|" + sObjList);
        }

        TCommFlash::CallFunc(ShockwaveFlash1, "SelectPoint", X_CRDN + "," + Y_CRDN + "|3");
    }
}
//---------------------------------------------------------------------------

