using Aitex.Common.Util;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.DBCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using SciChart.Core.Extensions;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using Kxware.Automation.Secs;
using Kxware.Common;
using Kxware.Connectivity.Remoting;
using Kxware.ToolAutomation;

namespace MECF.Framework.Common.Gem
{
    public class GemManager : Singleton<GemManager>
    {
        public string PPIDNoExtension { get; set; }

        public string PPID_CassAL { get; set; }

        public string PPID_CassAR { get; set; }

        public string LotID_CassAL { get; set; }

        public string LotID_CassAR { get; set; }

        public string SelectSlotID_CassAL { get; set; }

        public string SelectSlotID_CassAR { get; set; }

        public string LotID { get; set; }

        private string JobID = "";

        private string RtStatus => DATA.Poll("Rt.Status").ToString();

        private bool SystemIsOnline => bool.Parse(DATA.Poll("System.IsOnline").ToString());

        private bool LoadLockIsOnline => bool.Parse(DATA.Poll("LoadLock.IsOnline").ToString());

        private bool CassALIsOnline => bool.Parse(DATA.Poll("CassAL.IsOnline").ToString());
        private bool CassARIsOnline => bool.Parse(DATA.Poll("CassAR.IsOnline").ToString());
        private bool CassBLIsOnline => bool.Parse(DATA.Poll("CassBL.IsOnline").ToString());

        private Kxware.ToolAutomation.Equipment _equipment;
        public Kxware.ToolAutomation.Equipment Equipment => _equipment;

        private PeriodicJob _monitorJob;

        public string CommunicationState => _equipment?.GetCommunicationState().ToString();

        public string ControlMode => _equipment?.GetControlState().ToString();

        public string SequenceRecipeContent { get; set; }

        public string RecvMsgFromHost { get; set; }

        public string ProgramLog { get; set; }

        public string SecsLog { get; set; }

        public List<string> AlarmInfoList { get; set; } = new List<string>();

        public List<string> EventInfoList { get; set; } = new List<string>();

        public List<string> SequenceRecipeNameList => _equipment?.GetRecipeList(_equipment.MasterConnectionName);

        public List<string> CoatingNameList;

        public List<Kxware.Connectivity.Remoting.VariableData> VariableList
        {
            get
            {
                var result = _equipment?.GetVariables()?.Select(p => new Kxware.Connectivity.Remoting.VariableData()
                {
                    ConnectionName = p.ConnectionName,
                    SmlValue = p.GetSecsValue().ToSML(SmlFormat.RoundBracket),
                    Default = p.Default?.ToString(),
                    Description = p.Description,
                    HostVisible = p.HostVisible,
                    Id = p.Id,
                    IsCommonVariable = p.IsCommonVariable,
                    LimitEventName = p.LimitEvent?.Name,
                    Name = p.Name,
                    Max = p.Max?.ToString(),
                    Min = p.Min?.ToString(),
                    Persistent = p.Persistent,
                    Unit = p.Unit,
                    VariableType = (enumVariableTypes)p.VariableType
                }).ToList();

                return result;
            }
        }

        public List<Kxware.Connectivity.Remoting.EventData> EventList
        {
            get
            {
                var result = _equipment?.GetEvents()?.Select(p => new Kxware.Connectivity.Remoting.EventData()
                {
                    EventName = p.Name,
                    EventId = p.Id,
                    Description = p.Description
                }).ToList();

                return result;
            }
        }

        public List<Kxware.Connectivity.Remoting.AlarmData> AlarmList
        {
            get
            {
                var result = _equipment?.GetAlarms()?.Select(p => new Kxware.Connectivity.Remoting.AlarmData()
                {
                    Name = p.Name,
                    AlarmID = p.ALID,
                    ALCD = p.ALCD,
                    AlarmText = p.ALTX,
                    Description = p.Description
                }).ToList();

                return result;
            }
        }

        public void Initialize()
        {
            try
            {
                //注册
                DATA.Subscribe("GEM.CommunicationState", () => CommunicationState);
                DATA.Subscribe("GEM.ControlMode", () => ControlMode);
                DATA.Subscribe("GEM.VariableList", () => VariableList);
                DATA.Subscribe("GEM.EventList", () => EventList);
                DATA.Subscribe("GEM.EventInfoList", () => EventInfoList);
                DATA.Subscribe("GEM.AlarmList", () => AlarmList);
                DATA.Subscribe("GEM.AlarmInfoList", () => AlarmInfoList);
                DATA.Subscribe("GEM.SequenceRecipeNameList", () => SequenceRecipeNameList);
                DATA.Subscribe("GEM.SequenceRecipeContent", () => SequenceRecipeContent);
                DATA.Subscribe("GEM.RecvMsgFromHost", () => RecvMsgFromHost);
                DATA.Subscribe("GEM.ProgramLog", () => ProgramLog);
                DATA.Subscribe("GEM.SecsLog", () => SecsLog);
                DATA.Subscribe("GEM.PPID", () => PPIDNoExtension);
                DATA.Subscribe("GEM.LotID", () => LotID);

                DATA.Subscribe("GEM.PPID_CassAL", () => PPID_CassAL);
                DATA.Subscribe("GEM.LotID_CassAL", () => LotID_CassAL);
                DATA.Subscribe("GEM.PPID_CassAR", () => PPID_CassAR);
                DATA.Subscribe("GEM.LotID_CassAR", () => LotID_CassAR);
                DATA.Subscribe("GEM.SelectSlotID_CassAL", () => SelectSlotID_CassAL);
                DATA.Subscribe("GEM.SelectSlotID_CassAR", () => SelectSlotID_CassAR);

                OP.Subscribe($"GEM_SetSoftwareVersion", (string cmd, object[] args) => SetSoftwareVersion((string)args[0]));
                OP.Subscribe($"GEM_SetEnable", (string cmd, object[] args) => SetEnable((bool)args[0]));
                OP.Subscribe($"GEM_SetControlMode", (string cmd, object[] args) => SetControlMode(args[0].ToString()));
                OP.Subscribe($"GEM_SelectSequenceRecipeChanged", (string cmd, object[] args) => SelectSequenceRecipeChanged(args[0].ToString()));
                OP.Subscribe($"GEM_TerminalMessageConfirm", (string cmd, object[] args) => TerminalMessageConfirm());
                OP.Subscribe($"GEM_SendMessageToHost", (string cmd, object[] args) => SendMessageToHost(args[0].ToString()));
                OP.Subscribe($"GEM_ClearProgramLog", (string cmd, object[] args) => ClearProgramLog());
                OP.Subscribe($"GEM_ClearSecsLog", (string cmd, object[] args) => ClearSecsLog());
                OP.Subscribe($"GEM_ClearAllAlarm", (string cmd, object[] args) => ClearAllAlarm());
                OP.Subscribe($"GEM_ClearModuleAlarm", (string cmd, object[] args) => ClearModuleAlarm(args[0].ToString()));
                OP.Subscribe($"GEM_PPChange", (string cmd, object[] args) => PPChange(args));

                OP.Subscribe($"GEM_UpdateCoating", (string cmd, object[] args) => UpdateCoating(args));
                OP.Subscribe($"GEM_GrowCoating", (string cmd, object[] args) => GrowCoating(args));

                if (!SC.GetValue<bool>("Gem.Enable"))
                {
                    return;
                }

                string equipmentName = SC.GetStringValue("System.EquipmentName");
                int equipmentNo = SC.GetValue<int>("System.EquipmentNo");
                _equipment = new Kxware.ToolAutomation.Equipment("SicEquipment");

                //_equipment.RegisteringVariables += new RegisterVariableDelegate(RegisteringVariables);

                //_equipment.RegisteringAlarms += new RegisterAlarmDelegate(RegisteringAlarms);

                //initialize SECS/ GEM service from configruation file
                _equipment.Initialize(PathManager.GetCfgDir() + "Gem.exml");

                #region 设置变量

                //设置内置名称,软件版本等SV
                _equipment.SetValue("MDLN", "Sic");
                _equipment.SetValue("Manufacturer", "Sicentury");
                _equipment.SetValue("EqpModel", equipmentName);
                _equipment.SetValue("EqpSerialNum", equipmentNo.ToString());

                //设置Recipes路径
                _equipment.SetValue("PPDirectory", @"../SicRT/Recipes");
                _equipment.SetValue("PPFileExtension", "seq,rcp");

                //设置PPFormat
                _equipment.SetValue("PPFormat", 1);

                //设置Log路径
                //Log.SetLoggingDirectory("");

                #endregion

                #region 回调

                _equipment.AlarmSET += new OnAlarmSET(AlarmSET);
                _equipment.AlarmCLEAR += new OnAlarmCLEAR(AlarmCLEAR);

                //Kxware.Common.Log.NewMessage += Log_NewMessage;

                //_equipment.DataMessageReceived += DataMessageReceived;
                //_equipment.DataMessageSent += DataMessageSent;

                _equipment.TerminalMessageReceived += TerminalMessageReceived;

                //注册远程操作指令
                _equipment.RegisterRemoteCommandHandler("GO-LOCAL", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("GO-REMOTE", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("PP-SELECT", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("CREATE-JOB", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("START", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("ABORT", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("STOP", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("Online", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("Offline", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("CreateWafer", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("CreateTray", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("DeleteWafer", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("DeleteTray", OnReceivedRemoteCommand);
                _equipment.RegisterRemoteCommandHandler("Mapping", OnReceivedRemoteCommand);

                _equipment.EventTriggered += EventTriggered;

                //register custom SECS message
                _equipment.RegisterMessageHandler(7, 7, HandleS7F7);

                //Variable value change callback 
                var allHostECs = _equipment.GetVariables().FindAll(p => p.HostVisible && p.VariableType == VariableType.EC);
                allHostECs.ForEach(v =>
                {
                    v.AdvancedValueChanged += Variable_AdvancedValueChanged;
                });

                #endregion

                //enable GEM
                _equipment.GemEnable();
                _equipment.OnlineLocal(_equipment.MasterConnectionName);

                CoatingNameList = new List<string> { "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8",
                    "B1", "B2", "B3", "B4","B5", "B6", "B7", "B8" };
                GetCoating();

                _monitorJob = new PeriodicJob(1000, Monitor, "GEM_Monitor", true);
            }
            catch (Exception ex)
            {
                //LOG.Error(ex.Message,ex);
            }
        }

        public void GetCoating()
        {
            try
            {
                foreach (string name in CoatingNameList)
                {
                    string cmd = $"select * from tray_thickness_main where tray_number = '{name}' order by create_time desc";

                    DataSet dataSet = DB.ExecuteDataSet(cmd);
                    if (dataSet != null && dataSet.Tables.Count != 0 && dataSet.Tables[0].Rows.Count != 0)
                    {
                        double coating = double.Parse(dataSet.Tables[0].Rows[0]["tray_coating_thickness"].ToString());

                        double coatingMax = double.Parse(dataSet.Tables[0].Rows[0]["tray_max_thickness"].ToString());

                        UpdateCoating(name, coating, coatingMax);
                    }
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message,ex);
            }
        }

        public bool UpdateCoating(params object[] args)
        {
            string name = args[0].ToString();
            object value = args[1];
            object max = args[2];

            if(CoatingNameList.Contains(name))
            {
                _equipment?.SetValue(name + "Coating", value);
                _equipment?.SetValue(name + "CoatingMax", max);

                return true;
            }

            return false;
        }

        public bool GrowCoating(params object[] args)
        {
            string name = args[0].ToString();
            double grow = double.Parse(args[1].ToString());

            if (CoatingNameList.Contains(name))
            {
                double originValue =double.Parse(_equipment.GetValue(name + "Coating",0).ToString());
                _equipment?.SetValue(name + "Coating", originValue + grow);

                return true;
            }

            return false;
        }

        private void Variable_AdvancedValueChanged(Variable variable, SecsValue oldValue, SecsValue newValue, enumSource source)
        {
            //由Host主机修改的EC
            if (source == enumSource.Host)
            {

            }
        }

        private void HandleS7F7(DataMessage message)
        {
            //实现对S7F7的解析处理
            var node = (SecsAscii)message.Body;
            var MID = node.GetValueAsString();
            Kxware.Common.Log.Info("GEM", $"Received S7F7:\r\n{message.ToSML(SmlFormat.Standard)}");

            //回复消息分类
            {
                //无异常
                var s7f8 = new ReplyMessage(message);
                var l = new SecsList();
                l.AddChild(new SecsU4(0));
                l.AddChild(new SecsBoolean(true));
                s7f8.Body = l;
                _equipment?.SendMessage(_equipment.MasterConnectionName, s7f8);
            }

            //{
            //    //Unrecognized device ID(无法识别的设备ID)
            //    var s9f1 = new ReplyMessage(message);
            //    _equipment.SendMessage(_equipment.MasterConnectionName, s9f1);
            //}

            //{
            //    //Unrecognized stream type(无法识别的流类型)
            //    var s9f3 = new ReplyMessage(message);
            //    _equipment.SendMessage(_equipment.MasterConnectionName, s9f3);
            //}

            //{
            //    //Unrecognized function type(无法识别的函数类型)
            //    var s9f5 = new ReplyMessage(message);
            //    _equipment.SendMessage(_equipment.MasterConnectionName, s9f5);
            //}

            //{
            //    //Illegal data(非法数据)
            //    var s9f7 = new ReplyMessage(message);
            //    _equipment.SendMessage(_equipment.MasterConnectionName, s9f7);
            //}

            //{
            //    //Transaction timer timeout(事务定时器超时)
            //    var s9f5 = new ReplyMessage(message);
            //    _equipment.SendMessage(_equipment.MasterConnectionName, s9f5);
            //}

            //{
            //    //Conversation timeout(会话超时)
            //    var s9f5 = new ReplyMessage(message);
            //    _equipment.SendMessage(_equipment.MasterConnectionName, s9f5);
            //}
        }

        private void HandleS7F65(DataMessage message)
        {
            //实现对S7F65的解析处理
            var listNode = (SecsList)message.Body;
            var ppID = listNode[0].GetValueAsString();
            var pmID = listNode[1].GetValueAsString();
            //TODO: perform the command
            var s7f66 = new ReplyMessage(message);
            s7f66.Body = new SecsBinary(0);
            _equipment.SendMessage(_equipment.MasterConnectionName, s7f66);
        }

        private void SendCustomMessage()
        {
            var s99f1 = new DataMessage(99, 1, true);
            var list1 = new SecsList();
            list1.AddChild(new SecsAscii("SMIFReady"));
            list1.AddChild(new SecsList());
            s99f1.Body = list1;

            _equipment.SendMessage(_equipment.MasterConnectionName, s99f1);
        }

        private bool Monitor()
        {
            try
            {
                //设置变量值
                //SetValue();

                SetXmlValue();

                return true;
            }
            catch (Exception ex)
            {
                Kxware.Common.Log.Error(ex.Source, ex.Message, ex);
                LOG.Error(ex.Message, ex);
                return false;
            }
        }

        //设置GEM配置文件中变量的值
        private void SetXmlValue()
        {
            try
            {
                SortedDictionary<string, Func<object>> keyValues = Singleton<DataManager>.Instance.GetDBRecorderList();

                foreach (Variable variable in _equipment.GetVariables())
                {
                    if (variable.VariableType == VariableType.SV)
                    {
                        if (keyValues.ContainsKey(variable.Name))
                        {
                            _equipment?.SetValue(variable.Name, keyValues[variable.Name]());
                        }
                        else
                        {
                            //排除Gem 内置变量
                            if (variable.Id > 10000)
                            {
                                //LOG.Warning($"DATA no Contain Gem Varibable name {variable.Name}");
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message, ex);
            }
        }

        private void SetValue()
        {
            SortedDictionary<string, Func<object>> keyValues = Singleton<DataManager>.Instance.GetDBRecorderList();

            foreach (KeyValuePair<string, Func<object>> item in keyValues)
            {
                //判断类型,排除引用类型
                object obj = item.Value();
                if (obj != null)
                {
                    Type type = obj.GetType();
                    if (type == typeof(bool) || type == typeof(double) || type == typeof(float) || type == typeof(int) || type == typeof(ushort) ||
                        type == typeof(short) || type == typeof(long) || type == typeof(string))
                    {
                        _equipment?.SetValue(item.Key, obj);
                    }
                }
            }
        }

        private IEnumerable<VariableDefinition> RegisteringVariables()
        {
            List<VariableDefinition> variableDefinitionList = new List<VariableDefinition>();

            int index = 0;

            SortedDictionary<string, Func<object>> keyValues = Singleton<DataManager>.Instance.GetDBRecorderList();

            foreach (KeyValuePair<string, Func<object>> item in keyValues)
            {
                //判断类型,排除引用类型
                object obj = item.Value();
                if (obj != null)
                {
                    Type type = obj.GetType();
                    if (type == typeof(bool) || type == typeof(double) || type == typeof(float) || type == typeof(int) || type == typeof(ushort) ||
                        type == typeof(short) || type == typeof(long) || type == typeof(string))
                    {
                        ValueFormat valueFormat = ValueFormat.F8;

                        if (type == typeof(bool))
                        {
                            valueFormat = ValueFormat.BOOLEAN;
                        }
                        else if (type == typeof(int))
                        {
                            valueFormat = ValueFormat.I8;
                        }
                        else if (type == typeof(long))
                        {
                            valueFormat = ValueFormat.I8;
                        }
                        else if (type == typeof(short))
                        {
                            valueFormat = ValueFormat.I8;
                        }
                        else if (type == typeof(ushort))
                        {
                            valueFormat = ValueFormat.U8;
                        }
                        else if (type == typeof(float))
                        {
                            valueFormat = ValueFormat.F4;
                        }
                        else if (type == typeof(double))
                        {
                            valueFormat = ValueFormat.F4;
                        }
                        else if (type == typeof(string))
                        {
                            valueFormat = ValueFormat.A;
                        }

                        variableDefinitionList.Add(new VariableDefinition(Kxware.Common.VariableType.SV, valueFormat, (ulong)(1100000 + index), item.Key, (string)null, (string)null, (string)null, (string)null, (string)null, false, true, ""));

                        index++;
                    }
                }
            }

            return variableDefinitionList;
        }

        private IEnumerable<AlarmDefinition> RegisteringAlarms()
        {
            List<AlarmDefinition> alarmDefinitionList = new List<AlarmDefinition>();

            int index = 0;

            SortedDictionary<string, Func<object>> keyValues = Singleton<DataManager>.Instance.GetDBRecorderList();

            foreach (KeyValuePair<string, Func<object>> item in keyValues)
            {
                //alarmDefinitionList.Add(new AlarmDefinition((ulong)(1000000 + index),));

                index++;
            }

            return alarmDefinitionList;
        }

        private void AlarmSET(string equipmentName, string connectionName, ulong alarmID, string alarmName, string altx, Kxware.Common.AlarmCode alcd, string alarmDescription, string alarmAdditionalInformation, string setEvent, string clearEvent, DateTime occurredTime, Kxware.Common.VariableData[] associatedVariables, DataMessage alarmSecsMessage)
        {
            if (connectionName == _equipment.MasterConnectionName)
            {
                AlarmInfoList.Add($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} 【触发】 ID:{alarmID} {altx}");
                if (AlarmInfoList.Count > 30)
                {
                    AlarmInfoList.RemoveAt(0);
                }
            }
        }

        private void AlarmCLEAR(string equipmentName, string connectionName, ulong alarmID, string alarmName, string altx, Kxware.Common.AlarmCode alcd, string alarmDescription, string alarmAdditionalInformation, string setEvent, string clearEvent, DateTime occurredTime, Kxware.Common.VariableData[] associatedVariables, DataMessage alarmSecsMessage)
        {
            if (connectionName == _equipment.MasterConnectionName)
            {
                AlarmInfoList.Add($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} 【清除】 ID:{alarmID} {altx}");
                if (AlarmInfoList.Count > 30)
                {
                    AlarmInfoList.RemoveAt(0);
                }
            }
        }

        private void DataMessageSent(string equipmentName, string connectionName, DateTime time, Kxware.Automation.Secs.DataMessage message)
        {
            if (connectionName == _equipment.MasterConnectionName)
            {
                string msg = $"{time.ToString("yyyy/MM/dd HH:mm:ss.fff")} 【发送】\r\n{message.ToSML()}\r\n";
                //Kxware.Common.Log.Info("GEM", msg);
                SecsLog += msg;

                if (SecsLog.Length > 3000)
                {
                    SecsLog = SecsLog.Substring(SecsLog.Length - 3000);
                }
            }
        }

        private void Log_NewMessage(LogType loggingType, string customizedLogTypeName, DateTime timeStamp, string processName, int threadID, string source, string message)
        {
            try
            {
                // make a filter, do not show SML logging message at current window
                if (message.Contains("SECS MSG Recv") || message.Contains("SECS MSG Sent"))
                {
                    return;
                }

                ProgramLog += $"{timeStamp.ToString("yyyy/MM/dd HH:mm:ss,fff")} {source} 线程ID:{threadID} 内容:{message}\r\n";

                if (ProgramLog.Length > 3000)
                {
                    ProgramLog = ProgramLog.Substring(ProgramLog.Length - 3000);
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message, ex);
            }
        }

        private void DataMessageReceived(string equipmentName, string connectionName, DateTime time, DataMessage message)
        {
            try
            {
                if (connectionName == _equipment.MasterConnectionName)
                {
                    string msg = $"{time.ToString("yyyy/MM/dd HH:mm:ss.fff")} 【接受】\r\n{message.ToSML()}\r\n";
                    //Kxware.Common.Log.Info("GEM", msg);
                    SecsLog += msg;

                    if (SecsLog.Length > 3000)
                    {
                        SecsLog = SecsLog.Substring(SecsLog.Length - 3000);
                    }
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message, ex);
            }
        }

        private void EventTriggered(string equipmentName, string connectionName, ulong eventID, string eventName, string eventDescription, Kxware.Common.VariableData[] associatedVariables,DataMessage eventSecsMessage)
        {
            try
            {
                if (connectionName == _equipment.MasterConnectionName)
                {
                    var associatedDataInfo = "";
                    if (associatedVariables.Length > 0)
                    {
                        associatedDataInfo = "关联数据：" + string.Join(",", associatedVariables.Select(p => p.Name + " " + p.Value.ToSML(SmlFormat.RoundBracket)));
                    }
                    EventInfoList.Add($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} 编号:{eventID} 事件名:{eventName} {associatedDataInfo}");

                    if(EventInfoList.Count > 30)
                    {
                        EventInfoList.RemoveAt(0);
                    }
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message, ex);
            }
        }

        private enumRemoteCommandAckCode OnReceivedRemoteCommand(string connectionName, string objSpec, string remoteCommand, List<RemoteCommandParameter> remoteCommandParameters)
        {
            try
            {
                Kxware.Common.Log.Info("GEM", $"Received {remoteCommand} command.");

                //只接受从MasterConnection 收到的控制命令
                if (connectionName != _equipment.MasterConnectionName)
                    return enumRemoteCommandAckCode.CannotPerformNow;

                //判断控制状态，在Local 状态下只接受GO-REMOTE命令
                var currentCtrlState = _equipment.GetControlState();
                if (currentCtrlState != GEMControlStates.Online_Remote)
                {
                    if (remoteCommand.ToUpper() != "GO-REMOTE")
                        return enumRemoteCommandAckCode.CannotPerformNow;
                }

                var result = enumRemoteCommandAckCode.NoSuchObjectExists;
                switch (remoteCommand)
                {
                    case "GO-LOCAL":
                        {
                            if (currentCtrlState == GEMControlStates.Online_Remote)
                            {
                                _equipment.OnlineLocal(_equipment.MasterConnectionName);
                                result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                            }
                            else
                                result = enumRemoteCommandAckCode.RejectedAlreadyInDesiredCondition;
                        }
                        break;

                    case "GO-REMOTE":
                        {
                            if (currentCtrlState == GEMControlStates.Online_Remote)
                            {
                                result = enumRemoteCommandAckCode.RejectedAlreadyInDesiredCondition;
                            }
                            else if (!_equipment.OnlineRemote(_equipment.MasterConnectionName, out string error))
                                result = enumRemoteCommandAckCode.CannotPerformNow;
                            else
                                result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                        }
                        break;

                    //PP-SELECT指令附加参数(PPID&LotID)
                    case "PP-SELECT":
                        {
                            try
                            {
                                if (RtStatus != "AutoIdle" && RtStatus != "AutoRunning")
                                {
                                    Kxware.Common.Log.Warn("GEM", $"Cannot perform 'PP-SELECT' command. Equipment State is not in AutoIdle or AutoRunning.");
                                    result = enumRemoteCommandAckCode.CannotPerformNow;
                                }
                                else if (remoteCommandParameters.Find(p => p.CPNAME == "PPID") == null)
                                {
                                    Kxware.Common.Log.Warn("GEM", $"Cannot perform 'PP-SELECT' command. PPID is not specified.");
                                    result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
                                }
                                else if (remoteCommandParameters.Find(p => p.CPNAME == "LotID") == null)
                                {
                                    Kxware.Common.Log.Warn("GEM", $"Cannot perform 'PP-SELECT' command. LotID is not specified.");
                                    result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
                                }
                                else
                                {
                                    string PPID = remoteCommandParameters.Find(p => p.CPNAME == "PPID").CPVAL.GetValueAsString();
                                    PPIDNoExtension = PPID.Replace(@"Sequence\", "").Replace(".seq", "");
                                    LotID = remoteCommandParameters.Find(p => p.CPNAME == "LotID").CPVAL.GetValueAsString();

                                    Kxware.Common.Log.Info("GEM", $"Received 'PP-SELECT' command. PPID={PPID}, LotID={LotID}");

                                    result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                                }
                            }
                            catch (Exception)
                            {
                                result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
                            }
                        }
                        break;

                    //CREATE-JOB指令没有附加参数
                    case "CREATE-JOB":
                        {
                            if (RtStatus != "AutoIdle" && RtStatus != "AutoRunning")
                            {
                                Kxware.Common.Log.Warn("GEM", $"Cannot perform 'CREATE-JOB' command. Equipment State is not in AutoIdle or AutoRunning.");
                                result = enumRemoteCommandAckCode.CannotPerformNow;
                            }
                            else if (!SystemIsOnline)
                            {
                                Kxware.Common.Log.Warn("GEM", $"Cannot perform 'CREATE-JOB' command. Equipment System is not online.");
                                result = enumRemoteCommandAckCode.CannotPerformNow;
                            }
                            else if (!LoadLockIsOnline)
                            {
                                Kxware.Common.Log.Warn("GEM", $"Cannot perform 'CREATE-JOB' command. Equipment LoadLock is not online.");
                                result = enumRemoteCommandAckCode.CannotPerformNow;
                            }
                            else
                            {
                                //自动设备
                                if (remoteCommandParameters.Find(p => p.CPNAME == "CarrierID") != null)
                                {
                                    string ppID = remoteCommandParameters.Find(p => p.CPNAME == "PPID").CPVAL.GetValueAsString();
                                    string ppIDNoExtension = ppID.Replace(@"Sequence\", "").Replace(".seq", "");
                                    string lotID = remoteCommandParameters.Find(p => p.CPNAME == "LotID").CPVAL.GetValueAsString();

                                    string carrierID = remoteCommandParameters.Find(p => p.CPNAME == "CarrierID").CPVAL.GetValueAsString();
                                    string selectSlotID = remoteCommandParameters.Find(p => p.CPNAME == "SelectSlotID").CPVAL.GetValueAsString();

                                    string jobID = remoteCommandParameters.Find(p => p.CPNAME == "JobID").CPVAL.GetValueAsString();

                                    Kxware.Common.Log.Info("GEM", $"Received 'CREATE-JOB' command. CarrierID={carrierID}, PPID={ppID},LotID={lotID},SelectSlotID={selectSlotID}");

                                    if (selectSlotID.Split(',').Count() != 25)
                                    {
                                        result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
                                        break;
                                    }

                                    List<string> ppIDList = new List<string>();
                                    string[] slotArray = selectSlotID.Split(',');
                                    slotArray.ForEachDo(slot =>
                                    {
                                        if (int.TryParse(slot, out int slotID))
                                        {
                                            if (slotID == 1)
                                            {
                                                ppIDList.Add(ppIDNoExtension);
                                            }
                                            else
                                            {
                                                ppIDList.Add(string.Empty);
                                            }
                                        }
                                    });
                                   

                                    if (carrierID == "CassAL")
                                    {
                                        PPID_CassAL = ppIDNoExtension;
                                        LotID_CassAL = lotID;
                                        SelectSlotID_CassAL = selectSlotID;

                                        Dictionary<string, object> dictionary = new Dictionary<string, object>
                                     {
                                         { "JobId",  jobID},
                                         { "Module", carrierID },
                                         {"SlotSequence",ppIDList.ToArray()},
                                         { "LotId", lotID },
                                         { "AutoStart", true }
                                     };

                                        OP.DoOperation("System.CreateJob", dictionary);
                                    }
                                    else if (carrierID == "CassAR")
                                    {
                                        PPID_CassAR = ppIDNoExtension;
                                        LotID_CassAR = lotID;
                                        SelectSlotID_CassAR = selectSlotID;

                                        Dictionary<string, object> dictionary = new Dictionary<string, object>
                                     {
                                         { "JobId",  jobID},
                                         { "Module", carrierID },
                                         {"SlotSequence",ppIDList.ToArray()},
                                         { "LotId", lotID },
                                         { "AutoStart", true }
                                     };

                                        OP.DoOperation("System.CreateJob", dictionary);
                                    }
                                    else
                                    {
                                        result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
                                    }
                                }
                                else
                                {
                                    //具体操作
                                    JobID = "CJ_Remote_" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                                    //手动设备
                                    Dictionary<string, object> dictionary = new Dictionary<string, object>
                                     {
                                         { "JobId",  JobID},
                                         { "Module", "LoadLock" },
                                         {"SlotSequence",new string[]{PPIDNoExtension} },
                                         { "LotId", LotID },
                                         { "AutoStart", true }
                                     };

                                    OP.DoOperation("System.CreateJob", dictionary);
                                }

                                result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                            }
                        }
                        break;

                    //START指令
                    case "START":
                        {
                            if (RtStatus != "AutoIdle" && RtStatus != "AutoRunning")
                            {
                                Kxware.Common.Log.Warn("GEM", $"Cannot perform 'STRAT' command. Equipment State is not in AutoIdle or AutoRunning.");
                                result = enumRemoteCommandAckCode.CannotPerformNow;
                            }
                            else if(!SystemIsOnline)
                            {
                                Kxware.Common.Log.Warn("GEM", $"Cannot perform 'STRAT' command. Equipment System is not online.");
                                result = enumRemoteCommandAckCode.CannotPerformNow;
                            }
                            else if (!LoadLockIsOnline)
                            {
                                Kxware.Common.Log.Warn("GEM", $"Cannot perform 'CREATE-JOB' command. Equipment LoadLock is not online.");
                                result = enumRemoteCommandAckCode.CannotPerformNow;
                            }
                            else
                            {
                                string jobID = string.Empty;
                                //自动设备
                                if (remoteCommandParameters.Find(p => p.CPNAME == "JobID") != null)
                                {
                                    jobID = remoteCommandParameters.Find(p => p.CPNAME == "JobID").CPVAL.GetValueAsString();
                                }
                                else
                                {
                                    jobID = JobID;
                                }

                                //具体操作
                                OP.DoOperation("System.StartJob", jobID);

                                result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                            }
                        }
                        break;

                    //ABORT指令没有附加参数
                    case "ABORT":
                    case "STOP":
                        {
                            if (RtStatus != "AutoRunning")
                            {
                                Kxware.Common.Log.Warn("GEM", $"Cannot perform 'ABORT' command. Equipment State is not in AutoRunning.");
                                result = enumRemoteCommandAckCode.CannotPerformNow;
                            }
                            else
                            {
                                //具体操作
                                OP.DoOperation("System.Abort");

                                result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                            }
                        }
                        break;

                    //Online指令附加参数(ModuleID)
                    case "Online":
                        {
                            string module = remoteCommandParameters.Find(p => p.CPNAME == "ModuleID").CPVAL.GetValueAsString();
                            OP.DoOperation($"{module}.SetOnline");

                            result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                        }
                        break;

                    //Offline指令附加参数(ModuleID)
                    case "Offline":
                        {
                            string module = remoteCommandParameters.Find(p => p.CPNAME == "ModuleID").CPVAL.GetValueAsString();
                            OP.DoOperation($"{module}.SetOffline");

                            result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                        }
                        break;

                    //CreateWafer指令附加参数(ModuleID,SlotID)
                    case "CreateWafer":
                        {
                            string module = remoteCommandParameters.Find(p => p.CPNAME == "ModuleID").CPVAL.GetValueAsString();
                            int slot = remoteCommandParameters.Find(p => p.CPNAME == "SlotID").CPVAL.GetValueAsInt(0);
                            OP.DoOperation($"CreateWafer", module, slot);

                            result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                        }
                        break;

                    //CreateTray指令附加参数(ModuleID,SlotID)
                    case "CreateTray":
                        {
                            string module = remoteCommandParameters.Find(p => p.CPNAME == "ModuleID").CPVAL.GetValueAsString();
                            int slot = remoteCommandParameters.Find(p => p.CPNAME == "SlotID").CPVAL.GetValueAsInt(0);
                            OP.DoOperation($"CreateTray", module, slot);

                            result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                        }
                        break;

                    //DeleteWafer指令附加参数(ModuleID,SlotID)
                    case "DeleteWafer":
                        {
                            string module = remoteCommandParameters.Find(p => p.CPNAME == "ModuleID").CPVAL.GetValueAsString();
                            int slot = remoteCommandParameters.Find(p => p.CPNAME == "SlotID").CPVAL.GetValueAsInt(0);
                            OP.DoOperation($"DeleteWafer", module, slot);

                            result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                        }
                        break;

                    //DeleteTray指令附加参数(ModuleID)
                    case "DeleteTray":
                        {
                            string module = remoteCommandParameters.Find(p => p.CPNAME == "ModuleID").CPVAL.GetValueAsString();
                            int slot = remoteCommandParameters.Find(p => p.CPNAME == "SlotID").CPVAL.GetValueAsInt(0);
                            OP.DoOperation($"DeleteTray", module, slot);

                            result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                        }
                        break;

                    case "Mapping":
                        {
                            string carrierID = remoteCommandParameters.Find(p => p.CPNAME == "CarrierID").CPVAL.GetValueAsString();

                            if (carrierID != "CassAL" && carrierID != "CassAR" && carrierID != "CassBL")
                            {
                                Kxware.Common.Log.Warn("GEM", $"Cannot perform 'Mapping' command. CarrierID Error");
                                result = enumRemoteCommandAckCode.AtLeastOneParameterIsInvalid;
                            }
                            //else if (carrierID == "CassAL" && CassALIsOnline)
                            //{
                            //    Kxware.Common.Log.Warn("GEM", $"Cannot perform 'Mapping' command. CassAL is online.");
                            //    result = enumRemoteCommandAckCode.CannotPerformNow;
                            //}
                            //else if (carrierID == "CassAR" && CassARIsOnline)
                            //{
                            //    Kxware.Common.Log.Warn("GEM", $"Cannot perform 'Mapping' command. CassAR is online.");
                            //    result = enumRemoteCommandAckCode.CannotPerformNow;
                            //}
                            //else if (carrierID == "CassBL" && CassBLIsOnline)
                            //{
                            //    Kxware.Common.Log.Warn("GEM", $"Cannot perform 'Mapping' command. CassBL is online.");
                            //    result = enumRemoteCommandAckCode.CannotPerformNow;
                            //}
                            else
                            {
                                if (carrierID == "CassAL" || carrierID == "CassAR")
                                {
                                    OP.DoOperation("WaferRobot.MapWafer", carrierID);
                                }
                                else if (carrierID == "CassBL")
                                {
                                    OP.DoOperation("TrayRobot.MapTray", carrierID);
                                }

                                result = enumRemoteCommandAckCode.AcknowledgeCommandPerformed;
                            }
                        }
                        break;

                    default:
                        {
                            Kxware.Common.Log.Error("GEM", $"Un-handled remote command: {remoteCommand}");
                        }

                        break;
                }

                return result;
            }
            catch (Exception)
            {
                return enumRemoteCommandAckCode.CannotPerformNow;
            }
        }

        private bool SetSoftwareVersion(string softwareVersion)
        {
            _equipment.SetValue("SOFTREV", softwareVersion);

            return true;
        }

        private bool SetEnable(bool enable)
        {
            if (enable)
            {
                _equipment.GemEnable();
            }
            else
            {
                _equipment.GemDisable();
            }

            return true;
        }

        private bool SetControlMode(string mode)
        {
            switch (mode)
            {
                case "OnlineRemote":
                    {
                        _equipment?.OnlineRemote(_equipment.MasterConnectionName);
                    }
                    break;

                case "OnlineLocal":
                    {
                        _equipment?.OnlineLocal(_equipment.MasterConnectionName);
                    }
                    break;

                case "Offline":
                    {
                        _equipment?.Offline(_equipment.MasterConnectionName);
                    }
                    break;
            }

            return true;
        }

        private bool SelectSequenceRecipeChanged(string sequenceRecipeName)
        {
            if (!string.IsNullOrEmpty(sequenceRecipeName))
            {
                SequenceRecipeContent = File.ReadAllText(".\\Recipes\\" + sequenceRecipeName);
            }

            return true;
        }

        private bool ClearProgramLog()
        {
            ProgramLog = "";

            return true;
        }

        private bool ClearSecsLog()
        {
            SecsLog = "";

            return true;
        }

        private bool ClearAllAlarm()
        {
            foreach (var alarm in _equipment?.GetAlarms().Where(a => a.Active))
            {
                //获取变量名
                string variableName = alarm.Name + "Info";
                _equipment?.ClearAlarm(alarm.Name, alarm.AdditionalInfo, new string[] { variableName }, new object[] { "" });
            }

            return true;
        }

        private bool ClearModuleAlarm(string module)
        {
            foreach (var alarm in _equipment?.GetAlarms().Where(a => a.Name == $"{module}Alarm" && a.Active))
            {
                //获取变量名
                string variableName = alarm.Name + "Info";
                _equipment?.ClearAlarm(alarm.Name, alarm.AdditionalInfo, new string[] { variableName }, new object[] { "" });
            }

            return true;
        }

        private bool PPChange(object[] args)
        {
            if (args != null && args.Length == 2)
            {
                //PPChangeStatus: 1:created; 2:edited; 3:deleted
                _equipment?.TriggerEvent("PPChange", new string[] { "PPChangeName", "PPChangeStatus" }, new object[] { args[0], args[1] });
            }

            return true;
        }

        public void TriggerEvent(string eventName, string[] variableNames = null, object[] variableValues = null)
        {
            _equipment?.TriggerEvent(eventName, variableNames,variableValues);
        }

        //接受终端消息
        private void TerminalMessageReceived(string equipmentName, string connectionName, int terminalID, List<string> texts)
        {
            RecvMsgFromHost += $"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")} [{terminalID}] {string.Join("\r\n", texts)}\r\n";
            //Kxware.Common.Log.Info("GEM", $"Received TERMIAL message :{connectionName} :{terminalID}, {string.Join(",", texts)}");

            if (RecvMsgFromHost.Length > 3000)
            {
                RecvMsgFromHost = SecsLog.Substring(SecsLog.Length - 3000);
            }
        }

        //终端消息确认
        private bool TerminalMessageConfirm()
        {
            _equipment?.TriggerEvent("MessageRecognition");

            return true;
        }

        //发送消息给主机
        private bool SendMessageToHost(string sendMsg)
        {
            _equipment?.TerminalRequest(_equipment.MasterConnectionName, 0, sendMsg);

            return true;
        }

        public void Terminate()
        {

        }
    }
}
