using System;
using System.Xml;
using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.RT.Tolerance;
using Aitex.Core.Util;
using Venus_RT.Devices.IODevices;
using Aitex.Core.RT.Log;

namespace Venus_RT.Devices
{
    public class IoPressureControl : BaseDevice, IDevice
    {
        private bool _enableTolerance;

        public bool EnableTolerance
        {
            get
            {
                return _enableTolerance;
            }
            set
            {
                if (_enableTolerance != value)
                {
                    LOG.Write(eEvent.EV_DEVICE_INFO, Module, value ? "Start monitor pressure stability" : "Stop monitor pressure stability");

                    if (value)
                    {
                        _tolerance.Reset(_scAlarmTime.DoubleValue);
                    }
                }

                _enableTolerance = value;
            }
        }

        public bool IsIndependentControl
        {
            get
            {
                if (_scIsIndependentControl != null)
                    return _scIsIndependentControl.BoolValue;
                return false;
            }
        }

        public bool IsTvInstalled
        {
            get
            {
                if (_scTvInstalled != null)
                    return _scTvInstalled.BoolValue;
                return false;
            }
        }

        public bool IsBoostPumpInstalled
        {
            get
            {
                if (_scIsBoostPumpInstalled != null)
                    return _scIsBoostPumpInstalled.BoolValue;
                return false;
            }
        }

        public bool EnableBoostControl
        {
            get
            {
                return _diLogicProcessGasFlowing == null || _diLogicProcessGasFlowing.Value;
            }
        }

        //public readonly IoThrottleValve ThrottleValve;
        public readonly IoPressureMeter PressureGauge;
        public readonly IoPressureMeter ProcessGauge;
        public readonly IoPressureMeter ForelineGauge;
        public readonly IoPressureMeter LoadLockGauge;
        public readonly IoPressureMeter ESCHeGauge;

        //public readonly IoBoostPump _boost;
        //public readonly IoPump DryPump;
        private readonly ToleranceChecker _tolerance = new ToleranceChecker();

        private readonly SCConfigItem _scAlarmRange;
        private readonly SCConfigItem _scAlarmTime;
        private readonly SCConfigItem _scIsIndependentControl;
        private readonly SCConfigItem _scIsBoostPumpInstalled;
        private readonly SCConfigItem _scTvInstalled;
        private readonly DIAccessor _diLogicProcessGasFlowing;

        private readonly R_TRIG _trigPressureGauge = new R_TRIG();
        private readonly R_TRIG _trigProcessGauge = new R_TRIG();
        private readonly R_TRIG _trigForelineGauge = new R_TRIG();

        // Properties
        //
        public double TargetPressure { get; set; }

        
        private string PressureOutOfTolerance = "PressureOutOfTolerance";

        // Constructor
        //
        public IoPressureControl(string module, XmlElement node, string ioModule = "")
        {
            base.Module = module;
            base.Name = node.GetAttribute("id");
            base.Display = node.GetAttribute("display");
            base.DeviceID = node.GetAttribute("schematicId");

            _diLogicProcessGasFlowing   = ParseDiNode("diLogicProcessGasFlowing", node, ioModule);

            _scAlarmRange               = SC.GetConfigItem($"{Module}.GasFlowPressureAlarmRange");
            _scAlarmTime                = SC.GetConfigItem($"{Module}.GasFlowPressureAlarmTime");
            _scIsIndependentControl     = SC.GetConfigItem($"{Module}.IsIndependentControl");
            _scIsBoostPumpInstalled     = SC.GetConfigItem($"{Module}.EnableBoosterPump");
            _scTvInstalled              = SC.GetConfigItem($"{Module}.EnableThrottleValve");
            //_enableTolerance = true;

            PressureGauge               = ParseDeviceNode<IoPressureMeter>(Module, "pressureMeter", node);
            ProcessGauge                = ParseDeviceNode<IoPressureMeter>(Module, "processMeter", node);
            ForelineGauge               = ParseDeviceNode<IoPressureMeter>(Module, "forelineMeter", node);
            LoadLockGauge               = ParseDeviceNode<IoPressureMeter>(Module, "loadlockMeter", node);
            ESCHeGauge                  = ParseDeviceNode<IoPressureMeter>(Module, "escHeGauge", node);
            //DryPump                     = ParseDeviceNode<IoPump>(Module, "drypump", node);

        }

        public bool Initialize()
        {
            //DEVICE.Register($"{Module}.{Name}.{AITPressureControlOperation.SetBoostPressure}", _setBoostPressure);
            DEVICE.Register($"{Module}.{Name}.{AITPressureControlOperation.SetChamberPressure}", _setChamberPressure);

            OP.Subscribe($"{Module}.{Name}.{AITPressureControlOperation.SetChamberPressure}", (out string reason, int time, object[] param) =>
            {
                _setChamberPressure(out reason, 0, param);
                return true;
            });


            EV.Subscribe(new EventItem("Event", PressureOutOfTolerance, "Pressure Out Of Tolerance", EventLevel.Alarm, EventType.HostNotification));

            return true;
        }

        //public void StartPump(bool on)
        //{
        //    this.DryPump?.Start(on);
        //}





        private bool? _setChamberPressure(out string reason, int time, object[] param)
        {
            double setpoint = Convert.ToDouble((string)param[0]);
            TargetPressure = setpoint;
            reason = $"Chamber pressure set to {setpoint} mTorr";
            return true;
        }

        public void Terminate()
        {
        }

        public void Monitor()
        {
            CheckTolerance();
            _trigProcessGauge.CLK = ProcessGauge.GaugeAlarm;
            if (_trigProcessGauge.Q) LOG.Write(eEvent.ERR_DEVICE_INFO, Module, "Process pressure gauge Alarm");
            _trigPressureGauge.CLK = PressureGauge.GaugeAlarm;
            if (_trigPressureGauge.Q) LOG.Write(eEvent.ERR_DEVICE_INFO, Module, "Chamber pressure gauge Alarm");
            _trigForelineGauge.CLK = ForelineGauge.GaugeAlarm;
            if (_trigForelineGauge.Q) LOG.Write(eEvent.ERR_DEVICE_INFO, Module, "Foreline pressure gauge Alarm");
        }

        public void CheckTolerance()
        {
            if (!EnableTolerance)
                return;

            //if (ThrottleValve != null && IsTvInstalled && ThrottleValve.PressureMode == PressureCtrlMode.TVPositionCtrl)
            //    return;

            _tolerance.Monitor(PressureGauge.Value,
                TargetPressure - Math.Abs(_scAlarmRange.DoubleValue),
                TargetPressure + Math.Abs(_scAlarmRange.DoubleValue), _scAlarmTime.DoubleValue);

            if (_tolerance.Trig)
            {
                EV.Notify(PressureOutOfTolerance);

                LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"Gas Flow Pressure Alarm Out of range in {_scAlarmTime.Value:0} seconds");
            }
        }

        public void Reset()
        {
            _trigProcessGauge.RST = true;
            _trigPressureGauge.RST = true;
            _trigForelineGauge.RST = true;
            if (_scAlarmTime != null)
            {
                _tolerance.Reset(_scAlarmTime.DoubleValue);
            }
        }
    }
}