using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using System;
using System.Linq;
using System.Threading;
using System.Xml;
using RTOverEthernetDevelopmentKit;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps
{
    /// 昂坤Viper-RTC测温数据交互流程简介
    /// 1：上位机连接昂坤软件启动的服务器，昂坤服务器启用  工控机的IP + 53888固定端口，上位机连接服务器获取温度数据
    /// 2：昂坤软件通过USB线连接主机盒子获取温度，上位机不用干预
    /// 3：昂坤通讯特性，上位机发送一条指令后，服务器会一直安装设定频率，一直发送数据，上位机只接受就可以了
    /// 4：上位机读取数据，通过昂坤提供的库，调用连接和数据获取方法
    /// 5：断联分为昂坤软件服务器、USB两种断联和重连判断，例如：昂坤软件未打开或UBS线松动
    /// 6：继承ITempData接口，上层使用接口获取数据，方便以后扩展测温硬件
    /// <summary>
    ///  昂坤Viper-RTC测温
    /// </summary>
    public class AKunTemp : TempSensorBase
    {
        #region Variables

        private IROverEthernet _ir;

        /// <summary>
        /// 连接昂坤软件服务器
        /// </summary>
        private readonly R_TRIG _trigConnServiceError = new();

        /// <summary>
        /// 机箱USB断联
        /// </summary>
        private readonly R_TRIG _trigUSBDataError = new();

        /// <summary>
        /// 机箱USB重连
        /// </summary>
        private readonly R_TRIG _trigUSBDataOK = new();

        private int _lastIntegTime;
        
        #endregion Variables

        #region Constructors

        public AKunTemp(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule)
        {
            RTrigs.Add(_trigConnServiceError);
            RTrigs.Add(_trigUSBDataError);
            RTrigs.Add(_trigUSBDataOK);
        }

        #endregion

        #region Properties
        
        private int Port { get; set; }
        
        public override bool IsConnected => _ir.IsConnected;

        #endregion 

        #region Methods

        /// <summary>
        /// 获取系统配置中的积分时间。
        /// </summary>
        /// <returns></returns>
        private int GetScIntegrationTime()
        {
            var integrationTime = SC.GetValue<int>($"{ScBasePath}.{Name}.ControllerAverageTime"); // the minimum value should be 10ms.
            if (integrationTime < 10)
                integrationTime = 10;

            return integrationTime;
        }

        public override bool Connect()
        {
            try
            {
                if (IsSimMode)
                    return true;
                
                _ir.Init(Address, Port);
                _ir.StopIR();
                _lastIntegTime = GetScIntegrationTime();
                _ir.SetIntegrationTime(_lastIntegTime);
                _ir.StartIR();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        private void Reconnect()
        {
            try
            {
                if (IsSimMode)
                    return;

                _ir.Close();
            }
            catch
            {
                // ignored
            }
            finally
            {
                Connect();
            }
        }

        protected override bool HandleInitialize()
        {
            InitAKunController();
            return true;
        }

        private void InitAKunController()
        {
            if (IsSimMode)
                return;
            
            var data = SC.GetStringValue($"{ScBasePath}.{Name}.Address").Split(':');
            Address = data[0];
            Port = Convert.ToInt32(data[1]);
            _ir = new IROverEthernet();
            _trigUSBDataOK.CLK = true;//初始化重连信号

            SC.RegisterValueChangedCallback($"{ScBasePath}.{Name}.ControllerAverageTime",
                SetControllerAverageTime);
        }

        private void SetControllerAverageTime(object time)
        {
            if (IsSimMode)
                return;
            
            if (time != null && int.TryParse(time.ToString(), out var avt))
            {
                _ir.StopIR();
                _ir.SetIntegrationTime(avt);
                _ir.StartIR();
            }
            else
            {
                LOG.Error($"Unable to set {Name} controller average time, the parameter {time} is not a integer.");
            }
        }
        
          private int _usbReConnCnt = 0;//接受数据失败次数

        private double[] ReadTemp()
        {
            try
            {
                if (IsSimMode)
                    return null;
                
                var allChannel = _ir.GetAllChannel();

                //USB线断联和重连逻辑
                {
                    //连接时使用次数报警，多次接收到空数据开始报警 ，此时发现正常连接时Count=0会出现，频率是几分钟出现一次
                    if (allChannel.FirstOrDefault(ch => ch == null || !ch.Any()) != null || // 某个通道没有数据
                        _ir.Current.Status != 0) //首次打开上位机时，测试昂坤软件打开且未连接USB时，Count一直大于0，所以此处添加厂商提供的属性值判断USB连接
                    {
                        _usbReConnCnt++;
                        if (_usbReConnCnt <= 10) 
                            return null;
                        _trigUSBDataOK.CLK = false; //复位USB重连信号，
                        _trigUSBDataError.CLK = true;
                        if (_trigUSBDataError.Q)
                            TempBasFunction.PM1PM2PostLog(
                                $"Can not connect with {Name} From USB,Status:{_ir.Current.Status}",
                                EV.PostAlarmLog);
                        _usbReConnCnt = 0;

                        TempBasFunction.SetPm1Pm2IoForInterlock(true);
                        return null;

                    }

                    _trigUSBDataOK.CLK = true;
                    if (_trigUSBDataOK.Q)
                    {
                        TempBasFunction.PM1PM2PostLog($"Connect OK with {Name} From USB", EV.PostInfoLog);
                        _trigUSBDataError.RST = true;//复位USB断联信号

                        TempBasFunction.SetPm1Pm2IoForInterlock(false);
                    }

                    //有数据时必须复位
                    _usbReConnCnt = 0;
                }
                
                return allChannel.Select(ch => (double)ch.Average()).ToArray();
            }
            catch (Exception ex)
            {
                LOG.Write($"{Name} Read controller error, {ex}");
                return null;
            }
        }

        protected override double[] HandleReadTemp()
        {
            try
            {
                //判断昂坤软件服务器断联和重连逻辑
                if (_ir.IsConnected) 
                    return ReadTemp();
                
                Reconnect();
                if (!_ir.IsConnected)//昂坤软件的服务器未打开
                {
                    _trigConnServiceError.CLK = true;
                    if (_trigConnServiceError.Q)
                    {
                        Thread.Sleep(2000);//不加延时软件刚启动可能不打印
                        TempBasFunction.PM1PM2PostLog($"AKun Temp Software Maybe Not Open {Address} {Name}", EV.PostAlarmLog);
                        TempBasFunction.SetPm1Pm2IoForInterlock(true);
                    }
                }
                else//连接成功后不会再进入，只会提示一次
                {
                    _trigConnServiceError.RST = true;
                    TempBasFunction.PM1PM2PostLog($"Connect OK with AKun Temp Software Form {Address} {Name}", EV.PostInfoLog);
                    TempBasFunction.SetPm1Pm2IoForInterlock(false);
                }
                Thread.Sleep(1000);
                return null;
            }
            catch (Exception ex)
            {
                if (_trigConnServiceError.Q)
                {
                    TempBasFunction.PM1PM2PostLog($"{this} Unable to read data from viper RTC, {ex.Message}", EV.PostAlarmLog);
                }
                return null;
            }
        }

        public override void Terminate()
        {
            try
            {
                if (IsSimMode)
                    return;
                
                _ir.Close();
            }
            catch (Exception ex)
            {
                LOG.Write(ex);
            }
        }
        
        public override bool Disconnect()
        {
            Terminate();
            return true;
        }

        #endregion
    }
}