using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using MECF.Framework.Common.Event;
using System;
using System.Diagnostics;
using System.Xml;
using static Aitex.Core.Util.SubscriptionAttribute;
namespace Aitex.Core.RT.Device.Unit
{
    /// 
    ///  DO  reset
    /// DI alarm signal
    /// 
    public class IoAlarmSignal : BaseDevice, IDevice
    {
        private bool SignalFeedback
        {
            get
            {
                if (_diSignal != null)
                    return _diSignal.Value;
                if (_aiSignal != null && !string.IsNullOrEmpty(_condition))
                {
                    if (_condition == "H")
                        return _aiSignal.FloatValue > _limitValue;
                    if (_condition == "L")
                        return _aiSignal.FloatValue < _limitValue;
                }
                return false;
            }
            set
            {
            }
        }
        private bool SignalSetPoint
        {
            get
            {
                if (_doReset != null)
                    return _doReset.Value;
                return false;
            }
            set
            {
                if (_doReset != null)
                    _doReset.Value = value;
            }
        }
        private AIAccessor _aiSignal = null;
        private DIAccessor _diSignal = null;
        private DOAccessor _doReset = null;
        private Stopwatch _resetTimer = new Stopwatch();
        public AlarmEventItem AlarmTriggered { get; set; }
        public AlarmEventItem AlarmRecovery { get; set; }
        private RD_TRIG _trigSignalOn = new RD_TRIG();
        public RD_TRIG RrigSignalOn => _trigSignalOn;
        private bool _alarmTrigValue;
        public bool AlarmTrigValue => _alarmTrigValue;
        private DeviceTimer _alarmMonitorTimer = new DeviceTimer();
        public bool IsAlarmAutoRecovery => _isAlarmAutoRecovery;
        public bool _isAlarmAutoRecovery;
        public string Level { get; set; }
        bool _ignoreSaveDB = false;
        public bool ignoreSaveDB { get { return _ignoreSaveDB; } set { _ignoreSaveDB = value; } }
        private float _delayTime;//大于0时,此时间段内一直满足条件才报警
        private Stopwatch _delayTimer = new Stopwatch();
        private float _limitValue;//大于0时,此时间段内一直满足条件才报警
        private string _condition;
        public AITSensorData DeviceData
        {
            get
            {
                AITSensorData data = new AITSensorData()
                {
                    DeviceName = Name,
                    DeviceSchematicId = DeviceID,
                    DisplayName = Display,
                    Value = SignalFeedback,
                };
                return data;
            }
        }
        public bool Value => SignalFeedback;
        public IoAlarmSignal(string module, string name, DIAccessor diSignal, bool alarmTrigValue = true, bool isAlarmAutoRecovery = false)
        {
            base.Module = module;
            base.Name = name;
            _diSignal = diSignal;
            _alarmTrigValue = alarmTrigValue;
            _isAlarmAutoRecovery = isAlarmAutoRecovery;
            Initialize();
        }
        public IoAlarmSignal(string module, XmlElement node, string ioModule = "")
        {
            base.Module = string.IsNullOrEmpty(node.GetAttribute("module")) ? module : node.GetAttribute("module");
            base.Name = ioModule.ToLower().StartsWith("gasline") ? $"{ioModule}{node.GetAttribute("id")}" : node.GetAttribute("id");
            base.Display = node.GetAttribute("display");
            base.DeviceID = node.GetAttribute("schematicId");
            Level = node.GetAttribute("level");
            ignoreSaveDB = string.IsNullOrEmpty(node.GetAttribute("ignoreSaveDB")) ? false : Convert.ToBoolean(node.GetAttribute("ignoreSaveDB"));
            _doReset = ParseDoNode("doReset", node, ioModule);
            _diSignal = ParseDiNode("diSignal", node, ioModule);
            _aiSignal = ParseAiNode("aiSignal", node, ioModule);
            if (_diSignal == null)
                _diSignal = ParseDiNode("di", node, ioModule);
            _alarmTrigValue = Convert.ToBoolean(string.IsNullOrEmpty(node.GetAttribute("alarmTrigValue")) ? "true" : node.GetAttribute("alarmTrigValue"));
            _isAlarmAutoRecovery = Convert.ToBoolean(string.IsNullOrEmpty(node.GetAttribute("alarmAutoRecovery")) ? "false" : node.GetAttribute("alarmAutoRecovery"));
            _delayTime = Convert.ToSingle(string.IsNullOrEmpty(node.GetAttribute("delay")) ? "0" : node.GetAttribute("delay"));
            _limitValue = Convert.ToSingle(string.IsNullOrEmpty(node.GetAttribute("limitValue")) ? "0" : node.GetAttribute("limitValue"));
            _condition = node.GetAttribute("condition");
        }
        public bool Initialize()
        {
            //AlarmTriggered = SubscribeAlarm($"{Module}.{Name}.AlarmTriggered", $"{Name} alarm triggered", ResetAlarmChecker);
            DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData, FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{Name}.Value", () => SignalFeedback,FLAG.IgnoreSaveDB);
           // DATA.Subscribe($"{Module}.{Name}.ignoreSaveDB", () => ignoreSaveDB);
            _alarmMonitorTimer.Start(2000);
            return true;
        }
        private bool ResetAlarmChecker()
        {
            if (SignalFeedback)
            {
                if (!SignalSetPoint)
                {
                    _resetTimer.Restart();
                    SignalSetPoint = true;
                }
            }
            return !SignalFeedback;
        }
        public void Terminate()
        {
        }
        public void Monitor()
        {
            if (SC.ContainsItem("System.BypassInterlock") && SC.GetValue("System.BypassInterlock"))
                return;
            //两秒后才检测,防止有报警是false值的时候,PLC还没读取数值就报警
            if (!_alarmMonitorTimer.IsTimeout())
                return;
            if (AlarmTriggered != null)
            {
                if (_delayTime > 0)
                {
                    if (_alarmTrigValue == SignalFeedback)
                    {
                        if (!_delayTimer.IsRunning)
                            _delayTimer.Restart();
                        if (_delayTimer.ElapsedMilliseconds > _delayTime * 1000)
                            _trigSignalOn.CLK = true;
                        else
                            _trigSignalOn.CLK = false;
                    }
                    else
                    {
                        _trigSignalOn.CLK = false;
                        _delayTimer.Stop();
                    }
                }
                else
                {
                    _trigSignalOn.CLK = _alarmTrigValue ? SignalFeedback : !SignalFeedback;
                }
                if (_trigSignalOn.R)
                {
                    AlarmTriggered?.Set();
                }
                if (_trigSignalOn.T)
                {
                    AlarmTriggered?.Set();
                    if (!ignoreSaveDB)
                    {
                        EV.ClearAlarmEvent(AlarmTriggered.EventEnum);
                    }
                    LOG.Write($"{AlarmTriggered.EventEnum} is auto recovered");
                }
                if (SignalSetPoint)
                {
                    if (!SignalFeedback)
                    {
                        AlarmTriggered.Reset();
                        SignalSetPoint = false;
                        _resetTimer.Stop();
                    }
                    if (SignalFeedback && _resetTimer.IsRunning &&
                        _resetTimer.ElapsedMilliseconds > 5 * 1000)
                    {
                        _resetTimer.Stop();
                        EV.PostWarningLog(Module, $"Can not reset {Display} in 5 seconds");
                        SignalSetPoint = false;
                    }
                }
            }
        }
        public void Reset()
        {
            _trigSignalOn.RST = true;
            if (AlarmTriggered != null)
                AlarmTriggered.IsAcknowledged = true;
        }
        public void SetIgnoreError(bool ignore)
        {
            AlarmTriggered.SetIgnoreError(ignore);
        }
    }
}