using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

using yoseen = YoseenSDKCS;

namespace YoseenDemoWpf
{
    public partial class ShellView : Window
    {
        #region 字符串常量
        public const string Const_hwndShell = "YoseenDemo, Wpf";
        public const string Const_hwndPreview = "Preview";
        public const string Const_btnUrl = "Url";

        public const string Const_btnLogin = "Login";
        public const string Const_btnLogin2 = "Logout";
        public const string Const_btnPlayVideo = "Play Video";
        public const string Const_btnPlayTemp = "Play Temp";
        public const string Const_btnStop = "Stop";

        public const string Const_btnSaveJpgx = "Save .jpg";
        public const string Const_btnSaveMp4 = "Begin Save .mp4";
        public const string Const_btnSaveMp42 = "End Save .mp4";
        public const string Const_btnSaveStream = "Begin Save .stream";
        public const string Const_btnSaveStream2 = "End Save .stream";

        public const string Const_cmbTest_SetMeasureTemplate = "Measure Template";
        public const string Const_cmbTest_ManaulFFC = "Manual FFC";
        public const string Const_btnTest = "Test";

        #endregion

        int _userHandle = -1;
        int _previewHandle = -1;
        yoseen.YoseenLoginInfo _loginInfo;
        yoseen.CameraBasicInfo _cameraBasicInfo;
        ShellViewFlags _flags = 0;


        Array _transformAll;

        yoseen.TransformType _transformType;

        public ShellView()
        {
            InitializeComponent();

            cmbTest.Items.Add(Const_cmbTest_SetMeasureTemplate);
            cmbTest.Items.Add(Const_cmbTest_ManaulFFC);
            cmbTest.SelectedIndex = 0;
            _previewCallback = new yoseen.YoseenPreviewCallback(funcFrameRecved);
            _actUpdateData = new Action<yoseen.DataFrame>(funcUpdateData);
            _actUpdateError = new Action<int>(funcUpdateError);

            //
            _mtStruct = yoseen.MeasureTemplate.Create();

            //20210201
            _transformAll = Enum.GetValues(typeof(yoseen.TransformType));
            cmbTransform.ItemsSource = Enum.GetNames(typeof(yoseen.TransformType));
            cmbTransform.SelectedIndex = 0;
            cmbTransform.SelectionChanged += cmbTransform_SelectionChanged;
            _transformType = yoseen.TransformType.None;
        }

        private void cmbTransform_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            _transformType = (yoseen.TransformType)cmbTransform.SelectedIndex;
        }

        void btnUrl_Click(object sender, RoutedEventArgs e)
        {
            yoseen.DiscoverCameraResp2[] dcrs = yoseen.YoseenSDK.Yoseen_DiscoverCameras2(0x01);
            string s = null;
            if (dcrs.Length == 0)
            {
                s = "discover no cameras";
            }
            else
            {
                s = "discover cameras, ";
                int i = 0;
                for (; i < dcrs.Length; i++)
                {
                    s += yoseen.YoseenUtil.uint2str(dcrs[i].CameraIp) + ", ";
                }
            }
            tbEcho.Text = s;
        }

        void btnLogin_Click(object sender, RoutedEventArgs e)
        {
            if (_userHandle >= 0)
            {
                int ret = yoseen.YoseenSDK.Yoseen_Logout(_userHandle);
                _userHandle = -1;
                btnLogin.Content = Const_btnLogin;
                tbEcho.Text = string.Format("Yoseen_Logout, ret {0}", ret);
            }
            else
            {
                _loginInfo.CameraAddr = tbUrl.Text;
                //_loginInfo.Username = "admin";
                //_loginInfo.Password = "admin";
                int userHandle = yoseen.YoseenSDK.Yoseen_Login(ref _loginInfo, ref _cameraBasicInfo);
                if (userHandle >= 0)
                {
                    _userHandle = userHandle;
                    btnLogin.Content = Const_btnLogin2;
                }
                tbEcho.Text = string.Format("Yoseen_Login, ret {0}", userHandle);

                //yoseen.YoseenLoginInfoV2 loginInfoV2 = new yoseen.YoseenLoginInfoV2();
                //loginInfoV2.CameraAddr = tbUrl.Text;
                //loginInfoV2.PortConfig = 44402;
                //loginInfoV2.PortTemp = 44403;
                //loginInfoV2.PortTempSingle = 44405;
                //loginInfoV2.PortVideo = 44406;
                //loginInfoV2.PortMix = 44407;
                //int userHandle = yoseen.YoseenSDK.Yoseen_LoginV2(ref loginInfoV2, ref _cameraBasicInfo);
                //if (userHandle >= 0)
                //{
                //    _userHandle = userHandle;
                //    btnLogin.Content = Const_btnLogin2;
                //}
                //tbEcho.Text = string.Format("Yoseen_Login, ret {0}", userHandle);

            }
        }

        #region 预览
        yoseen.YoseenPreviewInfo _previewInfo;

        yoseen.YoseenPreviewCallback _previewCallback;
        void funcFrameRecved(int errorCode, ref yoseen.DataFrame dataFrame, IntPtr customData)
        {
            if (0 == errorCode)
            {
                this.Dispatcher.BeginInvoke(_actUpdateData, dataFrame);
            }
            else
            {
                this.Dispatcher.BeginInvoke(_actUpdateError, errorCode);
            }
        }

        readonly Action<int> _actUpdateError;
        void funcUpdateError(int errorCode)
        {
            tbEcho.Text = "PreviewCallback, errorCode " + errorCode;
        }

        readonly Action<yoseen.DataFrame> _actUpdateData;
        void funcUpdateData(yoseen.DataFrame dataFrame)
        {
            //必须检查预览句柄
            if (_previewHandle < 0) return;

            //温度流请用yoseen.H264FrameHeader, 获取已计算的全局温度, 
            //视频流请用yoseen.H264FrameHeaderV2, 获取已计算的全局和局部温度
            //yoseen.H264FrameHeader h264 = (yoseen.H264FrameHeader)Marshal.PtrToStructure(dataFrame.H264, typeof(yoseen.H264FrameHeader));
            //float max = h264.GlobalResult.Max;

            tempCanvas.UpdateData(ref dataFrame);
        }

        void _stopPlay()
        {
            if (_previewHandle < 0) return;

            tempCanvas.EndUpdate();
            int ret = yoseen.YoseenSDK.Yoseen_StopPreview(_previewHandle);
            _previewHandle = -1;
            tbEcho.Text = string.Format("Yoseen_StopPreview, ret {0}", ret);
        }

        void _startPlay(int dataType)
        {
            if (_previewHandle >= 0) return;

            //
            _previewInfo.DataType = dataType;
            _previewInfo.CustomData = IntPtr.Zero;
            _previewInfo.CustomCallback = _previewCallback;
            _previewInfo.Hwnd = IntPtr.Zero;

            //20210201
            int previewHandle = -1;
            if ((int)yoseen.xxxdatatype.temp == dataType)
            {
                //previewHandle = yoseen.YoseenSDK.Yoseen_StartPreview(_userHandle, ref _previewInfo);
                previewHandle = yoseen.YoseenSDK.Yoseen_StartPreviewTempTransform(_userHandle, ref _previewInfo, (int)_transformType);
            }
            else
            {
                previewHandle = yoseen.YoseenSDK.Yoseen_StartPreview(_userHandle, ref _previewInfo);
            }
            tbEcho.Text = string.Format("Yoseen_StartPreview, ret {0}", previewHandle);
            if (previewHandle < 0)
            {
                return;
            }
            _previewHandle = previewHandle;

            //
            int dataWidth = _cameraBasicInfo.DataWidth;
            int dataHeight = _cameraBasicInfo.DataHeight;
            if ((int)yoseen.xxxdatatype.temp == dataType)
            {
                if (_transformType == yoseen.TransformType.Rotate90 
                    || _transformType == yoseen.TransformType.Rotate270)
                {
                    dataWidth = _cameraBasicInfo.DataHeight;
                    dataHeight = _cameraBasicInfo.DataWidth;
                }
            }
            else
            {
                dataWidth = _cameraBasicInfo.VideoWidth;
                dataHeight = _cameraBasicInfo.VideoHeight;
            }

            tempCanvas.BeginUpdate(dataType, dataWidth, dataHeight);
        }

        void btnPlayVideo_Click(object sender, RoutedEventArgs e)
        {
            _startPlay((int)yoseen.xxxdatatype.video);
        }

        void btnPlayTemp_Click(object sender, RoutedEventArgs e)
        {
            _startPlay((int)yoseen.xxxdatatype.temp);
        }

        void btnStop_Click(object sender, RoutedEventArgs e)
        {
            _stopPlay();
        }
        #endregion

        #region 保存
        private void btnSaveJpgx_Click(object sender, RoutedEventArgs e)
        {
            if (_userHandle < 0) return;
            string fn = string.Format("{0}\\{1:yyyyMMdd_HHmmss}.jpg", AppPaths.Data, DateTime.Now);
            int ret = yoseen.YoseenSDK.Yoseen_SaveFrame(_userHandle, fn, 1);
            tbEcho.Text = string.Format("Yoseen_SaveFrame, fn {0}, ret {1}", fn, ret);
        }

        private void btnSaveMp4_Click(object sender, RoutedEventArgs e)
        {
            if (0 > _previewHandle) return;
            int ret;
            if (_flags.HasFlag(ShellViewFlags.SaveMp4))
            {
                ret = yoseen.YoseenSDK.Yoseen_EndSave(_previewHandle, (int)yoseen.xxxmediafile.mp4);
                _flags &= (~ShellViewFlags.SaveMp4);

                btnSaveMp4.Content = Const_btnSaveMp4;
                tbEcho.Text = string.Format("Yoseen_EndSave, ret {0}", ret);
            }
            else
            {
                string fn = string.Format("{0}\\{1:yyyyMMdd_HHmmss}.mp4", AppPaths.Data, DateTime.Now);
                ret = yoseen.YoseenSDK.Yoseen_BeginSave(_previewHandle, fn, (int)yoseen.xxxmediafile.mp4);
                if (0 == ret)
                {
                    _flags |= ShellViewFlags.SaveMp4;
                    btnSaveMp4.Content = Const_btnSaveMp42;
                }
                tbEcho.Text = string.Format("Yoseen_BeginSave, fn {0}, ret {1}", fn, ret);
            }
        }

        private void btnSaveStream_Click(object sender, RoutedEventArgs e)
        {
            if (0 > _previewHandle) return;
            int ret;
            if (_flags.HasFlag(ShellViewFlags.SaveStream))
            {
                ret = yoseen.YoseenSDK.Yoseen_EndSave(_previewHandle, (int)yoseen.xxxmediafile.stream);
                _flags &= (~ShellViewFlags.SaveStream);

                btnSaveStream.Content = Const_btnSaveStream;
                tbEcho.Text = string.Format("Yoseen_EndSave, ret {0}", ret);
            }
            else
            {
                string fn = string.Format("{0}\\{1:yyyyMMdd_HHmmss}.stream", AppPaths.Data, DateTime.Now);
                ret = yoseen.YoseenSDK.Yoseen_BeginSave(_previewHandle, fn, (int)yoseen.xxxmediafile.stream);
                if (0 == ret)
                {
                    _flags |= ShellViewFlags.SaveStream;
                    btnSaveStream.Content = Const_btnSaveStream2;
                }
                tbEcho.Text = string.Format("Yoseen_BeginSave, fn {0}, ret {1}", fn, ret);
            }
        }
        #endregion

        #region 测试

        yoseen.MeasureTemplate _mtStruct;

        private void btnTest_Click(object sender, RoutedEventArgs e)
        {
            if (0 > _userHandle) return;

            int sel = cmbTest.SelectedIndex;
            int ret;
            switch (sel)
            {
                //设置测温模板, 视频流预览
                case 0:
                    {
                        _mtStruct.Head.Width = _cameraBasicInfo.DataWidth;
                        _mtStruct.Head.Height = _cameraBasicInfo.DataHeight;

                        int width = _cameraBasicInfo.DataWidth;
                        int height = _cameraBasicInfo.DataHeight;

                        //
                        ushort[] xydata = _mtStruct.ShieldArray[0].xydata;
                        xydata[0] = (ushort)(width / 8); xydata[1] = (ushort)(height / 8);
                        xydata[2] = (ushort)(width * 2 / 8); xydata[3] = (ushort)(height / 8);
                        xydata[4] = (ushort)(width * 2 / 8); xydata[5] = (ushort)(height * 2 / 8);
                        xydata[6] = (ushort)(width / 8); xydata[7] = (ushort)(height * 2 / 8);
                        _mtStruct.Head.ShieldFlags = 0x01;

                        //
                        _mtStruct.GMO.measureflags = yoseen.xxxmeasureflags.track_max | yoseen.xxxmeasureflags.plot_max;
                        _mtStruct.LMOArray[0].measureflags = yoseen.xxxmeasureflags.track_max | yoseen.xxxmeasureflags.plot_max;
                        _mtStruct.LMOArray[0].emmi = 97;
                        _mtStruct.LMOArray[0].measuretype = yoseen.xxxmeasuretype.polygon;
                        _mtStruct.LMOArray[0].points = 4;
                        xydata = _mtStruct.LMOArray[0].xydata;
                        xydata[0] = (ushort)(width * 3 / 8); xydata[1] = (ushort)(height * 4 / 8);
                        xydata[2] = (ushort)(width * 5 / 8); xydata[3] = (ushort)(height * 4 / 8);
                        xydata[4] = (ushort)(width * 5 / 8); xydata[5] = (ushort)(height * 7 / 8);
                        xydata[6] = (ushort)(width * 3 / 8); xydata[7] = (ushort)(height * 7 / 8);
                        _mtStruct.Head.LMOFlags = 0x01;

                        //
                        IntPtr ptrMT = yoseen.Win32Helper.malloc(1024 * 1024);
                        Marshal.StructureToPtr(_mtStruct, ptrMT, false);
                        ret = yoseen.YoseenSDK.Yoseen_UploadMem(_userHandle, 0, ptrMT, yoseen.MeasureTemplate.ConstSize);
                        yoseen.Win32Helper.free(ptrMT);
                        break;
                    }

                //手动挡板校零
                case 1:
                    {
                        yoseen.Ctl ctl = new yoseen.Ctl();
                        ctl.Type = yoseen.CtlType.CtlType_ManualFFC;
                        ret = yoseen.YoseenSDK.Yoseen_SendControl(_userHandle, ref ctl);
                        break;
                    }


                default:
                    break;
            }

        }
        #endregion

        /// <summary>
        /// 关闭窗口, 停止预览, 防止跨线程问题
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosing(CancelEventArgs e)
        {
            _stopPlay();
            base.OnClosing(e);
        }
    }

    [Flags]
    enum ShellViewFlags
    {
        SaveMp4 = 0x0001,
        SaveStream = 0x0002,
    }
}
