using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Beckhoff.ModuleIO;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.TwinCat;
using CyberX8_Core;
using System;
using System.Collections.Generic;
using Aitex.Core.Util;
using MECF.Framework.Common.IOCore;

namespace CyberX8_RT.Devices.PUF
{
    public class PufVacuum : BaseDevice, IDevice
    {
        #region 常量
        private const string CHUCK = "Chuck";
        private const string SIDEA_CHUCK_OUT = "SideAChuckOut";
        private const string SIDEA_CHUCK_IN = "SideAChuckIn";
        private const string SIDEB_CHUCK_OUT = "SideBChuckOut";
        private const string SIDEB_CHUCK_IN = "SideBChuckIn";
        private const string CHUCKA_VAC = "ChuckAVac";
        private const string CHUCKB_VAC = "ChuckBVac";
        private const string CHUCKA_RELEASE = "ChuckARelease";
        private const string CHUCKB_RELEASE = "ChuckBRelease";
        private const string CHUCKA_VACUUM_STATUS = "ChuckAVacuumStatus";
        private const string CHUCKB_VACUUM_STATUS = "ChuckBVacuumStaus";
        private const string CHUCKA = "ChuckA";
        private const string CHUCKB = "ChuckB";
        private const string VACUUM_LEAK = "VacuumLeak";
        #endregion

        #region 内部变量
        private bool _chuck = false;
        private bool _sideAChuckOut = false;
        private bool _sideAChuckIn = false;
        private bool _sideBChuckOut=false;
        private bool _sideBChuckIn = false;
        private bool _chuckAWaferPresent;
        private bool _chuckBWaferPresent;

        private bool _chuckAReleased;
        private bool _chuckBReleased;
        private double _chuckAValue;
        private double _chuckBValue;

        private double _chuckVacuumCloseLimit;
        private double _chuckVacuumOpenLimit;
        private double _chuckVacuumWaferAbsent;
        private double _chuckVacuumWaferPresent;
        private string _chuckAVacuumStatus = "";
        private string _chuckBVacuumStatus = "";
        private DateTime _leakADateTime = DateTime.Now;
        private R_TRIG _leakATrig = new R_TRIG();
        private DateTime _leakBDateTime = DateTime.Now;
        private R_TRIG _leakBTrig = new R_TRIG();
        /// <summary>
        /// 变量是否初始化字典
        /// </summary>
        private Dictionary<string, bool> _variableInitializeDic = new Dictionary<string, bool>();
        /// <summary>
        /// 首次加载数据成功
        /// </summary>
        private bool _firstLoad = false;
        #endregion

        #region 属性
        /// <summary>
        /// ChuckA Wafer Present状态
        /// </summary>
        public bool ChuckAWaferPresent
        {
            get { return _chuckAWaferPresent; }
            set { _chuckAWaferPresent = value; }
        }
        /// <summary>
        /// ChuckB Wafer Present
        /// </summary>
        public bool ChuckBWaferPresent
        {
            get { return _chuckBWaferPresent; }
            set { _chuckBWaferPresent = value; }
        }
        /// <summary>
        /// Side A Vacuum状态
        /// </summary>
        public string ChuckAVacuumStatus
        {
            get { return _chuckAVacuumStatus; }
        }
        /// <summary>
        /// Side B Vacuum状态
        /// </summary>
        public string ChuckBVacuumStatus
        {
            get { return _chuckBVacuumStatus; }
        }
        /// <summary>
        /// Side B 是否关闭真空
        /// </summary>
        public bool ISChuckBReleased
        {
            get { return _chuckBReleased; }
        }
        /// <summary>
        /// Side A是否关闭真空
        /// </summary>
        public bool IsChuckAReleased
        {
            get { return _chuckAReleased; }
        }
        /// <summary>
        /// Chuck
        /// </summary>
        public bool Chuck
        {
            get { return _chuck; }
        }

        public bool SideAChuckOut
        {
            get { return _sideAChuckOut;  }
        }
        public bool SideAChuckIn
        {
            get { return _sideAChuckIn; }
        }

        public bool SideBChuckOut
        {
            get { return _sideBChuckOut; }
        }

        public bool SideBChuckIn
        {
            get { return _sideBChuckIn;}
        }
        /// <summary>
        /// 所有io变量是否初始化
        /// </summary>
        public bool IOInitialized { get { return AllIoVariableInitialized(); } }
        #endregion

        #region 事件
        public event EventHandler<string> OnVacuumLeak;

        public event EventHandler<string> OnVacuumResume;
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="moduleName"></param>
        public PufVacuum(string moduleName):base(moduleName,"Vacuum","Vacuum","Vacuum")
        {
            LoadConfigParameter();
        }
        /// <summary>
        /// 加载配置参数
        /// </summary>
        private void LoadConfigParameter()
        {
            _chuckVacuumCloseLimit = SC.GetValue<double>($"{Module}.ChuckVacuumCloseLimit");
            _chuckVacuumOpenLimit = SC.GetValue<double>($"{Module}.ChuckVacuumOpenLimit");
            _chuckVacuumWaferAbsent = SC.GetValue<double>($"{Module}.ChuckVacuumWaferAbsent");
            _chuckVacuumWaferPresent = SC.GetValue<double>($"{Module}.ChuckVacuumWaferPresent");
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <returns></returns>
        public bool Initialize()
        {
            SubscribeData();
            InitializeOperation();
            SubscribeValueAction();
            return true;
        }
        /// <summary>
        /// 初始化操作
        /// </summary>
        private void InitializeOperation()
        {
            OP.Subscribe($"{Module}.{PufMotionVaccumOpertaion.VacuumAOn}", VaccumAOnOperation);
            OP.Subscribe($"{Module}.{PufMotionVaccumOpertaion.VacuumBOn}", VaccumBOnOperation);
            OP.Subscribe($"{Module}.ChuckOn", (cmd,args) => { return ChuckOn(); });
            OP.Subscribe($"{Module}.ChuckOff", (cmd, args) => { return ChuckOff(); });
        }

        /// <summary>
        /// 订阅变量数值发生变化
        /// </summary>
        private void SubscribeValueAction()
        {
            BeckhoffIoSubscribeUpdateVariable(CHUCKA_VAC);
            BeckhoffIoSubscribeUpdateVariable(CHUCKB_VAC);
            BeckhoffIoSubscribeUpdateVariable(CHUCKA_RELEASE);
            BeckhoffIoSubscribeUpdateVariable(CHUCKB_RELEASE);
            BeckhoffIoSubscribeUpdateVariable(CHUCK);
            BeckhoffIoSubscribeUpdateVariable(SIDEA_CHUCK_IN);
            BeckhoffIoSubscribeUpdateVariable(SIDEA_CHUCK_OUT);
            BeckhoffIoSubscribeUpdateVariable(SIDEB_CHUCK_IN);
            BeckhoffIoSubscribeUpdateVariable(SIDEB_CHUCK_OUT);
        }

        /// <summary>
        /// 订阅IO变量
        /// </summary>
        /// <param name="variable"></param>
        private void BeckhoffIoSubscribeUpdateVariable(string variable)
        {
            _variableInitializeDic[variable] = false;
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", variable, UpdateVariableValue);
        }

        /// <summary>
        /// 是否所有IO变量初始化完成
        /// </summary>
        /// <returns></returns>
        private bool AllIoVariableInitialized()
        {
            foreach (string item in _variableInitializeDic.Keys)
            {
                if (!_variableInitializeDic[item])
                {
                    LOG.WriteLog(eEvent.ERR_DRYER, Module, $"{item} is not initialized");
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// 订阅数据
        /// </summary>
        private void SubscribeData()
        {
            DATA.Subscribe($"{Module}.{CHUCK}", () => _chuck, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{SIDEA_CHUCK_IN}", () => _sideAChuckIn, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{SIDEA_CHUCK_OUT}", () => _sideAChuckOut, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{SIDEB_CHUCK_IN}", () => _sideBChuckIn, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{SIDEB_CHUCK_OUT}", () => _sideBChuckOut, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{CHUCKA_RELEASE}", () => _chuckAReleased,SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{CHUCKB_RELEASE}", () => _chuckBReleased, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{CHUCKA_VAC}", () => _chuckAValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{CHUCKB_VAC}", () => _chuckBValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{CHUCKA_VACUUM_STATUS}", () => _chuckAVacuumStatus, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.{CHUCKB_VACUUM_STATUS}", () => _chuckBVacuumStatus, SubscriptionAttribute.FLAG.IgnoreSaveDB);
        }

        /// 更新变量数值
        /// </summary>
        /// <param name="variable"></param>
        /// <param name="value"></param>
        private void UpdateVariableValue(string variable, object value)
        {
            if(!_firstLoad)
            {
                _firstLoad = true;
                VacuumAOn();
                VacuumBOn();
            }
            if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable])
            {
                _variableInitializeDic[variable] = true;
            }
            if (variable == $"{CHUCKA_RELEASE}")
            {
                _chuckAReleased = (bool)value;
                var item = JudgeWaferPresent(_chuckAValue, _chuckAReleased, CHUCKA);
                _chuckAWaferPresent = item.Item1;
                _chuckAVacuumStatus = item.Item2;
                _leakATrig.CLK = item.Item2 == VACUUM_LEAK;
                if (_leakATrig.Q)
                {
                    _leakADateTime = DateTime.Now;
                }
            }
            else if(variable==$"{CHUCKB_RELEASE}")
            {
                _chuckBReleased=(bool)value;
                var item = JudgeWaferPresent(_chuckBValue, _chuckBReleased, CHUCKB);
                _leakBTrig.CLK = item.Item2 == VACUUM_LEAK;
                if (_leakBTrig.Q)
                {
                    _leakBDateTime = DateTime.Now;
                }
                _chuckBWaferPresent = item.Item1;
                _chuckBVacuumStatus = item.Item2;
            }
            else if(variable==$"{CHUCKA_VAC}")
            {
                _chuckAValue = (double)value;
                var item = JudgeWaferPresent(_chuckAValue, _chuckAReleased, CHUCKA);
                _leakATrig.CLK = item.Item2 == VACUUM_LEAK;
                if (_leakATrig.Q)
                {
                    _leakADateTime = DateTime.Now;
                }
                _chuckAWaferPresent =item.Item1;
                _chuckAVacuumStatus=item.Item2;
            }
            else if(variable==$"{CHUCKB_VAC}")
            {
                _chuckBValue=(double)value;
                var item = JudgeWaferPresent(_chuckBValue, _chuckBReleased, CHUCKB);
                _leakBTrig.CLK = item.Item2 == VACUUM_LEAK;
                if (_leakBTrig.Q)
                {
                    _leakBDateTime = DateTime.Now;
                }
                _chuckBWaferPresent = item.Item1;
                _chuckBVacuumStatus = item.Item2;
            }
            else
            {
                UpdateChuck(variable, (bool)value);
            }
        }
        /// <summary>
        /// 更新 chuck
        /// </summary>
        /// <param name="variable"></param>
        /// <param name="value"></param>
        private void UpdateChuck(string variable,bool value)
        {
            switch (variable)
            {
                case CHUCK:
                    _chuck = value;
                    LOG.WriteLog(eEvent.INFO_PUF, Module, $"Chuck value is {value}");
                    break;
                case SIDEA_CHUCK_IN:
                    _sideAChuckIn = value;
                    LOG.WriteLog(eEvent.INFO_PUF, Module, $"SideA Chuck In value is {value}");
                    break;
                case SIDEA_CHUCK_OUT:
                    _sideAChuckOut = value;
                    LOG.WriteLog(eEvent.INFO_PUF, Module, $"SideA Chuck Out value is {value}");
                    break;
                case SIDEB_CHUCK_IN:
                    _sideBChuckIn = value;
                    LOG.WriteLog(eEvent.INFO_PUF, Module, $"SideB Chuck In value is {value}");
                    break;
                case SIDEB_CHUCK_OUT:
                    _sideBChuckOut = value;
                    LOG.WriteLog(eEvent.INFO_PUF, Module, $"SideB Chuck Out value is {value}");
                    break;
            }
        }
        /// <summary>
        /// 检验ChuckOut
        /// </summary>
        /// <returns></returns>
        public bool CheckChuckOut()
        {
            if (!_chuck)
            {
                return false;
            }
            if (!_sideAChuckOut)
            {
                return false;
            }
            if (!_sideBChuckOut)
            {
                return false;
            }
            if (_sideAChuckIn)
            {
                return false;
            }
            if (_sideBChuckIn)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 检验ChuckIn
        /// </summary>
        /// <returns></returns>
        public bool CheckChuckIn()
        {
            if (_chuck)
            {
                return false;
            }
            if (_sideAChuckOut)
            {
                return false;
            }
            if (_sideBChuckOut)
            {
                return false;
            }
            if (!_sideAChuckIn)
            {
                return false;
            }
            if (!_sideBChuckIn)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 判定Wafer Present
        /// </summary>
        /// <param name="chuckValue"></param>
        /// <param name="chuckRelease"></param>
        /// <returns></returns>
        private (bool,string) JudgeWaferPresent(double chuckValue,bool chuckRelease,string chuck)
        {
            LoadConfigParameter();
            if (!chuckRelease)
            {
                if(chuckValue < _chuckVacuumWaferPresent)
                {
                    ResumeVacuum();
                    return (true,"WaferPresent");
                }
                else if( chuckValue > _chuckVacuumWaferAbsent)
                {
                    ResumeVacuum();
                    return (false,"WaferAbsent");
                }
                else
                {
                    return (false,"InvalidData");
                }

            }
            else
            {
                if(chuckValue<=_chuckVacuumCloseLimit)
                {
                    return (false,"VacuumLeak");
                }
                else if(chuckValue<=_chuckVacuumOpenLimit)
                {
                    ResumeVacuum();
                    return (false, "VacuumOff");
                }
                else
                {
                    ResumeVacuum();
                    return (false, "");
                }
            }
        }
        /// <summary>
        /// 故障恢复
        /// </summary>
        private void ResumeVacuum()
        {
            if (OnVacuumResume != null)
            {
                OnVacuumResume(this, Module);
            }
        }

        /// <summary>
        /// VacuumAOn操作
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private bool VaccumAOnOperation(string cmd, object[] args)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CHUCKA_RELEASE}");
            if(!string.IsNullOrEmpty(ioName))
            {
                IOModuleManager.Instance.WriteIoValue(ioName, args[1]);
            }
            return true;
        }
        /// <summary>
        /// VacuumBOn操作
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private bool VaccumBOnOperation(string cmd, object[] args)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CHUCKB_RELEASE}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, args[1]);
            }
            return true;
        }
        /// <summary>
        /// Chuck On
        /// </summary>
        /// <returns></returns>
        public bool ChuckOn()
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CHUCK}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, true);
            }
            return false;
        }
        /// <summary>
        /// Chuck Off
        /// </summary>
        /// <returns></returns>
        public bool ChuckOff()
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CHUCK}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, false);
            }
            return false;
        }
        /// <summary>
        /// VacuumA关闭
        /// </summary>
        public bool VacuumAOff()
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CHUCKA_RELEASE}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, true);
            }
            return false;
        }
        /// <summary>
        /// VacuumB关闭
        /// </summary>
        public bool VacuumBOff()
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CHUCKB_RELEASE}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, true);
            }
            return false;
        }
        /// <summary>
        /// VacuumA打开
        /// </summary>
        public bool VacuumAOn()
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CHUCKA_RELEASE}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, false);
            }
            return false;
        }
        /// <summary>
        /// VacuumB打开
        /// </summary>
        public bool VacuumBOn()
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CHUCKB_RELEASE}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, false);
            }
            return false;
        }
        /// <summary>
        /// 定时器
        /// </summary>
        public void OnTimer()
        {
            if (_leakATrig.CLK && DateTime.Now.Subtract(_leakADateTime).TotalSeconds >= 2&&_chuckAVacuumStatus!=VACUUM_LEAK)
            {
                _chuckAVacuumStatus = VACUUM_LEAK;
                LOG.WriteLog(eEvent.ERR_PUF, Module, $"ChuckA vacuum leak");

                if (OnVacuumLeak != null)
                {
                    OnVacuumLeak(this, Module);
                }
            }
            if (_leakBTrig.CLK && DateTime.Now.Subtract(_leakBDateTime).TotalSeconds >= 2 && _chuckBVacuumStatus != VACUUM_LEAK)
            {
                _chuckBVacuumStatus = VACUUM_LEAK;
                LOG.WriteLog(eEvent.ERR_PUF, Module, $"ChuckB vacuum leak");

                if (OnVacuumLeak != null)
                {
                    OnVacuumLeak(this, Module);
                }
            }
        }
        /// <summary>
        /// 监控
        /// </summary>
        public void Monitor()
        {
        }
        /// <summary>
        /// 重置
        /// </summary>
        public void Reset()
        {
        }
        /// <summary>
        /// 中止
        /// </summary>
        public void Terminate()
        {
        }
    }
}