using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using MECF.Framework.Common.Communications;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Aligners.HiWinAligner.Handlers;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Aligners.HiWinAligner
{
    public class HwAlignerGuide : BaseDevice, IConnection, IDevice
    {
        #region Variables

        private enum CommandEnum
        {
            NULL,
            SME11,
            SME21,
            SME31,
            HOM,
            DOC,
            CVN,
            MTM,
            CCD,
            BAL,
            MVR,
            CVF,
            ERS,
            STA,

            //
            SPS,
            WSZ,
            _WT,
            GLM,
            FWO,

        };


        private HwAlignerGuideConnection _connection;

        private readonly bool _activeMonitorStatus;

        private readonly R_TRIG _trigCommunicationError = new();
        private readonly R_TRIG _trigRetryConnect = new();
        private bool _bIsDisconnect = false;

        private string _lastHandlerName;
        private CommandEnum _iCurrentOper = CommandEnum.NULL;

        private readonly LinkedList<HandlerBase> _lstHandler = new();

        private readonly object _locker = new();

        #endregion

        #region Constructors

        /// <summary>
        /// 构造上银巡边器对象实例。
        /// </summary>
        /// <param name="module">所属模组名称。</param>
        /// <param name="scRoot">系统配置定义了当前巡边器相关配置的节点。</param>
        /// <param name="name">当前巡边器名称。</param>
        public HwAlignerGuide(string module, string scRoot, string name) : base(module, name, name, name)
        {

            ScBasePath = scRoot;
            _activeMonitorStatus = true;
        }


        #endregion

        #region Properties

        public bool HaveWafer { get; set; }

        public string Address { get; set; }

        public string Vacuum { get; set; } ="-Kpa" ;

        public string PError { get; set; } = "-";

        public string Response { get; set; } = "-";

        public bool IsConnected => _connection is { IsConnected: true };

        public bool AlarmStatus { get; set; }

        public bool PositionComplete { get; set; }

        public bool MotorBusy { get; set; }

        public bool IsBusy
        {
            get
            {
                lock (_locker)
                {
                    return _lstHandler.Count > 0 || _iCurrentOper != CommandEnum.NULL;
                }
            }
        }

        #endregion

        #region Private Methods


        private void InitData()
        {
            DATA.Subscribe($"{Module}.{Name}.HaveWafer", () => HaveWafer);
            DATA.Subscribe($"{Module}.{Name}.Response", () => Response, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{Name}.Vacuum", () => Vacuum, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{Name}.PError", () => PError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
        }

        private void InitOp()
        {
            //参数保存
            OP.Subscribe($"{Module}.{Name}.HwSaveParameters", (_, _) =>
            {
                Set("SPS");
                return true;
            });
            //读取/设定晶圆尺寸
            OP.Subscribe($"{Module}.{Name}.HwWaferSize", (_, param) =>
            {
                Set("WSZ" + " " + param[0]);
                return true;
            });
            //晶圆种类
            OP.Subscribe($"{Module}.{Name}.HwWaferType", (_, param) =>
            {
                Set("_WT" + " " + param[0]);
                return true;
            });
            //寻边材质
            OP.Subscribe($"{Module}.{Name}.HwWaferMaterial", (cmd, param) =>
            {
                Set("GLM" + " " + param[0]);
                return true;
            });
            //晶圆方向
            OP.Subscribe($"{Module}.{Name}.HwWaferOrientation", (cmd, param) =>
            {
                Set("FWO" + " " + param[0]);
                return true;
            });

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

            //原点复归
            OP.Subscribe($"{Module}.{Name}.HwHOM", (_, _) => MsgHome());

            //晶圆确认
            OP.Subscribe($"{Module}.{Name}.HwDOC", (_, _) => CheckWaferLoad());

            //开启真空
            OP.Subscribe($"{Module}.{Name}.HwCVN", (_, _) => OpenVacuum());

            //寻边补正
            OP.Subscribe($"{Module}.{Name}.HwBAL", (_, _) => MsgAliger());

            //关闭真空
            OP.Subscribe($"{Module}.{Name}.HwCVD", (_, _) => ReadVacuum());

            //关闭真空
            OP.Subscribe($"{Module}.{Name}.HwCVF", (_, _) => CloseVacuum());

            //移至测量中心点
            OP.Subscribe($"{Module}.{Name}.HwMTM", (_, _) => MoveToRobotPutPlace());

            //清除报警
            OP.Subscribe($"{Module}.{Name}.HwERS", (_, _) => ClearError());

            //读取报警
            OP.Subscribe($"{Module}.{Name}.HwPER", (_, _) => ReadError());

            //马达激磁
            OP.Subscribe($"{Module}.{Name}.HwSME", (_, _) =>
            {
                InitMachine();
                return true;
            });
            
            //相对位移
            OP.Subscribe($"{Module}.{Name}.HwMVR", (cmd, param) =>
            {
                Set("MVR");
                return true;
            });

            //
            OP.Subscribe($"{Module}.{Name}.HwAbort", (cmd, param) =>
            {
                Abort();
                return true;
            });


        }

        private bool OnTimer()
        {
            try
            {
                _connection.MonitorTimeout();

                //若断，重连

                if ((!_connection.IsConnected) || _connection.IsCommunicationError || _bIsDisconnect)
                {
                    _trigRetryConnect.CLK = _bIsDisconnect;

                    //重连机制要改，timeout之后，要是用心跳方式探测重连

                    _trigRetryConnect.CLK = _bIsDisconnect;
                    if (_connection.Connect())
                    {
                        _bIsDisconnect = false;
                        //
                        if (_trigRetryConnect.Q)
                        {
                            EV.PostInfoLog(Module, $"{Module}.{Name} connected");
                            LOG.Write($"{Module}.{Name} connected");
                        }
                    }
                    else
                    {
                        if (_trigRetryConnect.Q)
                        {
                            EV.PostInfoLog(Module,
                                $"Trying to connect {Module}.{Name} with address: {_connection.Address}");
                            LOG.Write($"Trying to connect {Module}.{Name} with address: {_connection.Address}");
                        }
                    }

                }


                //处理命令队列
                HandlerBase handler = null;
                if (!_connection.IsBusy)
                {
                    lock (_locker)
                    {
                        if (_lstHandler.Count == 0 && _activeMonitorStatus && !IsBusy)
                        {
                            _lastHandlerName = "";
                        }

                        if (_lstHandler.Count > 0)
                        {
                            handler = _lstHandler.First.Value;

                            _lstHandler.RemoveFirst();
                        }
                    }

                    if (handler != null)
                    {
                        _lastHandlerName = handler.Name;
                        _connection.Execute(handler);
                    }
                }

                //
                return true;

            }
            catch (Exception ex)
            {
                LOG.Write(ex);
            }

            return true;
        }

        internal void NoteError()
        {

        }

        protected override void HandleMonitor()
        {
            try
            {
                _trigCommunicationError.CLK = _connection.IsCommunicationError;
                if (_trigCommunicationError.Q)
                {
                    EV.PostAlarmLog(Module,
                        $"{Module}.{Name} communication error, {_connection.LastCommunicationError}");
                }
            }
            catch (Exception ex)
            {
                LOG.Write(ex);
            }
        }

        #endregion

        #region Methods

        public bool Connect()
        {
            return true;
        }

        public bool Disconnect()
        {
            return true;
        }
        
        public bool Initialize()
        {
            // string portName = SC.GetStringValue($"{_scRoot}.{Module}.{Name}.Address");
            var portName = SC.GetStringValue($"{ScBasePath}.Address");
            Address = portName;

            var scEnableLog = $"{ScBasePath}.EnableLogMessage";
            var enableLog = SC.GetValue<bool>(scEnableLog);
            SC.RegisterValueChangedCallback(scEnableLog, scValue =>
            {
                if (scValue is bool bEnableLog)
                    _connection.EnableLog(bEnableLog);
            });

            _connection = new HwAlignerGuideConnection(portName);
            _connection.EnableLog(enableLog);

           

            if (_connection.Connect())
            {
                EV.PostInfoLog(Module, $"{Module}.{Name} Connected");
            }

            var periodicJob = new PeriodicJob(200, OnTimer, $"{Name} MonitorHandler", true);

            InitData();
            InitOp();

            ConnectionManager.Instance.Subscribe($"{Name}", this);
            return true;
        }


        public void Abort()
        {

        }

        /// <summary>
        /// 初始化当前巡边器。
        /// </summary>
        public void InitMachine()
        {
            lock (_locker)
            {
                _lstHandler.Clear();
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "SME11", "SME 11"));
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "SME12", "SME 21"));
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "SME13", "SME 31"));
            }
        }

        /// <summary>
        /// 开始巡边。
        /// </summary>
        public void Aligner()
        {
            lock (_locker)
            {
                _lstHandler.Clear();
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVN", "CVN"));
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "BAL", "BAL"));
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVF", "CVF"));
            }
        }

        /// <summary>
        /// 回机械零点。
        /// </summary>
        /// <returns>
        /// <value>True：命令发送成功。</value>
        /// <br/>
        /// <value>False：命令发送失败</value>
        /// </returns>
        public bool MsgHome()
        {
            //_lstHandler.Clear();
            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "HOM", "HOM", 30));
            }

            return true;
        }

        /// <summary>
        /// 检测当前巡边器上是否有晶圆。
        /// </summary>
        /// <returns>
        /// <value>True：命令发送成功。</value>
        /// <br/>
        /// <value>False：命令发送失败</value>
        /// </returns>
        public bool CheckWaferLoad()
        {
            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerWaferCheckHandler(this));
            }

            return true;
        }

        /// <summary>
        /// 打开当前巡边器的真空吸附。
        /// </summary>
        /// <returns>
        /// <value>True：命令发送成功。</value>
        /// <br/>
        /// <value>False：命令发送失败</value>
        /// </returns>
        public bool OpenVacuum()
        {
            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVN", "CVN"));
            }

            return true;
        }

        /// <summary>
        /// 关闭当前巡边器的真空吸附。
        /// </summary>
        /// <returns>
        /// <value>True：命令发送成功。</value>
        /// <br/>
        /// <value>False：命令发送失败</value>
        /// </returns>
        public bool CloseVacuum()
        {
            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVF", "CVF"));
            }

            return true;
        }

        private bool ReadVacuum()
        {
            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVD", "CVD"));
            }

            return true;
        }

        public bool MoveToRobotPutPlace()
        {
            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "MTM", "MTM"));
            }

            return true;
        }


        public bool MsgAliger()
        {
            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "BAL", "BAL"));
            }

            return true;
        }


        public bool DoAliger()
        {
            lock (_locker)
            {
                _lstHandler.Clear();
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVN", "CVN"));
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "BAL", "BAL"));
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVF", "CVF"));
            }

            return true;
        }


        public bool ClearError()
        {

            lock (_locker)
            {
                _lstHandler.Clear();
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "ERS", "ERS"));
            }

            return true;
        }

        public bool ReadError()
        {

            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "PER", "PER"));
            }

            return true;
        }

        /// <summary>
        /// 新增一条命令到命令执行列队。
        /// </summary>
        /// <param name="command">命令字符。</param>
        public void Set(string command)
        {
            lock (_locker)
            {
                _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, command, command));
            }
        }


        public void Terminate()
        {
            try
            {
                lock(_locker)
                    _lstHandler.Clear();

                if (_connection != null)
                {
                    _connection.Disconnect();
                    _connection = null;
                }
            }
            catch (Exception ex)
            {
                LOG.Write(ex);
            }

        }

        public void Reset()
        {
            _bIsDisconnect = _connection.IsCommunicationError;

            //这里重置了CommunicationError ，就是去了OnTimer里面的重连的触发，所以需要另设变量以触发之(使用timeout来触发的情况）
            _connection.SetCommunicationError(false,"");

            _trigCommunicationError.RST = true;
            _trigRetryConnect.RST = true;
            _iCurrentOper = CommandEnum.NULL;

            //lock (_locker)
            //    _lstHandler.Clear();
        }

        public void SetCurrentOper()
        {
            _iCurrentOper = CommandEnum.CCD;
        }

        internal bool ParseData(string name, byte[] buffer, out bool bResult)
        {
            bResult = true;
            var sAnswer = Encoding.ASCII.GetString(buffer).TrimEnd('\r', '\n');
            Response = sAnswer;
            string[] units = Regex.Split(sAnswer,"\r\n");

            foreach (string unit in units)
            {
                if (unit.Contains("END"))
                {
                    _iCurrentOper = CommandEnum.NULL;
                    return true;
                }
                else if (unit.Contains("ERR") && _lastHandlerName != "PER")
                {
                    lock (_locker)
                    {
                        _lstHandler.Clear();
                    }

                    _iCurrentOper = CommandEnum.NULL;
                    bResult = false;

                    EV.PostAlarmLog(Module, $"Aligner, Execute {_lastHandlerName} error, {unit.TrimEnd('\r', '\n')}");

                    return true; //Handled
                }
                else if (_lastHandlerName == "CVD")
                {
                    try
                    {
                        double x = Convert.ToInt32(unit);
                        Vacuum = unit + "Kpa";
                    }
                    catch
                    {
                        Vacuum = "Convert(" + unit + ") Failed.";
                    }
                }
                else if (_lastHandlerName == "PER")
                {
                    PError = unit;
                }
            }
            return false;
        }

        internal bool CheckWaferDataA(string name, byte[] buffer, out bool bResult)
        {
            bResult = true;
            var sAnswer = Encoding.ASCII.GetString(buffer.ToArray());
            Response = sAnswer;
            if (sAnswer.Contains("END"))
            {
                HaveWafer = sAnswer.Contains("1\r\nEND");
                _iCurrentOper = CommandEnum.NULL;
                return true;
            }

            if (sAnswer.Contains("ERR"))
            {
                lock (_locker)
                {
                    _lstHandler.Clear();
                }

                _iCurrentOper = CommandEnum.NULL;
                bResult = false;

                EV.PostAlarmLog(Module, $"Aligner, Execute {_lastHandlerName} error, {sAnswer.TrimEnd('\r', '\n')}");

                return false; //Handle
            }

            return false;
        }

    }

    #endregion

}
