using System;
using System.Xml;
using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.Util;

namespace Aitex.Core.RT.Device.Unit
{

    public class IoHeater : BaseDevice, IDevice
    {
        public double SetPointLimit
        {
            get
            {
                if (_aoSetPointLimit != null)
                    return _aoSetPointLimit.Value;

                return 100;
            }
        }

        [Subscription(AITHeaterPropertyName.MonitorTcFeedback)]
        public float MonitorTcFeedback
        {
            get
            {
                if (_aiMonitorTcFeedback != null)
                    return _aiMonitorTcFeedback.Value;

                return 0;
            }
        }

        [Subscription(AITHeaterPropertyName.ControlTcFeedback)]
        public float ControlTcFeedback
        {
            get
            {
                if (_aiControlTcFeedback != null)
                    return _aiControlTcFeedback.Value;

                return 0;
            }
        }

        [Subscription(AITHeaterPropertyName.ControlTcSetPoint)]
        public float ControlTcSetPoint
        {
            get
            {
                if (_aoSetPoint != null)
                    return _aoSetPoint.Value;

                return 0;
            }
        }

        [Subscription(AITHeaterPropertyName.IsMonitorTcBroken)]
        public bool IsMonitorTcBroken
        {
            get
            {
                if (_diMonitorTcBroken != null)
                    return _diMonitorTcBroken.Value;

                return false;
            }
        }

        [Subscription(AITHeaterPropertyName.IsControlTcBroken)]
        public bool IsControlTcBroken
        {
            get
            {
                if (_diControlTcBroken != null)
                    return _diControlTcBroken.Value;

                return false;
            }
        }
 
        [Subscription(AITHeaterPropertyName.IsPowerOnFeedback)]
        public bool IsPowerOnFeedback
        {
            get
            {
                if (_diPowerOnFeedback != null)
                    return _diPowerOnFeedback.Value;

                if (_doPowerOn != null)
                    return _doPowerOn.Value;

                return false;
            }
        }

        [Subscription(AITHeaterPropertyName.IsPowerOnSetPoint)]
        public bool IsPowerOnSetPoint
        {
            get
            {
                if (_doPowerOn != null)
                    return _doPowerOn.Value;

                return false;
            }
        }

        public string Unit
        {
            get; set;
        }
        /*
               doPowerOn="DO_Chamber_heater_power_contactor__coil"
               diPowerOnFeedback="DI_Chamber_heater_power_fb"
               diControlTcBroken="DI_chamber_wall_control_tc_broken"
               diMonitorTcBroken="DI_chamber_wall_monitor_tc_broken"
               aoSetPoint="AO_chamber_wall_temp_setpotint"
               aiFeedback="AI_Chamber_wall_control_tc_fb"
               aoSetPointLimit="AO_chamber_wall_temp_limit_setpotint"
               aiMonitor="AI_chamber_wall_monitor_tc_fb"/>
         * 
         */

        private DIAccessor _diPowerOnFeedback = null;
        private DIAccessor _diControlTcBroken;
        private DIAccessor _diMonitorTcBroken;

        private DOAccessor _doPowerOn = null;

        private AIAccessor _aiControlTcFeedback = null;
        private AIAccessor _aiMonitorTcFeedback = null;

        private AOAccessor _aoSetPoint = null;
        private AOAccessor _aoSetPointLimit = null;

        private R_TRIG _trigMonitorTcBroken = new R_TRIG();
        private R_TRIG _trigControlTcBroken = new R_TRIG();
 
        public IoHeater(string module, XmlElement node)
        {
            base.Module = module;
            base.Name = node.GetAttribute("id");
            base.Display = node.GetAttribute("display");
            base.DeviceID = node.GetAttribute("schematicId");
            
            Unit = node.GetAttribute("unit");

            _diPowerOnFeedback = ParseDiNode("diPowerOnFeedback", node);
            _diControlTcBroken = ParseDiNode("diControlTcBroken", node);
            _diMonitorTcBroken = ParseDiNode("diMonitorTcBroken", node);

            _doPowerOn = ParseDoNode("doPowerOn", node);

            _aiControlTcFeedback = ParseAiNode("aiFeedback", node);
            _aiMonitorTcFeedback = ParseAiNode("aiMonitor", node);

            _aoSetPoint = ParseAoNode("aoSetPoint", node);
            _aoSetPointLimit = ParseAoNode("aoSetPointLimit", node);
 

        }

        public void UpdateConfig(double setPointLimit)
        {
            if (_aoSetPointLimit != null)
                _aoSetPointLimit.Value = (float)setPointLimit;
        }


        public bool Initialize()
        {
                                DATA.Subscribe(string.Format("Device.{0}.{1}", Module ,  Name), () =>
                    {
                        AITHeaterData data = new AITHeaterData()
                        {
                            DeviceName =  Name,
                            DeviceSchematicId =  DeviceID,
                            DisplayName =  Display,
                            
                            FeedBack =  ControlTcFeedback,
                            MonitorTcFeedBack = MonitorTcFeedback,
 
                            Scale =  SetPointLimit,
                            SetPoint =  ControlTcSetPoint,
                            
                            IsPowerOn = IsPowerOnFeedback,
                            IsPowerOnSetPoint = IsPowerOnSetPoint,

                            IsControlTcBroken = IsControlTcBroken,
                            IsMonitorTcBroken = IsMonitorTcBroken,
                            
                            Unit = Unit,
                        };

                        return data;
                    }, SubscriptionAttribute.FLAG.IgnoreSaveDB);

            DEVICE.Register(String.Format("{0}.{1}", Name, AITHeaterOperation.SetPowerOnOff), (out string reason, int time, object[] param) =>
                                                                                              {
                                                                                                  reason = "";
                bool isEnable =  Convert.ToBoolean((string)param[0]);

                bool result = true;
                if (_doPowerOn != null)
                {
                    result &= _doPowerOn.SetValue(isEnable, out reason);
                }

                if (result)
                    reason = string.Format("Set Heater {0} Power {1}", Name, isEnable ? "On" : "Off");

                return result;
            });

            DEVICE.Register(String.Format("{0}.{1}", Name, AITHeaterOperation.Ramp), (out string reason, int time, object[] param) =>{
                float setpoint = (float) Convert.ToDouble( (string) param[0]);

                if (setpoint > SetPointLimit || setpoint < 0)
                {
                    reason = string.Format("Heater {0} temperature setpoint {1} is not valid, should be (0, {2})", Display, setpoint, SetPointLimit);
                }

                if (_aoSetPoint != null)
                    _aoSetPoint.Value = setpoint;
 
                reason = string.Format("Heater {0} Set to {1}", Display, setpoint);

                return true;
            });

            return true;
        }

        public void Stop()
        {
            if (_aoSetPoint != null)
            {
                _aoSetPoint.Value = 0;
            }
        }

        public void Terminate()
        {
        }

        public void Monitor()
        {
            _trigControlTcBroken.CLK = IsControlTcBroken;
            if (_trigControlTcBroken.Q)
            {
                EV.PostMessage(Module, EventEnum.DefaultAlarm, string.Format("{0}, found control TC broken", Display));
            }

            _trigMonitorTcBroken.CLK = IsMonitorTcBroken;
            if (_trigMonitorTcBroken.Q)
            {
                EV.PostMessage(Module, EventEnum.DefaultAlarm, string.Format("{0}, found monitor TC broken", Display));
            }
        }
        
        public void Reset()
        {
            _trigControlTcBroken.RST = true;
            _trigMonitorTcBroken.RST = true;
        }
    }
}