using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using CalculatorModuleCs;
using GlobalVariableModuleCs;
using IfModuleCs;
using ImageSourceModuleCs;
using IMVSCircleFitModuCs;
using IMVSLineFindModuCs;
using SaveImageCs;
using VM.Core;
using VM.PlatformSDKCS;


namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MachineVision.HikVision
{
    public class HikVisionMasterSDK : BaseDevice, IDevice
    {
        string _sol = "";
        private PeriodicJob _thread;
        private bool _isInit = false;
        public HikVisionMasterSDK(string module, string scRoot, string name,bool isInit) : base(module, name, name, name)
        {
            IsProcessing = false;
            _sol = SC.SafeGetStringValue($"{Name}.VMSolutionAddress", "D:\\VMSolution\\123.sol");
            _thread = new PeriodicJob(200, OnTimer, $"{Module}.{Name} MonitorHandler", true);
            _isInit = isInit;
        }

        public string Command { get; set; } = "";

        /// <summary>
        /// 标记当前执行的程序流程
        /// </summary>
        public string ProjectName { get; set; } = "";   

        public bool ModuleStatus { get; set; } = false;

        public bool Result { get; set; } = false;

        public double[] SampleCircle { get; set; } = new double[3];

        public double[] CurrentCircle { get; set; } = new double[3];

        public double[] SampleData { get; set; }

        public double[] SampleData2 { get; set; }

        public double Distance { get; set; } = 0;

        public double Tolerance { get; set; } = 1;

        public double Tolerance2 { get; set; } = 1;

        public bool IsProcessing { get; set; } = false;

        public bool LoadFile { get; set; } = false;

        public byte[] OutputImage { get; set; } = null;

        public byte[] PreviewImage1 { get; set; } = null;

        public byte[] PreviewImage2 { get; set; } = null;

        public byte[] PreviewImage3 { get; set; } = null;

        public byte[] PreviewImage4 { get; set; } = null;

        public string LocalImageFilePath { get; set; }
        public bool Initialize()
        {
            LocalImageFilePath = SC.SafeGetStringValue($"{Name}.{nameof(LocalImageFilePath)}", "D:\\VMImage\\Input");
            if (!Directory.Exists(LocalImageFilePath))
            {
                // 创建文件夹
                Directory.CreateDirectory(LocalImageFilePath);
                Console.WriteLine($"Folder '{LocalImageFilePath}' created successfully.");
            }

            string s = SC.SafeGetStringValue($"{Name}.SampleData", "100,200,200,300,300,100");    //隐藏项
            string s2 = SC.SafeGetStringValue($"{Name}.SampleData2", "100,200,200,300,300,100");    //隐藏项
            SampleData = ConvertSample(s);
            SampleData2 = ConvertSample(s2);
            if (SampleData == null || SampleData2 == null)
            {
                EV.PostAlarmLog(Module, $"SampleData failed");
                return true;
            }

            Tolerance = SC.GetValue<double>($"{Name}.{nameof(Tolerance)}", 1);
            SC.RegisterValueChangedCallback($"{Name}.{nameof(Tolerance)}", (newvalue) => { Tolerance = (double)newvalue; LoadSolution(); });   //实时修改
            Tolerance2 = SC.GetValue<double>($"{Name}.{nameof(Tolerance2)}", 1);
            SC.RegisterValueChangedCallback($"{Name}.{nameof(Tolerance2)}", (newvalue) => { Tolerance2 = (double)newvalue; LoadSolution(); });   //实时修改

            DATA.Subscribe($"{Module}.{Name}.{nameof(ProjectName)}", () => ProjectName);
            DATA.Subscribe($"{Module}.{Name}.{nameof(ModuleStatus)}", () => ModuleStatus);
            DATA.Subscribe($"{Module}.{Name}.{nameof(IsProcessing)}", () => IsProcessing);
            DATA.Subscribe($"{Module}.{Name}.{nameof(SampleCircle)}", () => SampleCircle);
            DATA.Subscribe($"{Module}.{Name}.{nameof(CurrentCircle)}", () => CurrentCircle);
            DATA.Subscribe($"{Module}.{Name}.{nameof(Distance)}", () => Distance);
            DATA.Subscribe($"{Module}.{Name}.{nameof(OutputImage)}", () => OutputImage);
            DATA.Subscribe($"{Module}.{Name}.{nameof(Result)}", () => Result);
            DATA.Subscribe($"{Module}.{Name}.{nameof(LoadFile)}", () => LoadFile);
            DATA.Subscribe($"{Module}.{Name}.{nameof(PreviewImage1)}", () => PreviewImage1);
            DATA.Subscribe($"{Module}.{Name}.{nameof(PreviewImage2)}", () => PreviewImage2);
            DATA.Subscribe($"{Module}.{Name}.{nameof(PreviewImage3)}", () => PreviewImage3);
            DATA.Subscribe($"{Module}.{Name}.{nameof(PreviewImage4)}", () => PreviewImage4);

            if (!_isInit)
            {
                return true;
            }

            OP.Subscribe($"{Module}.{Name}.ExecuteLocalFile", (string cmd, object[] args) => ExecuteLocalFile((string)args[0]));
            OP.Subscribe($"{Module}.{Name}.SetSample", (string cmd, object[] args) => SetSample((string)args[0]));
            OP.Subscribe($"{Module}.{Name}.ReloadSolution", (string cmd, object[] args) => LoadSolution());
            OP.Subscribe($"{Module}.{Name}.ExecuteGrab", (string cmd, object[] args) => ExecuteGrab((string)args[0]));

            LoadSolution();
            return true;
        }

        private double[] ConvertSample(string s)
        {
            var ss = s.Split(',');
            if (ss.Length != 6) return null;
            double[] ff = new double[6];
            try
            {
                for (int i = 0; i < ff.Length; i++)
                {
                    ff[i] = Convert.ToDouble(ss[i]);
                }
            }
            catch (Exception)
            {
                return null;
            }
            
            return ff;
        }

        private bool SetSample(string command)
        {
            if (command == "GroupCheck")
            {
                ProjectName = "FindEdge";
            }
            else if (command.Contains("WaferPlaceCheck"))
            {
                ProjectName = "FindEdge2";
            }
            else
            {
                EV.PostInfoLog(Module, $"VM command error");
                return false;
            }

            IMVSLineFindModuTool module1 = (IMVSLineFindModuTool)VmSolution.Instance[$"{ProjectName}.FindEdge1"];
            IMVSLineFindModuTool module2 = (IMVSLineFindModuTool)VmSolution.Instance[$"{ProjectName}.FindEdge2"];
            IMVSLineFindModuTool module3 = (IMVSLineFindModuTool)VmSolution.Instance[$"{ProjectName}.FindEdge3"];
            GlobalVariableModuleTool globalVar = (GlobalVariableModuleTool)VmSolution.Instance["全局变量1"];
            if (globalVar == null || module1 == null || module2 == null || module3 == null) return false;

            if (ProjectName == "FindEdge")
            {
                globalVar.SetGlobalVar("point1x", module1.ModuResult.Midpoint.X.ToString());
                globalVar.SetGlobalVar("point1y", module1.ModuResult.Midpoint.Y.ToString());
                globalVar.SetGlobalVar("point2x", module2.ModuResult.Midpoint.X.ToString());
                globalVar.SetGlobalVar("point2y", module2.ModuResult.Midpoint.Y.ToString());
                globalVar.SetGlobalVar("point3x", module3.ModuResult.Midpoint.X.ToString());
                globalVar.SetGlobalVar("point3y", module3.ModuResult.Midpoint.Y.ToString());
                SampleData[0] = module1.ModuResult.Midpoint.X;
                SampleData[1] = module1.ModuResult.Midpoint.Y;
                SampleData[2] = module2.ModuResult.Midpoint.X;
                SampleData[3] = module2.ModuResult.Midpoint.Y;
                SampleData[4] = module3.ModuResult.Midpoint.X;
                SampleData[5] = module3.ModuResult.Midpoint.Y;
            }
            else if (ProjectName == "FindEdge2")
            {
                globalVar.SetGlobalVar("point1x_2", module1.ModuResult.Midpoint.X.ToString());
                globalVar.SetGlobalVar("point1y_2", module1.ModuResult.Midpoint.Y.ToString());
                globalVar.SetGlobalVar("point2x_2", module2.ModuResult.Midpoint.X.ToString());
                globalVar.SetGlobalVar("point2y_2", module2.ModuResult.Midpoint.Y.ToString());
                globalVar.SetGlobalVar("point3x_2", module3.ModuResult.Midpoint.X.ToString());
                globalVar.SetGlobalVar("point3y_2", module3.ModuResult.Midpoint.Y.ToString());
                SampleData2[0] = module1.ModuResult.Midpoint.X;
                SampleData2[1] = module1.ModuResult.Midpoint.Y;
                SampleData2[2] = module2.ModuResult.Midpoint.X;
                SampleData2[3] = module2.ModuResult.Midpoint.Y;
                SampleData2[4] = module3.ModuResult.Midpoint.X;
                SampleData2[5] = module3.ModuResult.Midpoint.Y;
            }
            
            var ss = $"{module1.ModuResult.Midpoint.X},{module1.ModuResult.Midpoint.Y},{module2.ModuResult.Midpoint.X},{module2.ModuResult.Midpoint.Y},{module3.ModuResult.Midpoint.X},{module3.ModuResult.Midpoint.Y}";
            if (ProjectName == "FindEdge")
            {
                SC.SetItemValue($"{Name}.SampleData", ss);      
            }
            else if (ProjectName == "FindEdge2")
            {
                SC.SetItemValue($"{Name}.SampleData2", ss);     
            }

            return true;
        }

        private bool SetInitSample(double[] sampleArray1,double tolerance1, double[] sampleArray2, double tolerance2)
        {
            if (sampleArray1.Length !=6 || sampleArray2.Length != 6)
            {
                return false;
            }
            GlobalVariableModuleTool globalVar = (GlobalVariableModuleTool)VmSolution.Instance["全局变量1"];
            if (globalVar == null) return false;
            try
            {
                globalVar.SetGlobalVar("point1x", sampleArray1[0].ToString());
                globalVar.SetGlobalVar("point1y", sampleArray1[1].ToString());
                globalVar.SetGlobalVar("point2x", sampleArray1[2].ToString());
                globalVar.SetGlobalVar("point2y", sampleArray1[3].ToString());
                globalVar.SetGlobalVar("point3x", sampleArray1[4].ToString());
                globalVar.SetGlobalVar("point3y", sampleArray1[5].ToString());
                globalVar.SetGlobalVar("tolerance", tolerance1.ToString());
                globalVar.SetGlobalVar("point1x_2", sampleArray2[0].ToString());
                globalVar.SetGlobalVar("point1y_2", sampleArray2[1].ToString());
                globalVar.SetGlobalVar("point2x_2", sampleArray2[2].ToString());
                globalVar.SetGlobalVar("point2y_2", sampleArray2[3].ToString());
                globalVar.SetGlobalVar("point3x_2", sampleArray2[4].ToString());
                globalVar.SetGlobalVar("point3y_2", sampleArray2[5].ToString());
                globalVar.SetGlobalVar("tolerance2", tolerance2.ToString());
            }
            catch (Exception ex)
            {
                return false;
            }
            
            return true;
        }

        private int _count = 0;
        private bool OnTimer()
        {
            if (IsProcessing)
            {
                if (ProjectName!="FindEdge" && ProjectName != "FindEdge2")
                {
                    return true;
                }
                VmProcedure process = (VmProcedure)VmSolution.Instance[ProjectName];
                if (process.IsRunning)
                {
                    _count++;
                    if (_count > 10)
                    {
                        _count = 0;
                        OutputImage = null;
                        CurrentCircle = new double[3] { 0,0,0 };
                        SampleCircle = new double[3] { 0,0,0 };
                        Distance = 0;
                        Result = false;
                        ModuleStatus = false;
                        IsProcessing = false;
                        EV.PostInfoLog(Module, $"VM TimeOver");
                    }
                    return true;
                }
                else
                {
                    try
                    {
                        IMVSCircleFitModuTool module1 = (IMVSCircleFitModuTool)VmSolution.Instance[$"{ProjectName}.圆拟合1"];
                        IMVSCircleFitModuTool module2 = (IMVSCircleFitModuTool)VmSolution.Instance[$"{ProjectName}.圆拟合2"];
                        CalculatorModuleTool module3 = (CalculatorModuleTool)VmSolution.Instance[$"{ProjectName}.变量计算1"];
                        SaveImageTool module4 = (SaveImageTool)VmSolution.Instance[$"{ProjectName}.OutputImage"];
                        IfModuleTool module5 = (IfModuleTool)VmSolution.Instance[$"{ProjectName}.条件检测2"];
                        if (module4.ModuResult.ModuStatus == 1) OutputImage = BitmapToBytes(module4.ModuResult.OutputImage.ToBitmap());
                        else OutputImage = null;

                        if (Command == "WaferPlaceCheck")
                        {
                            PreviewImage1 = OutputImage;
                        }
                        else if (Command == "GroupCheck1")
                        {
                            PreviewImage2 = OutputImage;
                        }
                        else if (Command == "GroupCheck2")
                        {
                            PreviewImage3 = OutputImage;
                        }
                        else if (Command == "GroupCheck3")
                        {
                            PreviewImage4 = OutputImage;
                        }
                        var point1 = module1.ModuResult.OutputCircle.CenterPoint;
                        var radius1 = module1.ModuResult.OutputCircle.Radius;
                        var point2 = module2.ModuResult.OutputCircle.CenterPoint;
                        var radius2 = module2.ModuResult.OutputCircle.Radius;
                        var result = module3.ModuResult.GetOutputFloat("distance").pFloatVal;
                        if (point1 == null || point2 == null || result == null)
                        {
                            CurrentCircle = new double[3] { 0, 0, 0 };
                            SampleCircle = new double[3] { 0, 0, 0 };
                            Distance = 0;
                            Result = false;
                            ModuleStatus = false;
                            IsProcessing = false;
                            EV.PostInfoLog(Module, $"VM Failed");
                            return true;
                        }
                        CurrentCircle = new double[3] { point1.X, point1.Y, radius1 };
                        SampleCircle = new double[3] { point2.X, point2.Y, radius2 };
                        Distance = result.Length == 1 ? result[0] : -1;
                        Result = module5.ModuResult.NIfResult == 1;

                        ModuleStatus = module4.ModuResult.ModuStatus == 1;
                    }
                    catch (Exception ex)
                    {
                        OutputImage = null;
                        CurrentCircle = new double[3] { 0, 0, 0 };
                        SampleCircle = new double[3] { 0, 0, 0 };
                        Distance = 0;
                        Result = false;
                        ModuleStatus = false;
                        IsProcessing = false;
                        EV.PostInfoLog(Module, $"VM Test Failed");
                    }
                    IsProcessing = false;
                }
            }
            else _count = 0;
            return true;
        }

        public byte[] BitmapToBytes(Bitmap bitmap)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                bitmap.Save(ms, ImageFormat.Bmp); // 推荐Bmp格式保证数据完整性:ml-citation{ref="1,5" data="citationList"}
                return ms.ToArray(); // 比GetBuffer()更精确获取有效数据:ml-citation{ref="12" data="citationList"}
            }
        }

        public bool ExecuteGrab(string command)
        {
            if (IsProcessing)
            {
                EV.PostInfoLog(Module, $"VM processing");
                return true;
            }
            var ccd = DEVICE.GetDevice<HikGigeCamera>($"LoadLock.HikGigeCamera");
            if (ccd == null) 
            {
                EV.PostInfoLog(Module, $"ccd no install");
                return true;
            }
            if (ccd.ImageData == null)
            {
                EV.PostInfoLog(Module, $"ccd no picture");
                return true;
            }
            if (command.Contains("WaferPlaceCheck"))
            {
                ProjectName = "FindEdge2";
            }
            else if (command.Contains("GroupCheck"))
            {
                ProjectName = "FindEdge";
            }
            else
            {
                EV.PostInfoLog(Module, $"VM command error");
                return true;
            }

            try
            {
                ModuleStatus = false;
                Result = false;
                VmProcedure process = (VmProcedure)VmSolution.Instance[$"{ProjectName}"];
                ImageSourceModuleTool module = (ImageSourceModuleTool)VmSolution.Instance[$"{ProjectName}.Picture"];
                if (null == process || module == null) return true;

                module.ModuParams.ImageSourceType = ImageSourceParam.ImageSourceTypeEnum.SDK;
                module.SetImageData(ccd.ImageData);

                process.Run(command);
                IsProcessing = true;
                Command = command;
            }
            catch (VmException ex)
            {
                EV.PostAlarmLog(Module, $"Excute VM Procedure Failed {ex}");
                return true;
            }
            return true;
        }

        public bool ExecuteLocalFile(string command)
        {
            if (IsProcessing)
            {
                EV.PostInfoLog(Module, $"VM processing");
                return true;
            }
            try
            {
                if (command.Contains("WaferPlaceCheck"))
                {
                    ProjectName = "FindEdge2";
                }
                else if (command.Contains("GroupCheck"))
                {
                    ProjectName = "FindEdge";
                }
                else
                {
                    EV.PostInfoLog(Module, $"VM command error");
                    return true;
                }
                VmProcedure process = (VmProcedure)VmSolution.Instance[$"{ProjectName}"];
                if (null == process) return true;

                ImageSourceModuleTool module = (ImageSourceModuleTool)VmSolution.Instance[$"{ProjectName}.Picture"];
                if (module.ModuParams.ImageSourceType == ImageSourceParam.ImageSourceTypeEnum.SDK)
                {
                    module.ModuParams.ImageSourceType = ImageSourceParam.ImageSourceTypeEnum.LocalImage;
                    module.ClearAllInputImage();
                    string[] filePaths = Directory.GetFiles(LocalImageFilePath);
                    foreach (var item in filePaths)
                    {
                        module.AddInputImageByPath(item);
                    }
                    module.ModuParams.AutoPlay = true;
                }               

                process.Run(command);
                IsProcessing = true;
                Command = command;
            }
            catch (VmException ex)
            {
                EV.PostAlarmLog(Module, $"Excute VM Procedure Failed {ex}");
                return true;
            }
            return true;
        }

        public void Reset()
        {
            //if (!_isInit)
            //{
            //    return;
            //}
            //LoadSolution();
        }

        private bool LoadSolution()
        {
            LoadFile = false;
            try
            {
                VmSolution.Load(_sol);

                ImageSourceModuleTool module = (ImageSourceModuleTool)VmSolution.Instance["FindEdge.Picture"];
                module.ModuParams.ImageSourceType = ImageSourceParam.ImageSourceTypeEnum.LocalImage;
                module.ClearAllInputImage();
                string[] filePaths = Directory.GetFiles(LocalImageFilePath);
                foreach (var item in filePaths)
                {
                    module.AddInputImageByPath(item);
                }
                module.ModuParams.AutoPlay = true;

                module = (ImageSourceModuleTool)VmSolution.Instance["FindEdge2.Picture"];
                module.ModuParams.ImageSourceType = ImageSourceParam.ImageSourceTypeEnum.LocalImage;
                module.ClearAllInputImage();
                filePaths = Directory.GetFiles(LocalImageFilePath);
                foreach (var item in filePaths)
                {
                    module.AddInputImageByPath(item);
                }
                module.ModuParams.AutoPlay = true;

            }
            catch (Exception ex)
            {
                EV.PostAlarmLog(Module, $"Load VM file {_sol} Failed {ex}");
                return false;
            }

            if (!SetInitSample(SampleData, Tolerance, SampleData2, Tolerance2))
            {
                EV.PostAlarmLog(Module, $"Set SampleData failed");
                return false;
            }

            EV.PostInfoLog(Module, $"Load VisionMaster Success");
            LoadFile = true;
            return true;
        }

        public void Terminate()
        {
            VmSolution.Instance?.Dispose();
        }
    }
}
