using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.SCCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps
{
    /// <summary>
    /// 会根据PM安装与否，执行合适的Log输出，DO输出，温度在规定次数内是否改变方法
    /// 此类作为一个测温类的对象使用，
    /// 初始化时传入的名称+温度下限+测温通道数，
    /// 1：名称会在Log中打印出来，2：传入温度<=最低温度时，认为温度发生变化
    /// </summary>
    public class TempBasFunction
    {
        private bool IsPM1Installed { get; set; }

        private bool IsPM2Installed { get; set; }

        private string DeviceName { get; set; }

        private double[] _chTempChangeCache;

        private double[] _allChTempChangeCache;

        //硬件通道数
        private int _numberOfChannels;

        private const double Epsilon = 0.001;

        /// <summary>
        /// 统计单路温度相同次数
        /// </summary>
        private int _chNoChangeNum;

        /// <summary>
        /// 统计单路温度相同次数
        /// </summary>
        private int _allChNoChangeNum;

        /// <summary>
        /// 记录温度不变时数据，最多记录10次
        /// </summary>
        private readonly StringBuilder _strChNoChangeMeg = new();

        private readonly StringBuilder _strAllChNoChangeMeg = new();

        /// <summary>
        /// 测温硬件最低测试温度，传入温度为此数值，不进行温度数据变化对比
        /// </summary>
        private readonly double TempMin;

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="deviceName">测温硬件名称</param>
        /// <param name="tempMin">最低温度显示，AE和昂坤都是600</param>
        public TempBasFunction(string deviceName, double tempMin, int numberOfChannels)
        {
            DeviceName = deviceName;
            TempMin = tempMin;
            _numberOfChannels = numberOfChannels;
            _chTempChangeCache = new double[numberOfChannels];
            _allChTempChangeCache = new double[numberOfChannels];
            IsPM1Installed = SC.GetValue<bool>($"System.SetUp.IsPM1Installed");
            IsPM2Installed = SC.GetValue<bool>($"System.SetUp.IsPM2Installed");
        }

        public void SetTempCh(int numberOfChannels)
        {
            _numberOfChannels = numberOfChannels;
            _chTempChangeCache = new double[numberOfChannels];
            _allChTempChangeCache = new double[numberOfChannels];
        }

        public void PM1PM2PostLog(string str, Action<string, string, int> action)
        {
            if (IsPM1Installed)
                action("PM1", $"{DeviceName} {str}", 2);

            if (IsPM2Installed)
                action("PM2", $"{DeviceName} {str}", 2);
        }

        /// <summary>
        /// 操作DO_PyroCommunicationError信号为InterLock提供输出,DO输出为true时设备报警宕机
        /// </summary>
        /// <param name="isReset"></param>
        public void SetPm1Pm2IoForInterlock(bool isReset)
        {
            if (IsPM1Installed)
                IO.DO[$"PM1.DO_PyroCommunicationError"].SetValue(isReset, out _);
            if (IsPM2Installed)
                IO.DO[$"PM2.DO_PyroCommunicationError"].SetValue(isReset, out _);
        }

        /// <summary>
        /// 复位单个PM的DO信号
        /// </summary>
        /// <param name="pm"></param>
        /// <param name="isReset"></param>
        public void SetPmIoForInterlock(string pm, bool isReset)
        {
            string PM = pm.ToUpper();
            if (IsMP(PM))
                IO.DO[$"{PM}.DO_PyroCommunicationError"].SetValue(isReset, out _);
        }

        /// <summary>
        /// 控制单个PM报警输出
        /// </summary>
        /// <param name="pm"></param>
        /// <param name="str"></param>
        /// <param name="action"></param>
        public void PMPostLog(string pm, string str, Action<string, string, int> action)
        {
            string PM = pm.ToUpper();
            if (IsMP(PM))
                action(PM, $"{DeviceName} {str}", 2);
        }

        private bool IsMP(string pm)
        {
            return (pm == "PM1" || pm == "PM2") ? true : false;
        }

        /// <summary>
        /// 温度是否发生改变（单路温度不变记录），返回数据不发生改变次数
        /// </summary>
        /// <param name="outputTemp"></param>
        /// <returns></returns>
        public int TempNoChangeCount(float[] outputTemp, out string errorInf)
        {
            errorInf = "";
            if (_chNoChangeNum > 999999)//防止数据溢出
                _chNoChangeNum = 0;
            for (int i = 0; i < outputTemp.Length; i++)
            {
                if (outputTemp[i] <= TempMin)//低于温度下限，数据不做对比
                    continue;
                if (Math.Abs(outputTemp[i] - _chTempChangeCache[i]) < Epsilon)
                {
                    if (_chNoChangeNum < 10)//记录前10次的数据
                        _strChNoChangeMeg.Append($"#{i + 1}:{outputTemp[i]:0.00}   ");

                    errorInf = _strChNoChangeMeg.ToString();
                    return _chNoChangeNum++;
                }
                _chTempChangeCache[i] = outputTemp[i];
            }

            //只要数据不同，就可以复位计数和缓存
            _strChNoChangeMeg.Clear();
            _chNoChangeNum = 0;
            return 0;
        }

        /// <summary>
        /// 温度是否发生改变（所有温度不变记录），返回数据不发生改变次数
        /// </summary>
        /// <param name="outputTemp"></param>
        /// <returns></returns>
        public int AllTempNoChangeCount(double[] outputTemp, out string errorInf)
        {
            errorInf = "";
            if (_allChNoChangeNum > 999999)//防止数据溢出
                _allChNoChangeNum = 0;

            int noChangeCount = 0;
            for (int i = 0; i < outputTemp.Length; i++)
            {
                if (outputTemp[i] <= TempMin)//低于温度下限，数据不做对比
                    continue;
                if (Math.Abs(outputTemp[i] - _allChTempChangeCache[i]) < Epsilon)
                {
                    if (_allChNoChangeNum < 10) //记录前10次的数据
                        _strAllChNoChangeMeg.Append($"#{i + 1}: {outputTemp[i]:0.00};  ");

                    errorInf = _strAllChNoChangeMeg.ToString();
                    noChangeCount += 1;
                }
                _allChTempChangeCache[i] = outputTemp[i];
            }

            if (noChangeCount == outputTemp.Length)//不变次数等于数组长度时，断定所有数据均无变化
            {
                _strAllChNoChangeMeg.Append("\r\n");
                return _allChNoChangeNum++;
            }
            //只要数据不同，就可以复位计数和缓存
            _strAllChNoChangeMeg.Clear();
            _allChNoChangeNum = 0;
            return 0;
        }
    }
}
