using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using MECF.Framework.Common.Communications;
using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Net;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.UPS
{
    public class UPSBase :BaseDevice, IConnection, IDevice
    {
        #region Properties

        private UPSConnection _connection;       //ITAUPSConnection 和 UPS类 是相互绑定的，既然这样应该写到一起才对，自上而下原则
        private bool _activeMonitorStatus;

        private R_TRIG _trigRetryConnect = new R_TRIG();//断开上升沿
        private R_TRIG _trigReconnection = new R_TRIG();//重连上升沿
        private R_TRIG _trigPowerLow = new R_TRIG();//缺电上升沿
        private PeriodicJob _thread;

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

        private object _locker = new object();

        private bool _enableLog = true;

        private string _scRoot;
        private string portName;

        public bool IsReceive = false;

        public int _connectTimes { get; set; }

        public string Address
        {
            get; set;
        }

        public bool IsConnected
        {
            get
            {
                return _connection != null && _connection.IsConnected;
            }
        }

        public float InputVoltage { get; set; }
        public float BatteryVoltage { get; set; }
        public float BatteryRemainsTime { get; set; }
        public float BatteryUnderResidue { get; set; }
        public bool UPSPowerAlarm { get; set; }
        public bool UPSLowerBatteryAlarm { get; set; }

        public Dictionary<string, string> Oids = new Dictionary<string, string>();

        #endregion

        #region Constructors

        public UPSBase(string module, string name, string scRoot) : base(module, name, name, name)
        {
            _scRoot = scRoot;
            _activeMonitorStatus = true;

        }

        ~UPSBase()
        {
            _connection.Disconnect();

        }
        #endregion

        #region Function

        public bool Connect()
        {
            return true;
        }

        public bool Disconnect()
        {
            _connection.Disconnect();
            return true;
        }

        public void Monitor()
        {


        }

        public void Reset()
        {
            _connectTimes = 0;
            _connection.SetCommunicationError(false, "");

            _enableLog = SC.GetValue<bool>($"PM.{Module}.{Name}.EnableLogMessage");
            _trigRetryConnect.RST = true;
            _trigReconnection.RST = true;
        }

        public void Terminate()
        {
            _connection.Disconnect();
        }

        public bool Initialize()
        {
            //_connection的底层写死使用161端口号
            portName = SC.GetStringValue($"PM.{Module}.{Name}.Address");
            Address = portName;
            int address = SC.GetValue<int>($"PM.{Module}.{Name}.DeviceAddress");
            _enableLog = SC.GetValue<bool>($"PM.{Module}.{Name}.EnableLogMessage");
            _connection = new UPSConnection(portName);
            _connection.EnableLog(_enableLog);

            _thread = new PeriodicJob(500, OnTimer, $"{Module}.{Name} MonitorHandler", true);

            InitData();

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

            return true;
        }

        private void InitData()
        {
            DATA.Subscribe($"{Module}.{Name}.InputVoltage", () => InputVoltage);
            DATA.Subscribe($"{Module}.{Name}.BatteryVoltage", () => BatteryVoltage);
            DATA.Subscribe($"{Module}.{Name}.BatteryRemainsTime", () => BatteryRemainsTime);
            DATA.Subscribe($"{Module}.{Name}.BatteryUnderResidue", () => BatteryUnderResidue);
        }

        bool CanConnect()
        {
            IPAddress ip = IPAddress.Parse(portName);
            Ping ping = new Ping();
            try
            {
                PingReply reply = ping.Send(ip);
                return (reply.Status == IPStatus.Success);
            }
            catch (PingException)
            {
                return false;
            }
        }

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

                if (!_connection.IsConnected || _connection.IsCommunicationError)//测试发现这个条件永远不会满足
                {
                    //lock (_locker)
                    //{
                    //    _lstHandler.Clear();
                    //}
                    //if (!_connection.Connect())
                    //{
                    //    _trigRetryConnect.CLK = !_connection.IsConnected;
                    //    if (_trigRetryConnect.Q)
                    //    {
                    //        EV.PostAlarmLog(Module, $"Can not connect with {_connection.Address}, {Module}.{Name}");
                    //    }
                    //}
                    //else
                    //{
                    //    _trigRetryConnect.RST = true;
                    //    EV.PostInfoLog(Module, $"Connected with {_connection.Address}, {Module}.{Name}");
                    //}

                }

                //执行最新连接操作
                HandlerBase handler = null;
                lock (_locker)
                {
                    if (_lstHandler.Count == 0)
                        QueryOids();
                    if (_lstHandler.Count > 0 && !_connection.IsBusy)
                    {
                        handler = _lstHandler.First.Value;
                        _lstHandler.RemoveFirst();
                        if (handler != null)
                        {
                            _connection.Execute(handler);   //执行成功_connection会将IsReceive置为true
                        }
                    }
                }

                if (!IsReceive) //单纯断联重连判断
                {
                    System.Threading.Thread.Sleep(3000);//不加延时第一次启动时未连接，可能不报警
                    _trigRetryConnect.CLK = true;//断联
                    if (_trigRetryConnect.Q)
                    {
                        InputVoltage = 0;
                        BatteryUnderResidue = 0;
                        BatteryVoltage = 0;
                        BatteryRemainsTime = 0;
                        EV.PostAlarmLog(Module, $"Can not connect with {_connection.Address}, {Module}.{Name}");
                    }
                    _trigReconnection.RST = true;//复位重连

                }
                else
                {
                    _trigReconnection.CLK = true;//重连
                    if (_trigReconnection.Q)
                    {
                        EV.PostInfoLog(Module, $"Connection with {_connection.Address}, {Module}.{Name}");
                    }
                    _trigRetryConnect.RST = true;//复位断联
                }

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

            return true;
        }

        public void QueryOids()
        {
            IsReceive = false;
            //UPS二代
            foreach (var oid in Oids)
            {
                if (oid.Key != null)
                {
                    _lstHandler.AddLast(new UPSGetHandler(this, oid.Key, "Get", oid.Value));
                }
            }
        }

        public void CheckBatteryUnderResidue()
        {
            if ((30 >= BatteryUnderResidue) && (BatteryUnderResidue >= 20) || (10 >= BatteryUnderResidue) && (BatteryUnderResidue >= 1))
            {
                _trigPowerLow.CLK = true;
                if (_trigPowerLow.Q)
                    EV.PostAlarmLog(Module, $"Attention {Module}.{Name} Is Power Low, Battery Under Residue {BatteryUnderResidue}%");
            }
            else
                _trigPowerLow.RST = true;//不满足报警条件时自动复位，准备下次报警操作
        }
        public virtual void SetBatteryUnderResidue(int data)
        {
            BatteryUnderResidue = data;
            CheckBatteryUnderResidue();
            
        }

        public virtual void ParseOutputSource(string value)
        {
            return;
        }

        public virtual void ParseBatteryRemainsTime(string value)
        {
            return;
        }

        public virtual void ParseBatteryVoltage(string value)
        {
            return;
        }

        public virtual void ParseInputVoltage(string value)
        {
            return;
        }
        #endregion

    }
}
