using System;
using System.Collections;
using System.Text;
using System.Xml;
using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.RT.Tolerance;
using Aitex.Core.Util;
using MECF.Framework.Common.Communications;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.Common.Device.Bases;
using MECF.Framework.Common.Equipment;
using Venus_Core;

namespace Venus_RT.Devices
{
    //interface IPumpControl
    //{
    //    bool IsRunning { get; }

    //    void TurnON();
    //    void TurnOFF();
    //}
    public enum SkyPumpState { ON = 0, OFF, Connected, Disconnected, Unknown, ERROR }

    static class SkyPumpMessage
    {
        public const string EOF = "\r\n";
        public const string SET_ON  = "@00CON_FDP_ON";
        public const string SET_OFF = "@00CON_FDP_OFF";
        public const string GET_ON  = "@00FDP_ONOK"; // \0\r\n
        public const string GET_OFF = "@00FDP_OFFOK"; // \0\r\n
        public const string READ_DATA = "@00READ_RUN_PARA";
        public const string GET_DATA = "@00RUN_PARA";
    }

    class SkyPump : PumpBase
    {
        // ----------------------------Fields--------------------------
        //
        private const ushort CHK_ST_INTERVAL = 1000;
        private const ushort CHK_REC_INTERVAL = 20 * 1000;
        private const ushort CHK_PUMP_REC_INTERVAL = 10 * 1000;
        private double _total;
        private double _fromLast;
        private const string EOF = "\r";
        private const char MSG_DELIMITER = ' ';
        private readonly string _PortNum = "COM91";
        private const int _counterMax = 30;
        private int _counter = 0;
        private string _fdp_Current = null;
        private string _roots_Current = null;
        private string _fdp_Temp = null;
        private string _roots_Temp = null;
        private string _n2Flow = null;
        private string _pressure = null;
        private string _runTime = null;
        private readonly AsyncSerialPort _serial;
        private readonly DeviceTimer _timerQueryStatus = new DeviceTimer();
        private readonly DeviceTimer _timerReceiveStatus = new DeviceTimer();
        private readonly DeviceTimer _timerPumpOn = new DeviceTimer();
        private readonly DeviceTimer _timerPumpOff = new DeviceTimer();
        private readonly DeviceTimer _timerTotal = new DeviceTimer();
        private readonly DeviceTimer _timerFromLast = new DeviceTimer();
        private readonly R_TRIG _trigPumpOn = new R_TRIG();
        private readonly R_TRIG _trigPumpOff = new R_TRIG();
        private readonly R_TRIG _trigReceiveStatus = new R_TRIG();
        private readonly RD_TRIG _trigOnOff = new RD_TRIG();
        private readonly R_TRIG _trigPMNeeded = new R_TRIG();
        private StatsDataItemRFAndPump _statPumpOnTime;
        // --------------------------Properties------------------------
        //
        public SkyPumpState StatusDry { get; set; }
        public SkyPumpState StatusRoose { get; set; }

        public string FDP_Current
        {
            get
            {
                return _fdp_Current;
            }
        }

        public string ROOTS_Current
        {
            get
            {
                return _roots_Current;
            }
        }

        public string FDP_Temp
        {
            get
            {
                return _fdp_Temp;
            }
        }

        public string ROOTS_Temp
        {
            get
            {
                return _roots_Temp;
            }
        }

        public string N2Flow
        {
            get
            {
                return _n2Flow;
            }
        }

        public string Pressure
        {
            get
            {
                return _pressure;
            }
        }

        public string RunTime
        {
            get
            {
                return _runTime;
            }
        }

        public string LastPMTime
        {
            get
            {
                return _statPumpOnTime != null ? _statPumpOnTime.LastPMTime.ToString() : "";
            }
        }

        public double DaysFromLastPM
        {
            get
            {
                return _statPumpOnTime == null ? 0 : _statPumpOnTime.fromLastPM;
            }
            set
            {
                if (_statPumpOnTime != null)
                    _statPumpOnTime.fromLastPM = value;
            }
        }

        public double TotalDays
        {
            get
            {
                return _statPumpOnTime != null ? _statPumpOnTime.Total : 0;
            }
            set
            {
                if (_statPumpOnTime != null)
                    _statPumpOnTime.Total = value;
            }
        }

        public double PMIntervalDays
        {
            get
            {
                return _statPumpOnTime != null ? _statPumpOnTime.PMInterval : 0;
            }
        }

        public bool IsPMNeeded
        {
            get
            {
                return DaysFromLastPM > PMIntervalDays;
            }
        }

        public bool EnableAlarm
        {
            get
            {
                return _statPumpOnTime == null || _statPumpOnTime.AlarmEnable;
            }
        }

        [Subscription(AITPumpProperty.IsRunning)]
        public override bool IsRunning
        {
            get
            {
                return StatusDry == SkyPumpState.ON;
            }
        }

        [Subscription(AITPumpProperty.IsError)]
        public override bool IsError
        {
            get
            {
                return StatusDry == SkyPumpState.ERROR || StatusDry == SkyPumpState.Disconnected;
            }
        }

        public override AITPumpData DeviceData
        {
            get
            {
                AITPumpData deviceData = new AITPumpData
                {
                    DeviceName = Name,
                    DeviceModule = Module,
                    DeviceSchematicId = DeviceID,
                    DisplayName = Display,
                    IsError = false,
                    IsWarning = false,
                    IsOn = IsRunning,
                    //WaterFlow = WaterFlowValue,
                    IsDryPumpEnable = true,
                    IsN2PressureEnable = false,
                    IsWaterFlowEnable = false,
                    //WaterFlowWarning = WaterFlowWarning,
                    //WaterFlowAlarm = WaterFlowAlarm,
                    //N2PressureAlarm = N2PressureAlarm,
                    //N2PressureWarning = N2PressureWarning,
                };

                return deviceData;
            }
        }

        // --------------------------Constructor-----------------------
        //
        public SkyPump(ModuleName mod) : base(mod.ToString(), VenusDevice.MainPump.ToString(), "SKY pump", "")
        {
            _PortNum = SC.GetStringValue($"{mod}.DryPump.Port");
            StatusDry = SkyPumpState.Unknown;

            _serial = new AsyncSerialPort(_PortNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, "\r\n", false);
        }

        public override bool Initialize()
        {
            base.Initialize();

            if (!_serial.Open())
            {
                StatusDry = SkyPumpState.Disconnected;
                EV.PostAlarmLog(this.Module, "Sky Pump串口无法打开");
                return false;
            }

            _statPumpOnTime = StatsDataManager.Instance.GetItemRFAndPump($"{Module}.PumpOnTime");

            StatusDry = SkyPumpState.Connected;
            _trigPumpOn.RST = true;
            _trigPumpOff.RST = true;
            _trigReceiveStatus.RST = true;
            _serial.OnDataChanged += OnPortDataChanged;
            _serial.OnBinaryDataChanged += OnPortBinaryDataChanged;
            _serial.OnErrorHappened += OnErrorOccurred;

            _timerQueryStatus.Start(CHK_ST_INTERVAL);
            _timerReceiveStatus.Start(CHK_REC_INTERVAL);

            return true;
        }

        private void OnPortBinaryDataChanged(byte[] obj)
        {
            try
            {
                _timerReceiveStatus.Stop();
                _timerReceiveStatus.Start(CHK_REC_INTERVAL);
                _trigReceiveStatus.RST = true;

                var strData = System.Text.Encoding.ASCII.GetString(obj);
                if (strData.Contains(SkyPumpMessage.EOF))
                {
                    string cmd = "";
                    if (obj.Length == 14 || obj.Length >= 40)
                        cmd = Encoding.ASCII.GetString(obj, 0, 11);
                    else if (obj.Length == 15)
                        cmd = Encoding.ASCII.GetString(obj, 0, 12);
                    if (cmd == SkyPumpMessage.GET_ON)
                    {
                        _trigPumpOn.CLK = true;
                        _timerPumpOn.Start(CHK_PUMP_REC_INTERVAL);
                        //LOG.Info($"[{Module}] {SkyPumpMessage.GET_ON}");
                        return;
                    }
                    if (cmd == SkyPumpMessage.GET_OFF)
                    {
                        _trigPumpOff.CLK = true;
                        _timerPumpOff.Start(CHK_PUMP_REC_INTERVAL);
                        //LOG.Info($"[{Module}] {SkyPumpMessage.GET_OFF}");
                        return;
                    }
                    if (cmd == SkyPumpMessage.GET_DATA)
                    {
                        _fdp_Current = Encoding.ASCII.GetString(obj, 11, 2);
                        _roots_Current = Encoding.ASCII.GetString(obj, 13, 2);
                        _fdp_Temp = Encoding.ASCII.GetString(obj, 15, 3);
                        _roots_Temp = Encoding.ASCII.GetString(obj, 18, 3);
                        _n2Flow = Encoding.ASCII.GetString(obj, 21, 2);
                        _pressure = Encoding.ASCII.GetString(obj, 23, 4);
                        _runTime = Encoding.ASCII.GetString(obj, 27, 5);

                        ParaErrSta1(new BitArray(new byte[] { obj[32] }));
                        ParaErrSta2(new BitArray(new byte[] { obj[33] }));
                        ParaRunSta(new BitArray(new byte[] { obj[34] }));
                        //ParaRunSta(new BitArray(new byte[] { obj[35] }));
                        ParaErrSta3(new BitArray(new byte[] { obj[36] }));
                    }
                }
                else
                {
                    if (!SC.GetValue<bool>("System.IsSimulatorMode"))
                    {
                        //LOG.Info($"[{Module}] Sky Pump 数据无效:[{strData}]");
                    }
                }
            }
            catch (Exception ex)
            {
                if (!SC.GetValue<bool>("System.IsSimulatorMode"))
                {
                    //LOG.Error($"[{Module}] sky pump data para error: [{ex.Message}]");
                }
            }
        }

        private void OnErrorOccurred(string obj)
        {
            StatusDry = SkyPumpState.ERROR;
            //LOG.Error($"[{Module}] sky pump error: [{obj}]");
        }

        private void OnPortDataChanged(string obj)
        {
            if (string.IsNullOrEmpty(obj))
                //LOG.Error($"[{Module}] sky pump message IsNullOrEmpty");
            try
            {
                string cmd = obj.ToString().Split('\n')[0].Split('\r')[0];
                if (cmd == SkyPumpMessage.GET_ON)
                {
                    //LOG.Info($"[{Module}] {SkyPumpMessage.GET_ON}");
                    return;
                }

                if (cmd == SkyPumpMessage.GET_OFF)
                {
                    //LOG.Info($"[{Module}] {SkyPumpMessage.GET_OFF}");
                    return;
                }

                if (cmd.Substring(0, 11) == SkyPumpMessage.GET_DATA)
                {
                    _fdp_Current = cmd.Substring(11, 2);
                    _roots_Current = cmd.Substring(13, 2);
                    _fdp_Temp = cmd.Substring(15, 3);
                    _roots_Temp = cmd.Substring(18, 3);
                    _n2Flow = cmd.Substring(21, 2);
                    _pressure = cmd.Substring(23, 4);
                    _runTime = cmd.Substring(27, 5);

                    ParaErrSta1(new BitArray(new byte[] { Convert.ToByte(cmd[32]) }));
                    ParaErrSta2(new BitArray(new byte[] { Convert.ToByte(cmd[33]) }));
                    ParaRunSta(new BitArray(new byte[] { Convert.ToByte(cmd[34]) }));
                    //ParaRunSta(new BitArray(new byte[] { Convert.ToByte(cmd[35]) }));
                    ParaErrSta3(new BitArray(new byte[] { Convert.ToByte(cmd[36]) }));
                }
            }
            catch(Exception ex)
            {
                //LOG.Error($"[{Module}] sky pump error: [{ex.Message}]");
            }
        }

        public void ParaErrSta1(BitArray bits)
        {
            for (int i = 0; i < bits.Count; i++)
            {
                if (bits[i]) ErrSta1(i);
            }
        }

        public void ParaErrSta2(BitArray bits)
        {
            for (int i = 0; i < bits.Count; i++)
            {
                if (bits[i]) ErrSta2(i);
            }
        }

        public void ParaErrSta3(BitArray bits)
        {
            for (int i = 0; i < bits.Count; i++)
            {
                if (bits[i]) ErrSta3(i);
            }
        }

        public void ParaRunSta(BitArray bits)
        {
            string sRes = "sky pump status: ";
            for (int i = 0; i < bits.Count; i++)
            {
                if (bits[i])
                    sRes += RunStaTure(i);
                else
                    sRes += RunStaFalse(i);
            }
            _counter++;
            if (_counter == _counterMax)
            {
                _counter = 0;
                //LOG.Info($"[{Module}] {sRes}");
            }
        }

        public string RunStaTure(int code)
        {
            switch (code)
            {
                case 7:
                    return "远程。";
                case 6:
                    StatusDry = SkyPumpState.ON;
                    if (_trigPumpOn.Q)
                    {
                        EV.PostInfoLog(this.Module, $"Dry Pump打开");
                    }
                    if (_trigPumpOff.Q && _timerPumpOff.IsTimeout())
                    {
                        _trigPumpOff.RST = true;
                        EV.PostMessage(Module, EventEnum.DefaultWarning, "Dry Pump 无法关闭");
                    }
                    _trigPumpOn.RST = true;
                    return "干泵开, ";
                case 5:
                    StatusRoose = SkyPumpState.ON;
                    return "罗茨泵开, ";
                case 4:
                    return "泵冷阀开, ";
                case 3:
                    return "清洗阀开, ";
                case 2:
                    return "有警示, ";
                case 1:
                    return "有故障, ";
                case 0:
                    return "无水, ";
                default:
                    return "";
            }
        }

        public string RunStaFalse(int code)
        {
            switch (code)
            {
                case 7:
                    return "本地。";
                case 6:
                    StatusDry = SkyPumpState.OFF;
                    if (_trigPumpOn.Q && _timerPumpOn.IsTimeout())
                    {
                        _trigPumpOn.RST = true;
                        LOG.Write(eEvent.DefaultWarning, ModuleHelper.Converter(Module), "Dry Pump 无法打开");
                    }
                    if (_trigPumpOff.Q)
                    {
                        EV.PostInfoLog(this.Module, $"Dry Pump关闭");
                    }
                    _trigPumpOff.RST = true;
                    return "干泵关, ";
                case 5:
                    StatusRoose = SkyPumpState.OFF;
                    return "罗茨泵关, ";
                case 4:
                    return "泵冷阀关, ";
                case 3:
                    return "清洗阀关, ";
                case 2:
                    return "无警示, ";
                case 1:
                    return "无故障, ";
                case 0:
                    return "有水, ";
                default:
                    return "";
            }
        }

        public void ErrSta1(int error)
        {
            //switch (error)
            //{
            //    //case 7:
            //    //    LOG.Error($"[{Module}]上泵变频器除通讯外故障");
            //    //    break;
            //    //case 6:
            //    //    LOG.Error($"[{Module}]下泵变频器除通讯外故障");
            //    //    break;
            //    //case 5:
            //    //    LOG.Error($"[{Module}]上泵接触器");
            //    //    break;
            //    //case 4:
            //    //    LOG.Error($"[{Module}]下泵接触器");
            //    //    break;
            //    //case 3:
            //    //    LOG.Error($"[{Module}]上泵电机过热");
            //    //    break;
            //    //case 2:
            //    //    LOG.Error($"[{Module}]下泵电机过热");
            //    //    break;
            //    //case 1:
            //    //    LOG.Error($"[{Module}]急停");
            //    //    break;
            //    //case 0:
            //    //    LOG.Error($"[{Module}]水冷");
            //    //    break;
            //    //default:
            //    //    break;
            //}
        }

        public void ErrSta2(int error)
        {
            //switch (error)
            //{
            //    //case 7:
            //    //    LOG.Error($"[{Module}]下泵变频器通讯故障");
            //    //    break;
            //    //case 6:
            //    //    LOG.Error($"[{Module}]上泵变频器通讯故障");
            //    //    break;
            //    //case 5:
            //    //    LOG.Error($"[{Module}]排气压力");
            //    //    break;
            //    //case 4:
            //    //    LOG.Error($"[{Module}]氮气流量");
            //    //    break;
            //    //case 3:
            //    //    LOG.Error($"[{Module}]下泵电流");
            //    //    break;
            //    //case 2:
            //    //    LOG.Error($"[{Module}]上泵电流");
            //    //    break;
            //    //case 1:
            //    //    LOG.Error($"[{Module}]下泵温度");
            //    //    break;
            //    //case 0:
            //    //    LOG.Error($"[{Module}]上泵温度");
            //    //    break;
            //    //default:
            //    //    break;
            //}
        }

        public void ErrSta3(int error)
        {
            //switch (error)
            //{
            //    case 7:
            //    case 6:
            //    case 5:
            //    case 4:
            //    case 3:
            //    case 2:
            //        break;
            //    case 1:
            //        LOG.Error($"[{Module}]下泵温度传感器未连接");
            //        break;
            //    case 0:
            //        LOG.Error($"[{Module}]上泵温度传感器未连接");
            //        break;
            //    default:
            //        break;
            //}
        }

        public override void Monitor()
        {
            try
            {
                // 状态查询
                if (_timerQueryStatus.IsTimeout() && this.StatusDry != SkyPumpState.ERROR)
                {
                    this.SendCmd(SkyPumpMessage.READ_DATA);
                    _timerQueryStatus.Start(CHK_ST_INTERVAL);
                }

                if (_timerReceiveStatus.IsTimeout() && this.StatusDry != SkyPumpState.ERROR)
                {
                    _trigReceiveStatus.CLK = true;
                    if(_trigReceiveStatus.Q)
                    {
                        EV.PostMessage(Module, EventEnum.DefaultWarning, "Dry Pump 没有回复");
                    }
                }

                _trigOnOff.CLK = IsRunning;

                //第一次检测到打开了,开始计时
                if (_trigOnOff.R)
                {
                    _total = TotalDays;
                    _fromLast = DaysFromLastPM;
                    _timerTotal.Start(0);
                    _timerFromLast.Start(0);
                }

                //第一次检测到从打开到关闭状态
                if (_trigOnOff.T)
                {

                }

                //如果开着,就更新SC
                if (_trigOnOff.M)
                {
                    TotalDays = _total + _timerTotal.GetElapseTime() / 1000 / 60 / 60;
                    DaysFromLastPM = _fromLast + _timerFromLast.GetElapseTime() / 1000 / 60 / 60;
                }

                if (PMIntervalDays > 0)
                {
                    _trigPMNeeded.CLK = IsPMNeeded;

                    if (_trigPMNeeded.Q)
                    {
                        if (EnableAlarm)
                        {
                            EV.PostAlarmLog(Module, "pump on time value larger than setting interval days");
                        }
                    }
                }

                StatsDataManager.Instance.Increase($"{Module}.PumpOnTime", $"{Module} PumpOnTime", DaysFromLastPM, TotalDays);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool SendCmd(string str)
        {
            return _serial.Write(str + "\r");
        }

        public override void Reset()
        {
            _trigPumpOn.RST = true;
            _trigPumpOff.RST = true;
            _trigReceiveStatus.RST = true;
            _trigPMNeeded.RST = true;
            //SetPumpOnOff(false);
        }

        public override void Terminate()
        {
            //if (StatusDry == SkyPumpState.ON)
            //    SetPumpOnOff(false);
            _serial?.Close();
        }

        public override void SetPumpOnOff(bool on)
        {
            SendCmd(on ? SkyPumpMessage.SET_ON : SkyPumpMessage.SET_OFF);
        }
    }
}