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

#include <vcl.h>
#pragma hdrstop

#include "FrameSamsungXnsActiveXF.h"
#include "XnsCommon.h"
#include "XnsDeviceInterface.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "cxButtons"
#pragma link "cxGraphics"
#pragma link "cxLookAndFeelPainters"
#pragma link "cxLookAndFeels"
#pragma link "dxSkinBlack"
#pragma link "dxSkinMcSkin"
#pragma link "dxSkinsCore"
#pragma link "ImageBtn"
#pragma link "cxContainer"
#pragma link "cxControls"
#pragma link "cxEdit"
#pragma link "cxLabel"
#pragma link "cxTextEdit"
#pragma link "XNSSDKDEVICELib_OCX"
#pragma link "XNSSDKWINDOWLib_OCX"
#pragma link "cxDropDownEdit"
#pragma link "cxMaskEdit"
#pragma resource "*.dfm"
TFrameSamsungXnsActiveX *FrameSamsungXnsActiveX;
//---------------------------------------------------------------------------
__fastcall TFrameSamsungXnsActiveX::TFrameSamsungXnsActiveX(TComponent* Owner)
    : TFrame(Owner)
{
    //::CoInitialize(NULL);
    //::CoUninitialize();
    FStrmPlay = false;

    reMsg->Lines->Clear();
    FStrmHandle = 0;

    PnlCamera->Color = clBlack;
    XnsSdkWindow1->Parent = PnlCamera;
    XnsSdkWindow1->Align  = alClient;
	m_hDevice      = 0;     // Device handle
	m_hMediaSource = 0;     // Media stream ID
	m_nControlId   = 0;     // Control ID
	m_bIsMediaPlay = false;

    SetupWebCamera();
}
//---------------------------------------------------------------------------

bool __fastcall TFrameSamsungXnsActiveX::SetupWebCamera()
{
//// Samsung ip camera activex initialize start
    String sLog;
	long nRet = XnsSdkDevice1->Initialize();
	if (nRet != ERR_SUCCESS && nRet != ERR_ALREADY_INITIALIZE)
	{
		//sLog.printf(L"Samsung XnsSdkDevice Initialize() fail: errno=[%d]", nRet);
    	sLog.printf(L"Samsung XnsSdkDevice Initialize() fail: return=[%d](%s)\n", nRet, XnsSdkDevice1->GetErrorString(nRet));
        ShowMessage(sLog);
        return false;
	}

	nRet = XnsSdkWindow1->Initialize(NULL, NULL);
	if (nRet != ERR_SUCCESS && nRet != ERR_ALREADY_INITIALIZE)
	{
		//sLog.printf(L"Samsung XnsSdkDevice Initialize() fail: errno=[%d]", nRet);
    	sLog.printf(L"Samsung XnsSdkWindow Initialize() fail: return=[%d](%s)\n", nRet, XnsSdkDevice1->GetErrorString(nRet));
        ShowMessage(sLog);
        return false;
	}

	long device_id = XnsSdkDevice1->CreateDeviceEx();
	m_hDevice = XnsSdkDevice1->GetDeviceHandle(device_id);
	if (m_hDevice == 0)
	{
		sLog = "CreateDevice() fail";
    	ShowMessage(sLog);
        return false;
	}
    //EdDeviceId->Text = String(device_id);

#if 1
    WideString sFindModel = "samsung";
	long nFind = XnsSdkDevice1->FindModel(sFindModel.c_bstr());

	long nCount = XnsSdkDevice1->GetFindSize(nFind);
	String sModel;
    CboModel->Properties->Items->Clear();
	for (int ii = 0 ; ii < nCount ; ii++)
	{
		sModel = XnsSdkDevice1->GetFindString(nFind, ii);
        CboModel->Properties->Items->Add(sModel);
	}
	XnsSdkDevice1->CloseFind(nFind);
    CboModel->ItemIndex = 0;
    CboModel->Text = "SNP-3120VH";
#endif

    return true;
//// Samsung ip camera activex initialize end
}
//---------------------------------------------------------------------------

void __fastcall TFrameSamsungXnsActiveX::ReleaseWebCamera()
{
	if (m_hDevice != 0)
    {
		if (m_hMediaSource)
		{
			XnsSdkWindow1->Stop();
			XnsSdkDevice1->CloseMedia(m_hDevice, m_hMediaSource);
		}
		if (XnsSdkDevice1->GetDeviceStatus(m_hDevice) == XDEVICE_STATUS_CONNECTED)
		{
			XnsSdkDevice1->Disconnect(m_hDevice);
		}
    	XnsSdkDevice1->ReleaseDevice(m_hDevice);
    }
}
//---------------------------------------------------------------------------

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

    //PTZ Control
	//	XPTZ_UP			1		Tilt up
	//	XPTZ_DOWN		2		Tilt down
	//	XPTZ_LEFT		3		Pan left
	//	XPTZ_RIGHT		4		Pan right
	//	XPTZ_UPLEFT		5		Tilt up and pan left
	//	XPTZ_UPRIGHT	6		Tilt up and pan right
	//	XPTZ_DOWNLEFT	7		Tilt down and pan left
	//	XPTZ_DOWNRIGHT	8		Tilt down and pan right
	//	XPTZ_ZOOMIN		9		Zoom in
	//	XPTZ_ZOOMOUT	10		Zoom out
	//	XPTZ_STOP		11		Stop the PTZ moving
	//	XPTZ_FOCUS_NEAR	12		Focus near
	//	XPTZ_FOCUS_FAR	13		Focus far
	//	XPTZ_FOCUS_STOP	14		Stop focus moving
	//	XPTZ_IRIS_OPEN	15		Open iris
	//	XPTZ_IRIS_CLOSE	16		Close iris

    try
    {
        TImageBtn *pBtn = (TImageBtn*)Sender;
        //	PTZ_FOCUS_NEAR	12		Focus near
        //	PTZ_FOCUS_FAR	13		Focus far
        //	PTZ_FOCUS_STOP	14		Stop focus moving
        if (pBtn->Tag == 0)
        {
        }
        else
        {
            ControlCamera((int)pBtn->Tag);
        }
    }
    catch(...) {}
}
//---------------------------------------------------------------------------
void __fastcall TFrameSamsungXnsActiveX::BtnWebCamControlMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
    TImageBtn *pBtn = (TImageBtn*)Sender;

    //PTZ Control Stop

    try
    {
        TImageBtn *pBtn = (TImageBtn*)Sender;
        //	PTZ_FOCUS_NEAR	12		Focus near
        //	PTZ_FOCUS_FAR	13		Focus far
        //	PTZ_FOCUS_STOP	14		Stop focus moving
        if (pBtn->Tag == PTZ_FOCUS_NEAR || pBtn->Tag == PTZ_FOCUS_FAR)
        {
            ControlCamera(PTZ_FOCUS_STOP);
        }
        else if (pBtn->Tag == 0)
        {
        }
        else
        {
            ControlCamera(PTZ_STOP);
        }
    }
    catch(...) {}
}
//---------------------------------------------------------------------------
void __fastcall TFrameSamsungXnsActiveX::ControlCamera(int nCommand)
{
	long ret;

    if (m_hDevice == 0 || m_nControlId == 0) return;

    int nPtzSpeed = PTZSpeed->Position;

	//WLOGD(_T("MoveCamera, command=[%d], speed=%d\n"), nCommand, m_nPtzSpeed);

// 	if( nCommand != XPTZ_STOP)
// 		m_ctrlXnsDevice.ControlPtz(m_hDevice, m_nControlId, XPTZ_STOP, 30);

	// Returns the capabilities of the control module.
	long bIsCap = XnsSdkDevice1->GetControlCapability(m_hDevice, m_nControlId, XCTL_CAP_PTZ_SPEED);

	// [ XNS ACTIVEX HELP ]
	// -----------------------------------------------------------------------
	// Moves the camera to the predefined PTZ position. This function is
	// valid as long as the application is receiving media stream from the
	// camera.
	// -----------------------------------------------------------------------
	//	Command			Value	Description
	// -----------------------------------------------------------------------
	//	XPTZ_UP			1		Tilt up
	//	XPTZ_DOWN		2		Tilt down
	//	XPTZ_LEFT		3		Pan left
	//	XPTZ_RIGHT		4		Pan right
	//	XPTZ_UPLEFT		5		Tilt up and pan left
	//	XPTZ_UPRIGHT	6		Tilt up and pan right
	//	XPTZ_DOWNLEFT	7		Tilt down and pan left
	//	XPTZ_DOWNRIGHT	8		Tilt down and pan right
	//	XPTZ_ZOOMIN		9		Zoom in
	//	XPTZ_ZOOMOUT	10		Zoom out
	//	XPTZ_STOP		11		Stop the PTZ moving
	//	XPTZ_FOCUS_NEAR	12		Focus near
	//	XPTZ_FOCUS_FAR	13		Focus far
	//	XPTZ_FOCUS_STOP	14		Stop focus moving
	//	XPTZ_IRIS_OPEN	15		Open iris
	//	XPTZ_IRIS_CLOSE	16		Close iris
	// -----------------------------------------------------------------------
	if (bIsCap)
	{
		ret = XnsSdkDevice1->ControlPtz(
			m_hDevice,		// [in] Device handle. This value is returned from CreateDevice().
			m_nControlId,	// [in] Control ID.
			nCommand,		// [in] PTZ command
			nPtzSpeed		// [in] If nPtzCommand is a speed-related command,
							// this value indicates the PTZ operation speed.
							// (1~100) This value is valid only if the camera
							// supports the XCTL_CAP_PTZ_SPEED capability.
			);
	}
	else
    {
		ret = XnsSdkDevice1->ControlPtz(m_hDevice, m_nControlId, nCommand, 30);
    }

	if (ret != ERR_SUCCESS)
	{
        String sErr;
		sErr.printf(L"ControlPtz() fail:: error=[%d](%s)", ret, XnsSdkDevice1->GetErrorString(ret));
        ShowMessage(sErr);
	}
}
//---------------------------------------------------------------------------

void __fastcall TFrameSamsungXnsActiveX::OpenStream()
{
}
//---------------------------------------------------------------------------

void __fastcall TFrameSamsungXnsActiveX::CloseStream()
{
    DisconnectWebCamera();
    ReleaseWebCamera();
}
//---------------------------------------------------------------------------

void __fastcall TFrameSamsungXnsActiveX::BtnConnectClick(TObject *Sender)
{
    ConnectWebCamera();
}
//---------------------------------------------------------------------------
bool __fastcall TFrameSamsungXnsActiveX::ConnectWebCamera()
{
    bool       bConnect   = true;
    WideString sDefModel  = "Samsung";
    WideString sModelName = CboModel->Text.Trim();
    WideString sIpAddress = EdIpAddress->Text.Trim();
    int        nPort      = StrToInt(EdPort->Text.Trim());
    WideString sID        = EdStreamId->Text.Trim();
    WideString sPass      = EdStreamPswd->Text.Trim();

    nPort = 4520;
	XnsSdkDevice1->SetConnectionInfo(
		m_hDevice,					        // [in] Device handle
		sDefModel.Copy(),				    // [in] Fixed as 'Samsung'
		sModelName.Copy(),				    // [in] Name of model to connect to. The maximum length allowed is 126-byte.
		XADDRESS_IP, sIpAddress.Copy(),	    // [in] Address type, actual address according to addresstype.
		nPort, 0,					        // [in] Port number, port number for web access
		sID.Copy(), sPass.Copy()		    // [in] Login ID, password
		);

	long nRet = XnsSdkDevice1->ConnectNonBlock(
		m_hDevice,		// [in] Device handle
		true,			// [in] Flag to decide where to forcibly log in or not.
		false			// [in] If this value is 1, try to connect again.
		);
	if (nRet != ERR_SUCCESS)
	{
        String sLog;
    	sLog.printf(L"ConnectNonBlock() fail: errno=[%d](%s)\n", nRet, XnsSdkDevice1->GetErrorString(nRet));
        ShowMessage(sLog);
        bConnect = false;
	}

    return bConnect;
}
//---------------------------------------------------------------------------
bool __fastcall TFrameSamsungXnsActiveX::OpenWebCamera()
{
	if (m_hMediaSource)
	{
		reMsg->Lines->Add("Media stream was already opend\n");
		return true;
	}

	int xret = XnsSdkDevice1->GetControlType(m_hDevice, 1);

	//WLOGD(_T("Open media stream:%d\n"), xret);

	// [ XNS ACTIVEX HELP ]
	// -----------------------------------------------------------------------
	// Returns the type of control module corresponding to the control ID.
	//
	// < DVR control module structure >
	// +------------------------------------------------------------
	// Control Module(Device, 1) ----------------- Control ID : 1
	// |---- Control Module(Camera, 1) ----------- Control ID : 2
	// |---- Control Module(Camera, 2) ----------- Control ID : 3
	// |---- Control Module(Camera, 3) ----------- Control ID : 4
	// |---- ....
	// |---- Control Module(Camera,16) ----------- Control ID : 17
	// |---- Control Module(Sensor-in, 1) -------- Control ID : 18
	// |---- ...
	// |---- Control Module(Sensor-in, 16) ------- Control ID : 34
	// |---- Control Module(Digital-out, 1) ------ Control ID : 35
	// |---- ...
	// |---- Control Module(Digital-out, 4) ------ Control ID : 38
	// +------------------------------------------------------------
	//
	// < Network Camera control module structure >
	// +------------------------------------------------------------
	// Control Module(Device, 1) ----------------- Control ID : 1
	// |---- Control Module(Camera, 1) ----------- Control ID : 2
	//       |--- Control Module(Video, 1) ------- Control ID : 3
	//       |--- Control Module(Video, 2) ------- Control ID : 4
	//       |--- ...
	//       |--- Control Module(Video, 10) ------ Control ID : 12
	//       |--- Control Module(Sensor-in, 1) --- Control ID : 13
	//       |--- Control Module(Digital-out, 1) - Control ID : 14
	// +------------------------------------------------------------
	// -----------------------------------------------------------------------

	if (XnsSdkDevice1->GetControlType(m_hDevice, 1) & XCTL_DVR)
	{
		// Returns the number of control modules. The application can get
		// the number of a specific type of control modules, and can get
		// also the whole number of video recorders or cameras.
		// DVR control id is start with 2
		int nCount = XnsSdkDevice1->GetControlCount(m_hDevice, XCTL_CAMERA);
		for(int i=0; i<nCount ; i++)
		{
			// Returns the capabilities of the control module.
			if (XnsSdkDevice1->GetControlCapability(m_hDevice, i+2, XCTL_CAP_LIVE) &&
				// Gets the status of the control module.
				// DVR control id is start with 2
				XnsSdkDevice1->GetControlStatus(m_hDevice, i+2, 1))
			{
				// When called, it will start getting media streams from the
				// device. The receiving media streams will, then, be
				// forwarded to the XnsSdkWindow component that will play
				// the streams after decoding. phMediaSource is needed to
				// link the stream data with XnsSdkWindow.
				// The value can be obtained from a parameter (out-parameter)
				// of OpenMedia(). When XnsSdkWindow receives this value,
				// it can get stream data from the device.
				// phMediaSource is also used for controlling playback of
				// multimedia files. As a result, the application should keep this value at all times.
                XnsSdkDevice1->OpenMedia(
					m_hDevice,			// [in] Device handle. This value is returned from CreateDevice().
					i+2,				// [in] Control ID of video control module.
					MEDIA_TYPE_LIVE,	// [in] Media type.
					0,					// [in] Play start time. Format: 4-byte time_t.
					0,					// [in] Play end time. Format: 4-byte time_t.
					&m_hMediaSource		// [out] Media stream ID. This is needed for controlling
										//       the media stream and also used as a parameter
										//       of XnsSdkWindow::Start().
					);

				// Adds the media source handle to XnsSdkWindow.
				// The media source handle is created by XnsSdkDevice.
				// If the application calls XnsSdkDevice::OpenMedia(),
				// it will receive media stream from the device and return the MediaSource
				// handle. The application uses uses Start() to forward the mediasource
				// handle to XnsSdkWindow so that XnsSdkWindow can obtain stream data.
				XnsSdkWindow1->Start(m_hMediaSource);

				m_nControlId = i+2;
                m_bIsMediaPlay = true;
				//WLOGD(_T("DVR TYPE,  control id = %d\n"), m_nControlId);
				return true;
			}
		}
	}
	else if (XnsSdkDevice1->GetControlType(m_hDevice, 1) & (XCTL_NETCAM |XCTL_ENCODER))
	{
		int nCount = XnsSdkDevice1->GetControlCount(m_hDevice, XCTL_VIDEO);
		if (nCount == 0)
		{
        	nCount = XnsSdkDevice1->GetControlCount(m_hDevice, XCTL_CAMERA);
        }

		for(int i=0; i<nCount ; i++)
		{
			// Network camera and encoder control id is start with 3
			if (XnsSdkDevice1->GetControlCapability(m_hDevice, i+3, XCTL_CAP_LIVE) &&
				XnsSdkDevice1->GetControlStatus(m_hDevice, i+3, 1))
			{
				XnsSdkDevice1->OpenMedia(m_hDevice, i+3, MEDIA_TYPE_LIVE, 0, 0, &m_hMediaSource);
				XnsSdkWindow1->Start(m_hMediaSource);

				m_nControlId = i+3;
                m_bIsMediaPlay = true;
				//WLOGD(_T("NETCAM or ENCODER TYPE,  control id = %d\n"), m_nControlId);
				return true;
			}
		}
	}
	//WLOGD(_T("No valid device.."));

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

void __fastcall TFrameSamsungXnsActiveX::BtnDisconnectClick(TObject *Sender)
{
    DisconnectWebCamera();
    BtnConnect->Enabled = true;
    BtnDisconnect->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcall TFrameSamsungXnsActiveX::DisconnectWebCamera()
{
    if (m_hDevice == 0) return;

	CloseWebCamera();

	// Disconnects from the device.
	XnsSdkDevice1->Disconnect(m_hDevice);

	m_bIsMediaPlay = false;
	m_hMediaSource = 0;
}
//---------------------------------------------------------------------------
void __fastcall TFrameSamsungXnsActiveX::CloseWebCamera()
{
	if (!m_hMediaSource)
	{
		return;
	}

	if (m_bIsMediaPlay)
	{
        XnsSdkWindow1->Stop();
        m_bIsMediaPlay = false;
	}

	XnsSdkDevice1->CloseMedia(m_hDevice, m_hMediaSource);
	m_hMediaSource = 0;
	m_nControlId   = 0;
}
//---------------------------------------------------------------------------

void __fastcall TFrameSamsungXnsActiveX::XnsSdkDevice1ConnectFailed(TObject *Sender, long nDeviceID, long nControlID)
{
    String sDeviceID  = String(nDeviceID);
    String sControlID = String(nControlID);
    String sLog = "Connect Failed: " + sDeviceID + "  " + sControlID;

    reMsg->Lines->Add(sLog);
    BtnConnect->Enabled = true;
    BtnDisconnect->Enabled = false;
}
//---------------------------------------------------------------------------

void __fastcall TFrameSamsungXnsActiveX::XnsSdkDevice1DeviceStatusChanged(TObject *Sender, long nDeviceID, long nErrorCode,
          long nDeviceStatus, long nHddCondition)
{
    String sDeviceID     = String(nDeviceID);
    String sDeviceStatus = String(nDeviceStatus);
    String sErrorCode    = String(nErrorCode);
    String sErrorDesc;

    sErrorDesc.printf(L"%s", XnsSdkDevice1->GetErrorString(nErrorCode));

    reMsg->Lines->Add("Event: " + sDeviceID + "  " + sDeviceStatus + "  " + sErrorDesc);

#if 0
	if (nErrorCode != ERR_SUCCESS || nDeviceStatus != 1)
	{
		return;
	}
#endif
    if (nErrorCode == ERR_SUCCESS && nDeviceStatus == 1)
    {
        reMsg->Lines->Add("Connected...");

    	bool bIsPtzSupport = XnsSdkDevice1->GetControlCapability(m_hDevice, 2, XCTL_CAP_PTZ_PAN);

        OpenWebCamera();

        BtnConnect->Enabled = false;
        BtnDisconnect->Enabled = true;
    }
    else if (nErrorCode == ERR_SUCCESS && nDeviceStatus == 0)
    {
        reMsg->Lines->Add("DisConnected...");
    }
}
//---------------------------------------------------------------------------

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

