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

#include <vcl.h>
#pragma hdrstop

#include "FrmCctvCtrlF.h"
#include "TVS.h"
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
#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 "TVSLib_OCX"
#pragma link "cxDropDownEdit"
#pragma resource "*.dfm"

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

__fastcall TFrmCctvCtrl::TFrmCctvCtrl(TComponent* Owner)
    : TForm(Owner)//TdxCustomRibbonForm(Owner)//TForm(Owner)
{
    //DoubleBuffered = true;
    Application->OnException = OnAppException;

    reMsg->Lines->Clear();

    m_lCurChID = 0;

    ::CoInitialize(NULL);
}
//---------------------------------------------------------------------------

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"); }

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

void __fastcall TFrmCctvCtrl::reMsgDblClick(TObject *Sender)
{
    reMsg->Lines->Clear();
}
//---------------------------------------------------------------------------

#include <Registry.hpp>
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;
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::FormShow(TObject *Sender)
{
    Refresh();
    Application->ProcessMessages();

	VARIANT var;
	VariantInit(&var);
	var.vt = VT_I4;
	var.lVal = 1;// / MAX_INSTANCE;

	TVSLiveControl1->set_LocalConfig(TN_LCI_MAX_DISPLAY_CHANNEL, var);

	var = TVSLiveControl1->get_LocalConfig(TN_LCI_OSD_MODE);
	var.lVal = TN_OSD_MODE_D3D;//GDI
	TVSLiveControl1->set_LocalConfig(TN_LCI_OSD_MODE, var);

	var = TVSLiveControl1->get_LocalConfig(TN_LCI_MAX_DISPLAY_CHANNEL);

    m_pDisp = TVSLiveControl1->GetDisplay();
    m_pDisp->set_LayoutMode(0, TN_LM_4X4);
    //VARIANT var;
    var.vt = VT_I4;
    var.lVal = 4;
    //m_dlgVideo[m_nLastSelInst].m_tvsLive.SetLocalConfig(TN_LCI_BUFFER_FRAMES, var);
    TVSLiveControl1->set_LocalConfig(TN_LCI_BUFFER_FRAMES, var);
    TVSLiveControl1->set_LocalConfig(TN_LCI_DISPLAY_GRID_ON, var);
    TVSLiveControl1->set_LocalConfig(TN_LCI_DISPLAY_GRID_COLOR, var);
    TVSLiveControl1->set_LocalConfig(TN_LCI_DISPLAY_GRID_WIDTH, var);

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

void __fastcall TFrmCctvCtrl::TmrOnShowTimer(TObject *Sender)
{
    Refresh();
	TmrOnShow->Enabled = false;
	Application->ProcessMessages();
}
//---------------------------------------------------------------------------

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

void __fastcall TFrmCctvCtrl::CommClose()
{
    try
    {
        Disconnect();
        ::CoUninitialize();
    }
    catch(...)
    {
    }
}
//---------------------------------------------------------------------------

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

void __fastcall TFrmCctvCtrl::OnAppException(TObject *Sender, Exception *exception)
{
    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::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();
}
//---------------------------------------------------------------------------

bool __fastcall TFrmCctvCtrl::Connect()
{
    if (m_lCurChID <= 0)
    {
        int  nProtocol = 0;
        bool bHD = false;       // High Definition
        bool bAudio = false;

        String sAddress = "";
        String sAudio = "";
        String sVideo = "";
        String sStream = "";

        m_IpAddr = EdIp->Text.Trim();
        m_Port = EdPort->Text.Trim();
        m_nChannel = CbChannel->ItemIndex + 1;
        m_nStream = CbStream->ItemIndex;
        m_UserId = EdUserId->Text.Trim();
        m_UserPswd = EdUserPswd->Text.Trim();

        if (bAudio) sAudio = "+audio" + String(m_nChannel);
        sStream = (m_nStream == 1) ? "s" : "";  // secondary == s, primary == null
        sVideo = "video" + String(m_nChannel) + sStream;

        //"vsnm://210.99.141.193:2323/video1s+audio1";
        if (nProtocol == 0)         // tcp
            sAddress = "vsnm://" + m_IpAddr + ":" + m_Port + "//" + sVideo + sAudio;
        else if (nProtocol == 1)    // multicate
            sAddress = "vsnm-multicast://" + m_IpAddr + ":" + m_Port + "//" + sVideo + sAudio;
        else                        // udp
            sAddress = "vsnm-udp://" + m_IpAddr + ":" + m_Port + "//" + sVideo + sAudio;

        VARIANT var;
        VariantInit(&var);

        var.vt = VT_I4;
		var.lVal = bHD ? 1 : 0;
        TVSLiveControl1->set_LocalConfig(TN_LCI_MAX_HD_CHANNEL, var);

        m_lCurChID = TVSLiveControl1->Connect(sAddress.c_str(), m_UserId.c_str(), m_UserPswd.c_str());
        if (m_lCurChID <= 0)
        {
            reMsg->Lines->Add("Connection error(" + String(m_lCurChID) + ")");
            return false;
        }

        m_pDisp->set_MapChannel(0, 0, m_lCurChID);

        VARIANT_BOOL vb;
        vb = true;
        TVSLiveControl1->set_AutoReconnect(m_lCurChID, vb);
        TVSLiveControl1->set_VideoOn(m_lCurChID, true);
        TVSLiveControl1->Play(m_lCurChID);
        //TVSLiveControl1->Pause(m_lCurChID);

        m_pDisp->set_ShowToolbar(1, 0);
        m_pDisp->set_OsdBackColor(0, 0);

        PnlCamConrtol->Enabled = true;

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

void __fastcall TFrmCctvCtrl::Disconnect()
{
	if (m_lCurChID > 0)
	{
		if (TVSLiveControl1->get_ChannelState(m_lCurChID) & TN_CS_CONNECTED)
		{
			TVSLiveControl1->Disconnect(m_lCurChID);
		}
        m_lCurChID = 0;

        BtnCamera->Caption = "영상 연결";
        BtnCamera->Tag = 0;
	}
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::TVSLiveControl1ChannelNotify(TObject *Sender, long lChID, long eNewState, long eReason)
{
	if (eNewState & TN_CS_CONNECTED)
	{
		reMsg->Lines->Add("ChannelNotify(TN_CS_CONNECTED)");
	}
	else
	{
		if (eReason < 10)
		{
            reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:reason=" + String(eReason));
		}
		else
		{
			switch (eReason)
			{
			case TN_SNC_CN_SERVER_UNREACHABLE:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Server is unreachable for connection)");
				//m_pdlgMain->Pause();
				break;
			case TN_SNC_CN_TOO_MANY_CONNECTION:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Too many connections on the server)");
				break;
			case TN_SNC_CN_PASSWORD_MISMATCH:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Password is incorrect)");
				break;
			case TN_SNC_CN_CONNECTION_DISABLED:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Server disabled the connection)");
				break;
			case TN_SNC_CN_ID_NOT_EXIST:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Login ID doesn't exist)");
				break;
			case TN_SNC_CN_DOMAINNAME_UNKNOWN:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Can't resolve the domain name)");
				break;
/*			case TN_SNC_CN_PARAMETER_OUTOFRANGE:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Invalid channels is one of this case)");
				break;
*/			case TN_SNC_CN_DUPLICATE_CONNECT:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Multiple connections to a channel are not allowed)");
				break;
			case TN_SNC_CN_KEEPALIVE_FAILED:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:Disconnected due to keep alive timeout)");
				//m_pdlgMain->Pause();
				break;
			case TN_SNC_CN_NO_AUTHORITY_OPERATION:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:No authority operation)");
				break;
			case TN_SNC_CN_OPERATION_FAILED:
				reMsg->Lines->Add("ChannelNotify(NOT CONNECTED:General failure)");
				break;
			}

			Disconnect();
		}

	}

	if (eNewState & TN_CS_STREAMED)
	{
		reMsg->Lines->Add("ChannelNotify(TN_CS_STREAMED)");
	}

	if (eNewState & TN_CS_DECODED)
	{
		reMsg->Lines->Add("ChannelNotify(TN_CS_DECODED)");
	}

	if (eNewState & TN_CS_DISPLAYED)
	{
		reMsg->Lines->Add("ChannelNotify(TN_CS_DISPLAYED)");
	}

	if (eNewState & TN_CS_RECORDED)
	{
		reMsg->Lines->Add("ChannelNotify(TN_CS_RECORDED)");
	}
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::TVSLiveControl1ServerEvent(TObject *Sender, long lChID, long eEventType, short nIndex, long eEventStatus,
          Variant vData)
{
	switch (eEventType)
	{
		case TN_ET_DI:
			reMsg->Lines->Add("ServerEvent([%" + String(nIndex) + "] TN_ET_DI=" + String(eEventStatus) + ")");
			break;
		case TN_ET_VIDEOLOSS:
			reMsg->Lines->Add("ServerEvent([%" + String(nIndex) + "] TN_ET_VIDEOLOSS=" + String(eEventStatus) + ")");
			break;
		case TN_ET_MOTION:
			//reMsg->Lines->Add("ServerEvent([%" + String(nIndex) + "] TN_ET_MOTION=" + String(eEventStatus) + ")");
			break;
		case TN_ET_TIMECHANGED:
			reMsg->Lines->Add("ServerEvent([%" + String(nIndex) + "] TN_ET_TIMECHANGED=" + String(eEventStatus) + ")");
			break;
		case TN_ET_DO:
			reMsg->Lines->Add("ServerEvent([%" + String(nIndex) + "] TN_ET_DO=" + String(eEventStatus) + ")");
			break;
		case TN_ET_RECORD:
			reMsg->Lines->Add("ServerEvent([%" + String(nIndex) + "] TN_ET_RECORD=" + String(eEventStatus) + ")");
			break;
        case TN_ET_RESOLUTIONCHANGED:
			reMsg->Lines->Add("ServerEvent([%" + String(nIndex) + "] TN_ET_RESOLUTIONCHANGED=" + String(eEventStatus) + ")");
            break;
		default:
			reMsg->Lines->Add("ServerEvent(unknown)");
            break;
	 }
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::BtnCameraClick(TObject *Sender)
{
    if (BtnCamera->Tag == 0)
    {
        if (Connect())
        {
            BtnCamera->Caption = "영상 연결 해제";
            BtnCamera->Tag = 1;
        }
    }
    else
    {
        Disconnect();
    }
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::BtnPTZMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
    TImageBtn *pBtn = (TImageBtn*)Sender;

    long lPTZSpeed = PTZSpeed->Position;

    try
    {
        //nType Type of control. 0: PAN, 1: TILT, 2: ZOOM
        switch(pBtn->Tag)
        {
        //case  0: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_HOME); break;  // HOME
        case  1:  // Tilt Up
        case  2:  // Tilt Down
            TVSLiveControl1->SetPTZControlSpeed(m_lCurChID, 1, lPTZSpeed);
            break;
        case  3:  // Pan left
        case  4:  // Pan right
            TVSLiveControl1->SetPTZControlSpeed(m_lCurChID, 0, lPTZSpeed);
            break;
        case  9:  // Zoom In
        case 10:  // Zoom Out
            TVSLiveControl1->SetPTZControlSpeed(m_lCurChID, 2, lPTZSpeed);
            break;
        case 12:  // Focus In
        case 13:  // Focus Out
            break;
        default: return;
        }


        switch(pBtn->Tag)
        {
        case  0: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_HOME); break;  // HOME
        case  1: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_UP); break;  // Tilt Up
        case  2: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_DOWN); break;  // Tilt Down
        case  3: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_LEFT); break;  // Pan left
        case  4: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_RIGHT); break;  // Pan right
        case  9: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_ZOOMIN); break;  // Zoom In
        case 10: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_ZOOMOUT); break;  // Zoom Out
        case 12: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_FOCUSNEAR); break;  // Focus In
        case 13: TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_FOCUSFAR); break;  // Focus Out
        default: return;
        }
    }
    catch(...) {}
}
//---------------------------------------------------------------------------

void __fastcall TFrmCctvCtrl::BtnPTZMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
    TImageBtn *pBtn = (TImageBtn*)Sender;

    String sPTZSpeed = String(PTZSpeed->Position);
    TVSLiveControl1->SendPTZCommand(m_lCurChID, TN_PTZ_STOP);

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

