using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceModel.Discovery;
using System.Text;
using System.Threading;

namespace YoseenSDKCS.HKDef
{
    public class HKDevice : IDisposable
    {
        #region static
        static bool __sdkInited;

        public static bool HK_InitSDK()
        {
            if (__sdkInited) return true;

            __sdkInited = HKSDK.NET_DVR_Init();
            return __sdkInited;
        }

        public static void HK_FreeSDK()
        {
            if (__sdkInited)
            {
                HKSDK.NET_DVR_Cleanup();
                __sdkInited = false;
            }
        }

        #endregion

        string _ip;
        string _username;
        string _password;

        NET_DVR_DEVICEINFO_V30 _deviceInfo;
        const int ConstSTD_BufferSize = 8 * 1024;
        const int ConstDVR_BufferSize = 8 * 1024;
        const int Const_BufferSize = ConstSTD_BufferSize + ConstDVR_BufferSize;
        IntPtr _ptrBuffer;

        int _userId;
        public int UserId
        {
            get { return _userId; }
        }

        //
        int _serialId;
        byte[] _sendBuffer;
        byte[] _recvBuffer;
        ManualResetEvent _mre;
        int _pan;
        int _tilt;
        int _zoom;
        int _recvTimeout;
        public int RecvTimeout
        {
            get { return _recvTimeout; }

            set
            {
                if (value >= 1000 && value <= 3000)
                {
                    _recvTimeout = value;
                }
            }
        }
        SERIALDATACALLBACK _serialCallback;

        public HKDevice()
        {
            _userId = -1;
            _ptrBuffer = Win32Helper.calloc(1, Const_BufferSize);
            if (_ptrBuffer == IntPtr.Zero)
            {
                throw new Exception("no mem");
            }

            //xptz
            _serialId = -1;
            _sendBuffer = new byte[256];
            _recvBuffer = new byte[256];
            _mre = new ManualResetEvent(false);
            _recvTimeout = 1000;
            _serialCallback = new SERIALDATACALLBACK(_serialCallbackFunc);

            //xml
            _stdConfig.byDataType = 1;
            _stdConfig.lpCondBuffer = _ptrBuffer + 1024;
            _stdConfig.dwCondSize = 1024;
            _stdConfig.lpXmlBuffer = _stdConfig.lpCondBuffer + 1024;
            _stdConfig.dwXmlSize = 1024;

            //bin
            _dvrConfig = _ptrBuffer + ConstSTD_BufferSize;
        }

        public bool Login(string ip, string username, string password)
        {
            bool valid = !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(ip);
            if (!valid)
            {
                return false;
            }
            if (username == _username && password == _password && ip == _ip) return true;

            //
            if (_userId > 0)
            {
                HKSDK.NET_DVR_Logout(_userId);
                _userId = -1;
            }

            _userId = HKSDK.NET_DVR_Login_V30(ip, HKConsts.Port, username, password, ref _deviceInfo);
            if (_userId < 0) goto error1;
            _ip = ip;
            _username = username;
            _password = password;
            return true;

            error1:
            if (_userId >= 0)
            {
                HKSDK.NET_DVR_Logout(_userId);
                _userId = -1;
            }
            return false;
        }

        public void Logout()
        {
            XPtzFree();

            //
            if (_userId >= 0)
            {
                HKSDK.NET_DVR_Logout(_userId);
                _userId = -1;
            }
            _ip = "";
        }

        public void Dispose()
        {
            if (_serialId > 0)
            {
                HKSDK.NET_DVR_SerialStop(_serialId);
                _serialId = -1;
            }

            if (_userId > 0)
            {
                HKSDK.NET_DVR_Logout(_userId);
                _userId = -1;
            }

            if (_ptrBuffer != IntPtr.Zero)
            {
                Win32Helper.free(_ptrBuffer);
                _ptrBuffer = IntPtr.Zero;
            }
        }

        public bool PtzControl(ePtzAction act, byte arg)
        {
            if (_userId < 0) return false;

            bool ret = false;
            uint hkcmd = 0;
            uint hkarg = arg;

            switch (act)
            {
                //
                case ePtzAction.MoveUp:
                    hkcmd = HKConsts.Ptz_Up;
                    break;
                case ePtzAction.MoveDown:
                    hkcmd = HKConsts.Ptz_Down;
                    break;

                case ePtzAction.MoveLeft:
                    hkcmd = HKConsts.Ptz_Left;
                    break;

                case ePtzAction.MoveRight:
                    hkcmd = HKConsts.Ptz_Right;
                    break;

                //
                case ePtzAction.MoveLeftUp:
                    hkcmd = HKConsts.Ptz_LeftUp;
                    break;

                case ePtzAction.MoveRightUp:
                    hkcmd = HKConsts.Ptz_RightUp;
                    break;

                case ePtzAction.MoveLeftDown:
                    hkcmd = HKConsts.Ptz_LeftDown;
                    break;

                case ePtzAction.MoveRightDown:
                    hkcmd = HKConsts.Ptz_RightDown;
                    break;

                //
                case ePtzAction.ZoomIn:
                    hkcmd = HKConsts.Ptz_ZoomIn;
                    break;

                case ePtzAction.ZoomOut:
                    hkcmd = HKConsts.Ptz_ZoomOut;
                    break;

                case ePtzAction.FocusFar:
                    hkcmd = HKConsts.Ptz_FocusFar;
                    break;

                case ePtzAction.FocusNear:
                    hkcmd = HKConsts.Ptz_FocusNear;
                    break;

                case ePtzAction.IrisOpen:
                    hkcmd = HKConsts.Ptz_IrisOpen;
                    break;

                case ePtzAction.IrisClose:
                    hkcmd = HKConsts.Ptz_IrisClose;
                    break;

                //
                case ePtzAction.PresetSet:
                    hkcmd = HKConsts.Ptz_SetPreset;
                    break;
                case ePtzAction.PresetClear:
                    hkcmd = HKConsts.Ptz_ClearPreset;
                    break;
                case ePtzAction.PresetGoto:
                    hkcmd = HKConsts.Ptz_GotoPreset;
                    break;

                //
                case ePtzAction.SwitchLightPowerOn:
                    hkcmd = HKConsts.Ptz_LightPowerOn;
                    hkarg = 0;
                    break;
                case ePtzAction.SwitchLightPowerOff:
                    hkcmd = HKConsts.Ptz_LightPowerOn;
                    hkarg = 1;
                    break;
                case ePtzAction.SwitchWiperPowerOn:
                    hkcmd = HKConsts.Ptz_WiperPowerOn;
                    hkarg = 0;
                    break;
                case ePtzAction.SwitchWiperPowerOff:
                    hkcmd = HKConsts.Ptz_WiperPowerOn;
                    hkarg = 1;
                    break;

                default:
                    return false;
            }
            if (act >= ePtzAction.MoveUp && act <= ePtzAction.IrisClose)
            {
                ret = HKSDK.NET_DVR_PTZControlWithSpeed_Other(_userId, 1, hkcmd, 0, hkarg);
            }
            else if (act >= ePtzAction.PresetSet && act <= ePtzAction.PresetGoto)
            {
                ret = HKSDK.NET_DVR_PTZPreset_Other(_userId, 1, hkcmd, hkarg);
            }
            else if (act >= ePtzAction.SwitchLightPowerOn && act <= ePtzAction.SwitchWiperPowerOff)
            {
                ret = HKSDK.NET_DVR_PTZControl_Other(_userId, 1, hkcmd, hkarg);
            }
            return ret;
        }

        public bool PtzControl_Stop(ePtzAction act, byte arg)
        {
            if (_userId < 0) return false;

            bool ret = false;
            uint hkcmd = 0;
            uint hkarg = arg;

            switch (act)
            {
                //
                case ePtzAction.MoveUp:
                    hkcmd = HKConsts.Ptz_Up;
                    break;
                case ePtzAction.MoveDown:
                    hkcmd = HKConsts.Ptz_Down;
                    break;

                case ePtzAction.MoveLeft:
                    hkcmd = HKConsts.Ptz_Left;
                    break;

                case ePtzAction.MoveRight:
                    hkcmd = HKConsts.Ptz_Right;
                    break;

                //
                case ePtzAction.MoveLeftUp:
                    hkcmd = HKConsts.Ptz_LeftUp;
                    break;

                case ePtzAction.MoveRightUp:
                    hkcmd = HKConsts.Ptz_RightUp;
                    break;

                case ePtzAction.MoveLeftDown:
                    hkcmd = HKConsts.Ptz_LeftDown;
                    break;

                case ePtzAction.MoveRightDown:
                    hkcmd = HKConsts.Ptz_RightDown;
                    break;

                //
                case ePtzAction.ZoomIn:
                    hkcmd = HKConsts.Ptz_ZoomIn;
                    break;

                case ePtzAction.ZoomOut:
                    hkcmd = HKConsts.Ptz_ZoomOut;
                    break;

                case ePtzAction.FocusFar:
                    hkcmd = HKConsts.Ptz_FocusFar;
                    break;

                case ePtzAction.FocusNear:
                    hkcmd = HKConsts.Ptz_FocusNear;
                    break;

                case ePtzAction.IrisOpen:
                    hkcmd = HKConsts.Ptz_IrisOpen;
                    break;

                case ePtzAction.IrisClose:
                    hkcmd = HKConsts.Ptz_IrisClose;
                    break;

                default:
                    return false;
            }
            ret = HKSDK.NET_DVR_PTZControlWithSpeed_Other(_userId, 1, hkcmd, 1, hkarg);
            return ret;
        }

        public bool SaveFrame(string filename)
        {
            if (_userId < 0) return false;
            bool ret = HKSDK.NET_DVR_CaptureJPEGPicture(_userId, 1, ref HKConsts.jpgPara, filename);
            return ret;
        }

        public bool SaveFrameToMem(IntPtr ptrBuffer, int bufferSize, ref int sizeReturned)
        {
            if (_userId < 0) return false;
            bool ret = HKSDK.NET_DVR_CaptureJPEGPicture_NEW(_userId, 1, ref HKConsts.jpgPara, ptrBuffer, bufferSize, ref sizeReturned);
            return ret;
        }

        #region XPtz

        public bool XPtzInit()
        {
            if (_userId < 0) return false;
            if (_serialId >= 0) return false;

            _serialId = HKSDK.NET_DVR_SerialStart(_userId, 2, _serialCallback, 0);//2
            bool ret = _serialId >= 0;
            return ret;
        }

        public void XPtzFree()
        {
            if (_serialId >= 0)
            {
                HKSDK.NET_DVR_SerialStop(_serialId);
                _serialId = -1;
            }
        }

        public bool XPtzControl(ePtzAction act, byte arg)
        {
            if (act == ePtzAction.ZoomIn || act == ePtzAction.ZoomOut)
            {
                return _beginZoom(act, arg);
            }

            //
            if (_serialId < 0) return false;
            _sendBuffer[0] = 0xff;
            _sendBuffer[1] = 0x01;
            switch (act)
            {
                //
                case ePtzAction.Stop:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x00;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x00;
                    break;
                case ePtzAction.MoveUp:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x08;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = arg;
                    break;

                case ePtzAction.MoveDown:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x10;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = arg;
                    break;

                case ePtzAction.MoveLeft:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x04;
                    _sendBuffer[4] = arg; _sendBuffer[5] = 0x00;
                    break;

                case ePtzAction.MoveRight:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x02;
                    _sendBuffer[4] = arg; _sendBuffer[5] = 0x00;
                    break;

                //
                case ePtzAction.MoveLeftUp:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x0c;
                    _sendBuffer[4] = arg; _sendBuffer[5] = arg;
                    break;

                case ePtzAction.MoveRightUp:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x0a;
                    _sendBuffer[4] = arg; _sendBuffer[5] = arg;
                    break;

                case ePtzAction.MoveLeftDown:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x14;
                    _sendBuffer[4] = arg; _sendBuffer[5] = arg;
                    break;

                case ePtzAction.MoveRightDown:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x12;
                    _sendBuffer[4] = arg; _sendBuffer[5] = arg;
                    break;

                //
                //case ePtzAction.ZoomIn:
                //    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x20;
                //    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x00;
                //    break;
                //case ePtzAction.ZoomOut:
                //    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x40;
                //    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x00;
                //    break;

                case ePtzAction.FocusFar:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x80;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x00;
                    break;

                case ePtzAction.FocusNear:
                    _sendBuffer[2] = 0x01; _sendBuffer[3] = 0x00;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x00;
                    break;

                case ePtzAction.IrisOpen:
                    _sendBuffer[2] = 0x20; _sendBuffer[3] = 0x00;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x00;
                    break;

                case ePtzAction.IrisClose:
                    _sendBuffer[2] = 0x40; _sendBuffer[3] = 0x00;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x00;
                    break;

                //
                case ePtzAction.PresetSet:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x03;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = arg;
                    break;

                case ePtzAction.PresetClear:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x05;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = arg;
                    break;

                case ePtzAction.PresetGoto:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x07;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = arg;
                    break;

                //
                case ePtzAction.SwitchLightPowerOn:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x09;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x02;
                    break;

                case ePtzAction.SwitchLightPowerOff:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x0b;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x02;
                    break;

                case ePtzAction.SwitchWiperPowerOn:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x09;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x01;
                    break;

                case ePtzAction.SwitchWiperPowerOff:
                    _sendBuffer[2] = 0x00; _sendBuffer[3] = 0x0b;
                    _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x01;
                    break;

                default:
                    return false;
            }
            _sendBuffer[6] = (byte)((_sendBuffer[1] + _sendBuffer[2] + _sendBuffer[3] + _sendBuffer[4] + _sendBuffer[5]) & 0xff);
            Marshal.Copy(_sendBuffer, 0, _ptrBuffer, 7);

            bool ret = HKSDK.NET_DVR_SerialSend(_serialId, 1, _ptrBuffer, 7);
            return ret;
        }

        public bool XPtzControl_Stop(ePtzAction act, byte arg)
        {
            if (act == ePtzAction.ZoomIn || act == ePtzAction.ZoomOut)
            {
                return _endZoom(act, arg);
            }
            bool ret = XPtzControl(ePtzAction.Stop, 0);
            return ret;
        }

        void _serialCallbackFunc(int lSerialHandle, IntPtr pRecvDataBuffer, uint dwBufSize, uint dwUser)
        {
            while (dwBufSize >= 7)
            {
                Marshal.Copy(pRecvDataBuffer, _recvBuffer, 0, 7);
                dwBufSize -= 7;
                pRecvDataBuffer += 7;

                byte ptzType = _recvBuffer[3];
                if (ptzType == 0x59)
                {
                    _pan = (_recvBuffer[4] << 8) + _recvBuffer[5];
                }
                else if (ptzType == 0x5b)
                {
                    _tilt = (_recvBuffer[4] << 8) + _recvBuffer[5];
                    _mre.Set();
                }
                //else if (ptzType == 0x5d)
                //{
                //    _zoom = (_recvBuffer[4] << 8) + _recvBuffer[5];
                //}
            }
        }

        NET_DVR_PTZPOS _ptzPos;
        bool _getZoom(ref int zoom)
        {
            uint bytesReturn = 0;
            bool ret = HKSDK.NET_DVR_GetDVRConfig(_userId, HKConsts.NET_DVR_GET_PTZPOS, 1, _ptrBuffer, 8, ref bytesReturn);
            if (ret)
            {
                _ptzPos = (NET_DVR_PTZPOS)Marshal.PtrToStructure(_ptrBuffer, typeof(NET_DVR_PTZPOS));
                zoom = _ptzPos.wZoomPos;
                zoom = (zoom & 0x000f) + ((zoom >> 4) & 0x000f) * 10 + ((zoom >> 8) & 0x000f) * 100 + ((zoom >> 12) & 0x000f) * 1000;
            }
            return ret;
        }

        bool _setZoom(int zoom)
        {
            _ptzPos.wAction = 4;

            int z1000 = zoom / 1000;
            int z100 = (zoom - z1000 * 1000) / 100;
            int z10 = (zoom - z1000 * 1000 - z100 * 100) / 10;
            int z1 = zoom - z1000 * 1000 - z100 * 100 - z10 * 10;
            zoom = (z1000 << 12) | (z100 << 8) | (z10 << 4) | (z1);

            _ptzPos.wZoomPos = (ushort)zoom;
            Marshal.StructureToPtr(_ptzPos, _ptrBuffer, false);
            bool ret = HKSDK.NET_DVR_SetDVRConfig(_userId, HKConsts.NET_DVR_SET_PTZPOS, 1, _ptrBuffer, 8);

            return ret;
        }

        bool _beginZoom(ePtzAction act, byte arg)
        {
            uint hkcmd = 0;
            uint hkarg = arg;
            if (act == ePtzAction.ZoomIn)
            {
                hkcmd = HKConsts.Ptz_ZoomIn;
            }
            else
            {
                hkcmd = HKConsts.Ptz_ZoomOut;
            }
            bool ret = HKSDK.NET_DVR_PTZControlWithSpeed_Other(_userId, 1, hkcmd, 0, hkarg);
            return ret;
        }

        bool _endZoom(ePtzAction act, byte arg)
        {
            uint hkcmd = 0;
            uint hkarg = arg;
            if (act == ePtzAction.ZoomIn)
            {
                hkcmd = HKConsts.Ptz_ZoomIn;
            }
            else
            {
                hkcmd = HKConsts.Ptz_ZoomOut;
            }
            bool ret = HKSDK.NET_DVR_PTZControlWithSpeed_Other(_userId, 1, hkcmd, 1, hkarg);
            return ret;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pan">0-36000, 0.01</param>
        /// <param name="tilt">0-36000, 0.01</param>
        /// <param name="zoom">10-300, 0.1</param>
        /// <returns></returns>
        public bool XPtzControl_GetPtz(ref int pan, ref int tilt, ref int zoom)
        {
            if (_serialId < 0) return false;
            _sendBuffer[0] = 0xff;
            _sendBuffer[1] = 0x01;

            _sendBuffer[2] = 0x00;
            _sendBuffer[4] = 0x00; _sendBuffer[5] = 0x00;

            _mre.Reset();
            //
            _sendBuffer[3] = 0x51;
            _sendBuffer[6] = (byte)((_sendBuffer[1] + _sendBuffer[2] + _sendBuffer[3] + _sendBuffer[4] + _sendBuffer[5]) & 0xff);
            Marshal.Copy(_sendBuffer, 0, _ptrBuffer, 7);
            bool ret = HKSDK.NET_DVR_SerialSend(_serialId, 1, _ptrBuffer, 7);
            if (!ret) goto error1;

            //
            Thread.Sleep(300);
            _sendBuffer[3] = 0x53;
            _sendBuffer[6] = (byte)((_sendBuffer[1] + _sendBuffer[2] + _sendBuffer[3] + _sendBuffer[4] + _sendBuffer[5]) & 0xff);
            Marshal.Copy(_sendBuffer, 0, _ptrBuffer, 7);
            ret = HKSDK.NET_DVR_SerialSend(_serialId, 1, _ptrBuffer, 7);
            if (!ret) goto error1;

            //
            //_sendBuffer[3] = 0x55;
            //_sendBuffer[6] = (byte)((_sendBuffer[1] + _sendBuffer[2] + _sendBuffer[3] + _sendBuffer[4] + _sendBuffer[5]) & 0xff);
            //Marshal.Copy(_sendBuffer, 0, _ptrBuffer, 7);
            //ret = HK.NET_DVR_SerialSend(_serialId, 1, _ptrBuffer, 7);
            ret = _getZoom(ref _zoom);
            if (!ret) goto error1;

            //
            ret = _mre.WaitOne(_recvTimeout);
            if (ret)
            {
                pan = _pan;
                tilt = _tilt;
                zoom = _zoom;
            }
            error1:
            return ret;
        }

        public bool XPtzControl_SetPtz(int pan, int tilt, int zoom)
        {
            if (_serialId < 0) return false;
            _sendBuffer[0] = 0xff;
            _sendBuffer[1] = 0x01;
            _sendBuffer[2] = 0x00;

            //
            bool ret = false;
            if (pan >= 0)
            {
                _sendBuffer[3] = 0x4b;
                _sendBuffer[4] = (byte)((pan >> 8) & 0xff); _sendBuffer[5] = (byte)(pan & 0xff);
                _sendBuffer[6] = (byte)((_sendBuffer[1] + _sendBuffer[2] + _sendBuffer[3] + _sendBuffer[4] + _sendBuffer[5]) & 0xff);
                Marshal.Copy(_sendBuffer, 0, _ptrBuffer, 7);
                ret = HKSDK.NET_DVR_SerialSend(_serialId, 1, _ptrBuffer, 7);
                if (!ret) goto error1;
            }

            //
            if (tilt >= 0)
            {
                _sendBuffer[3] = 0x4d;
                _sendBuffer[4] = (byte)((tilt >> 8) & 0xff); _sendBuffer[5] = (byte)(tilt & 0xff);
                _sendBuffer[6] = (byte)((_sendBuffer[1] + _sendBuffer[2] + _sendBuffer[3] + _sendBuffer[4] + _sendBuffer[5]) & 0xff);
                Marshal.Copy(_sendBuffer, 0, _ptrBuffer, 7);
                ret = HKSDK.NET_DVR_SerialSend(_serialId, 1, _ptrBuffer, 7);
                if (!ret) goto error1;
            }

            //
            if (zoom >= 0)
            {
                //_sendBuffer[3] = 0x4f;
                //_sendBuffer[4] = (byte)((zoom >> 8) & 0xff); _sendBuffer[5] = (byte)(zoom & 0xff);
                //_sendBuffer[6] = (byte)((_sendBuffer[1] + _sendBuffer[2] + _sendBuffer[3] + _sendBuffer[4] + _sendBuffer[5]) & 0xff);
                //Marshal.Copy(_sendBuffer, 0, _ptrBuffer, 7);
                //ret = HK.NET_DVR_SerialSend(_serialId, 1, _ptrBuffer, 7);
                ret = _setZoom(zoom);
                if (!ret) goto error1;
            }
            error1:
            return ret;
        }

        #endregion

        #region NET_DVR_GetSTDConfig, xml
        NET_DVR_STD_CONFIG _stdConfig = new NET_DVR_STD_CONFIG();
        public bool GetSupplementLight(out SupplementLight xml)
        {
            Marshal.WriteInt32(_stdConfig.lpCondBuffer, 1);
            _stdConfig.dwCondSize = 4;

            bool b;
            b = HKSDK.NET_DVR_GetSTDConfig(_userId, HKConsts.NET_DVR_GET_SUPPLEMENTLIGHT, ref _stdConfig);
            if (!b)
            {
                xml = null;
                return b;
            }

            string s = Marshal.PtrToStringAnsi(_stdConfig.lpXmlBuffer);
            xml = XmlUtil.Deserialize<SupplementLight>(s);
            return b;
        }

        public bool SetSupplementLight(SupplementLight xml)
        {
            string s = XmlUtil.Serialize<SupplementLight>(xml);
            byte[] bs = Encoding.ASCII.GetBytes(s);
            if (bs.Length > 1024) return false;

            Marshal.WriteInt32(_stdConfig.lpCondBuffer, 1);
            _stdConfig.dwCondSize = 4;
            Marshal.Copy(bs, 0, _stdConfig.lpXmlBuffer, bs.Length);
            _stdConfig.dwXmlSize = (uint)bs.Length;

            bool b;
            b = HKSDK.NET_DVR_SetSTDConfig(_userId, HKConsts.NET_DVR_SET_SUPPLEMENTLIGHT, ref _stdConfig);
            return b;
        }
        #endregion

        #region NET_DVR_GetDVRConfig, bin
        IntPtr _dvrConfig;
        public bool GetCameraParamCfg(ref NET_DVR_CAMERAPARAMCFG bin)
        {
            if (_userId < 0) return false;
            bool b;
            uint bytesReturn = 0;
            b = HKSDK.NET_DVR_GetDVRConfig(_userId, HKConsts.NET_DVR_GET_CCDPARAMCFG, 0, _dvrConfig, ConstDVR_BufferSize, ref bytesReturn);
            if (!b) return b;

            bin = Marshal.PtrToStructure<NET_DVR_CAMERAPARAMCFG>(_dvrConfig);
            return true;
        }

        public bool SetCameraParamCfg(ref NET_DVR_CAMERAPARAMCFG bin)
        {
            if (_userId < 0) return false;
            bool b;
            Marshal.StructureToPtr<NET_DVR_CAMERAPARAMCFG>(bin, _dvrConfig, false);
            b = HKSDK.NET_DVR_SetDVRConfig(_userId, HKConsts.NET_DVR_SET_CCDPARAMCFG, 0, _dvrConfig, ConstDVR_BufferSize);
            return b;
        }
        #endregion
    }

    public enum ePtzAction
    {
        Stop,

        MoveUp,
        MoveDown,
        MoveLeft,
        MoveRight,

        MoveLeftUp,
        MoveRightUp,
        MoveLeftDown,
        MoveRightDown,

        ZoomIn,
        ZoomOut,

        FocusFar,
        FocusNear,

        IrisOpen,
        IrisClose,

        PresetSet,
        PresetClear,
        PresetGoto,


        GetPTZ,
        SetPTZ,

        SwitchLightPowerOn,
        SwitchLightPowerOff,

        SwitchWiperPowerOn,
        SwitchWiperPowerOff,
    }
}
