using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.UI.Control;
using Aitex.Core.Util;
using MECF.Framework.Common.Beckhoff.IOAxis;
using MECF.Framework.Common.Beckhoff.ModuleIO;
using MECF.Framework.Common.CommonData;
using MECF.Framework.Common.CommonData.Metal;
using MECF.Framework.Common.Persistent.Reservoirs;
using MECF.Framework.Common.TwinCat;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using MECF.Framework.Common.ToolLayout;
using MECF.Framework.Common.Layout;
using Aitex.Core.RT.SCCore;
using System.Diagnostics;
using CyberX8_Core;
using CyberX8_RT.Devices.Metal;
using CyberX8_RT.Devices.Reservoir;
using MECF.Framework.Common.IOCore;

namespace CyberX8_RT.Devices.Metal
{
    public class CompactMembranMetalDevice : MetalCellDevice
    {
        private enum ANCellStatus
        {
            Unknow,
            Filling,
            Emptying,
            Full,
            Empty
        }

        private enum ANCellOperation
        {
            None,
            Fill,
            Drain
        }
        #region 常量 
        private const string SIDE_A = "SideA";
        private const string SIDE_B = "SideB";
        private const string AN_A_PINENABLE = "ANAPinEnable";
        private const string AN_B_PINENABLE = "ANBPinEnable";
        private const string AN_A_POUTENABLE = "ANAPoutEnable";
        private const string AN_B_POUTENABLE = "ANBPoutEnable";
        private const string CELL_FLOW = "CellFlow";
        private const string WH_CLAMP = "WHClamp";
        private const string WH_UNCLAMP = "WHUnclamp";
        private const string CELL_FLOW_VALVE = "CellFlowValve";

        private const string COUNTER_VALUE = "CounterValue";
        private const string COUNTER_START = "Start";
        private const string COUNTER_STOP = "Stop";
        private const string COUNTER_RESET = "Reset";

        private const string AN_A_CELL_FLOW = "ANACellFlow";
        private const string AN_B_CELL_FLOW = "ANBCellFlow";

        #endregion

        #region 内部变量
        /// <summary>
        /// 设备数据
        /// </summary>
        private CompactMembranMetalDeviceData _metalDeviceData = new CompactMembranMetalDeviceData();
        /// <summary>
        /// 变量是否初始化字典
        /// </summary>
        private Dictionary<string, bool> _variableInitializeDic = new Dictionary<string, bool>();
        /// <summary>
        /// 阳极A面cellFlow
        /// </summary>
        private CounterFlowData _anACellFlow = new CounterFlowData();
        /// <summary>
        /// 阳极B面cellFlow
        /// </summary>
        private CounterFlowData _anBCellFlow = new CounterFlowData();
        /// <summary>
        /// Counter字典
        /// </summary>
        private Dictionary<string, CounterFlowData> _nameCounterFlowData = new Dictionary<string, CounterFlowData>();
        /// <summary>
        /// 当前阳极A面操作
        /// </summary>
        private ANCellOperation _currentANACellOperation;
        /// <summary>
        /// 当前阳机B面操作
        /// </summary>
        private ANCellOperation _currentANBCellOperation;
        /// <summary>
        /// AN Fill Routine
        /// </summary>
        private CompactMembranFillRoutine _anANACellFillRoutine;
        /// <summary>
        /// 阳机B面Fill Routine
        /// </summary>
        private CompactMembranFillRoutine _anANBCellFillRoutine;
        /// <summary>
        /// 阳极A面流量总数值 
        /// </summary>
        private double _anATotalFillFlow = 0;
        /// <summary>
        /// 阳极B面流量总数值 
        /// </summary>
        private double _anBTotalFillFlow = 0;
        /// <summary>
        /// 阳极A面Drain时间
        /// </summary>
        private DateTime _anADrainTime = DateTime.Now;
        /// <summary>
        /// 阳极B面Drain时间
        /// </summary>
        private DateTime _anBDrainTime = DateTime.Now;
        /// <summary>
        /// Flow Valve计时
        /// </summary>
        private Stopwatch _flowValveStopWatch = new Stopwatch();
        /// <summary>
        /// ANA Flow Valve计时
        /// </summary>
        private Stopwatch _anaFlowValveStopWatch = new Stopwatch();
        /// <summary>
        /// ANB Flow Valve计时
        /// </summary>
        private Stopwatch _anbFlowValveStopWatch = new Stopwatch();
        #endregion

        #region 属性
        /// <summary>
        /// 设备数据
        /// </summary>
        public CompactMembranMetalDeviceData MetalDeviceData { get { return _metalDeviceData; } }
        /// <summary>
        /// 阳极A面CellFlow
        /// </summary>
        public CounterFlowData ANACellFlow { get { return _anACellFlow; } }
        /// <summary>
        /// 阳极B面CellFlow
        /// </summary>
        public CounterFlowData ANBCellFlow { get { return _anBCellFlow; } }
        /// <summary>
        /// Flow Valve稳定状态
        /// </summary>
        public bool FlowValveStable { get { return _metalDeviceData.CellFlowValve && _flowValveStopWatch.ElapsedMilliseconds >= 3000; } }
        /// <summary>
        /// ANA Flow 稳定状态
        /// </summary>
        public bool ANAFlowValveStable { get { return _metalDeviceData.ANAPinEnable && _anaFlowValveStopWatch.ElapsedMilliseconds >= 3000; } }
        /// <summary>
        /// ANB Flow 稳定状态
        /// </summary>
        public bool ANBFlowValveStable { get { return _metalDeviceData.ANBPinEnable && _anbFlowValveStopWatch.ElapsedMilliseconds >= 3000; } }
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="moduleName"></param>
        public CompactMembranMetalDevice(string moduleName) : base(moduleName)
        {
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <returns></returns>
        public override bool Initialize()
        {
            base.Initialize();
            InitializeRoutine();
            SubscribeValueAction();
            SubscribeData();
            return true;
        }
        /// <summary>
        /// 初始化Routine
        /// </summary>
        private void InitializeRoutine()
        {
            _anANACellFillRoutine = new CompactMembranFillRoutine(Module, "A");
            _anANBCellFillRoutine = new CompactMembranFillRoutine(Module, "B");
        }
        /// <summary>
        /// 订阅数据
        /// </summary>
        private void SubscribeData()
        {
            DATA.Subscribe($"{Module}.MetalData", () => _metalDeviceData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.SideAFlow", () => ANACellFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.SideAFlowStatus", () => ANACellFlow.Status, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.SideBFlow", () => ANBCellFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.SideBFlowStatus", () => ANBCellFlow.Status, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.CellFlow", () => MetalDeviceData.CellFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ANBPinEnable", () => _metalDeviceData.ANBPinEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ANAPinEnable", () => _metalDeviceData.ANAPinEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ANAPoutEnable", () => _metalDeviceData.ANAPoutEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ANBPoutEnable", () => _metalDeviceData.ANBPoutEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.CellFlowEnable", () => _metalDeviceData.CellFlowValve, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.WaferShuttleClamped", () => _metalDeviceData.WHClamp, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.WaferShuttleUnclamped", () => _metalDeviceData.WHUnclamp, SubscriptionAttribute.FLAG.IgnoreSaveDB);
        }
        /// <summary>
        /// 订阅变量数值发生变化
        /// </summary>
        private void SubscribeValueAction()
        {
            BeckhoffIoSubscribeUpdateVariable(AN_A_PINENABLE);
            BeckhoffIoSubscribeUpdateVariable(AN_B_PINENABLE);
            BeckhoffIoSubscribeUpdateVariable(AN_A_POUTENABLE);
            BeckhoffIoSubscribeUpdateVariable(AN_B_POUTENABLE);
            BeckhoffIoSubscribeUpdateVariable(CELL_FLOW);
            BeckhoffIoSubscribeUpdateVariable(WH_CLAMP);
            BeckhoffIoSubscribeUpdateVariable(WH_UNCLAMP);
            BeckhoffIoSubscribeUpdateVariable(CELL_FLOW_VALVE);

            BeckhoffCounterSubscribeUpdateVariable(AN_A_CELL_FLOW, ANACellFlow);
            BeckhoffCounter anACellFlowCounter = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_A_CELL_FLOW}");
            if (anACellFlowCounter != null)
            {
                ANACellFlow.Period = anACellFlowCounter.Period;
            }
            BeckhoffCounterSubscribeUpdateVariable(AN_B_CELL_FLOW, ANBCellFlow);
            BeckhoffCounter anBCellFlowCounter = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_B_CELL_FLOW}");
            if (anACellFlowCounter != null)
            {
                ANBCellFlow.Period = anBCellFlowCounter.Period;
            }
        }
        /// <summary>
        /// 订阅Operation
        /// </summary>
        protected override void InitializeOperation()
        {
            base.InitializeOperation();
            OP.Subscribe($"{Module}.ANAFillOn", AnSideAFillOn);
            OP.Subscribe($"{Module}.ANAFillOff", AnSideAFillOff);
            OP.Subscribe($"{Module}.ANBFillOn", AnSideBFillOn);
            OP.Subscribe($"{Module}.ANBFillOff", AnSideBFillOff);

            OP.Subscribe($"{Module}.ANADrainOn", AnSideADrainOn);
            OP.Subscribe($"{Module}.ANADrainOff", AnSideADrainOff);
            OP.Subscribe($"{Module}.ANBDrainOn", AnSideBDrainOn);
            OP.Subscribe($"{Module}.ANBDrainOff", AnSideBDrainOff);

            OP.Subscribe($"{Module}.WHClampOn", WHClampOn);
            OP.Subscribe($"{Module}.WHClampOff", WHClampOff);
            OP.Subscribe($"{Module}.WHUnclampOn", WHUnClampOn);
            OP.Subscribe($"{Module}.WHUnclampOff", WHUnClampOff);
            OP.Subscribe($"{Module}.CellFlowValveOn", CellFlowValveOn);
            OP.Subscribe($"{Module}.CellFlowValveOff", CellFlowValveOff);

            OP.Subscribe($"{Module}.WaferHolderClampOn", WaferHolderClampOn);
            OP.Subscribe($"{Module}.WaferHolderUnclampOn", WaferHolderUnclampOn);
            OP.Subscribe($"{Module}.WaferHolderDisconnect", WaferHolderDisConnect);

            OP.Subscribe($"{Module}.A.Fill", ANSideAFillOperation);
            OP.Subscribe($"{Module}.B.Fill", ANSideBFillOperation);
            OP.Subscribe($"{Module}.A.Stop", ANSideAStopOperation);
            OP.Subscribe($"{Module}.B.Stop", ANSideBStopOperation);
            OP.Subscribe($"{Module}.A.Drain", ANSideADrainOperation);
            OP.Subscribe($"{Module}.B.Drain", ANSideBDrainOperation);
        }

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

        /// <summary>
        /// 更新变量数值
        /// </summary>
        /// <param name="variable"></param>
        /// <param name="value"></param>
        private void UpdateVariableValue(string variable, object value)
        {
            if (!_metalDeviceData.IsDataInitialized)
            {
                _metalDeviceData.IsDataInitialized = true;
            }
            PropertyInfo property = _metalDeviceData.GetType().GetProperty(variable);
            if (property != null)
            {
                property.SetValue(_metalDeviceData, value);
            }
            if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable])
            {
                _variableInitializeDic[variable] = true;
            }

            if (variable == CELL_FLOW_VALVE)
            {
                bool bValue = (bool)value;
                if (bValue)
                {
                    _flowValveStopWatch.Restart();
                }
            }
            else if (variable == AN_A_PINENABLE)
            {
                bool bValue = (bool)value;
                if (bValue)
                {
                    _anaFlowValveStopWatch.Restart();
                }
            }
            else if (variable == AN_B_PINENABLE)
            {
                bool bValue = (bool)value;
                if (bValue)
                {
                    _anbFlowValveStopWatch.Restart();
                }
            }
        }

        /// <summary>
        /// 订阅Counter变量
        /// </summary>
        /// <param name="variable"></param>
        private void BeckhoffCounterSubscribeUpdateVariable(string variable, CounterFlowData counterFlowData)
        {
            _nameCounterFlowData[$"{Module}.{variable}"] = counterFlowData;
            BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_VALUE, UpdateCounterVariableValue);
            BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_START, UpdateCounterVariableValue);
            BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_STOP, UpdateCounterVariableValue);
            BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_RESET, UpdateCounterVariableValue);
        }

        /// <summary>
        /// 更新变量数值
        /// </summary>
        /// <param name="variable"></param>
        /// <param name="value"></param>
        private void UpdateCounterVariableValue(string variable, object value)
        {
            string[] strAry = variable.Split('.');
            string lastVariable = strAry[strAry.Length - 1];
            PropertyInfo property = null;
            string key = variable.Replace($".{lastVariable}", "");
            if (_nameCounterFlowData.ContainsKey(key))
            {
                CounterFlowData counterFlowData = _nameCounterFlowData[key];
                if (counterFlowData != null)
                {
                    property = counterFlowData.GetType().GetProperty(lastVariable);
                    if (property != null)
                    {
                        property.SetValue(counterFlowData, value);
                    }
                }
            }
        }

        #region Fill
        /// <summary>
        /// AN A面Fill On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool AnSideAFillOn(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_PINENABLE}");
            string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_CELL_FLOW}");
            bool result = BeckhoffCounterManager.Instance.StartCounter(countName);
            if (result)
            {
                return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// AN A面Fill Off
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool AnSideAFillOff(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_PINENABLE}");
            string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_CELL_FLOW}");
            bool result = BeckhoffCounterManager.Instance.StopCounter(countName);
            if (result)
            {
                result = BeckhoffCounterManager.Instance.ResetCounter(countName, 0);
                if (result)
                {
                    return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
                }
            }
            return false;
        }

        /// <summary>
        /// AN B面Fill On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool AnSideBFillOn(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_PINENABLE}");
            string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_CELL_FLOW}");
            bool result = BeckhoffCounterManager.Instance.StartCounter(countName);
            if (result)
            {
                return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// AN B面Fill Off
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool AnSideBFillOff(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_PINENABLE}");
            string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_CELL_FLOW}");
            bool result = BeckhoffCounterManager.Instance.StopCounter(countName);
            if (result)
            {
                result = BeckhoffCounterManager.Instance.ResetCounter(countName, 0);
                if (result)
                {
                    return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
                }
            }
            return false;
        }
        #endregion

        #region Drain
        /// <summary>
        /// AN A面Drain On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private bool AnSideADrainOn(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_POUTENABLE}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
        }
        /// <summary>
        /// AN A面Drain Off
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool AnSideADrainOff(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_POUTENABLE}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
        }

        /// <summary>
        /// AN B面Drain On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private bool AnSideBDrainOn(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_POUTENABLE}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
        }
        /// <summary>
        /// AN A面Drain Off
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool AnSideBDrainOff(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_POUTENABLE}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
        }
        #endregion

        #region WH Clamp
        /// <summary>
        /// WH Clamp On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private bool WHClampOn(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
        }

        /// <summary>
        /// WH Clamp Off
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private bool WHClampOff(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
        }
        /// <summary>
        /// WH UnClamp On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private bool WHUnClampOn(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
        }

        /// <summary>
        /// WH UnClamp Off
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private bool WHUnClampOff(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
        }
        /// <summary>
        /// Wafer Holder Clamp On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool WaferHolderClampOn(string cmd, object[] param)
        {
            string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
            bool result = BeckhoffIOManager.Instance.WriteIoValue(unclampIOName, false);
            if (result)
            {
                string clampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
                return BeckhoffIOManager.Instance.WriteIoValue(clampIOName, true);
            }
            return false;
        }
        /// <summary>
        /// Wafer Holder Clamp On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool WaferHolderUnclampOn(string cmd, object[] param)
        {
            string clampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
            bool result = BeckhoffIOManager.Instance.WriteIoValue(clampIOName, false);
            if (result)
            {
                string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
                return BeckhoffIOManager.Instance.WriteIoValue(unclampIOName, true);
            }
            return false;
        }
        /// <summary>
        /// Wafer Holder Disconnect
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool WaferHolderDisConnect(string cmd, object[] param)
        {
            string clampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
            bool result = BeckhoffIOManager.Instance.WriteIoValue(clampIOName, false);
            if (result)
            {
                string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
                return BeckhoffIOManager.Instance.WriteIoValue(unclampIOName, false);
            }
            return false;
        }
        #endregion

        #region Cell Flow Valve
        /// <summary>
        /// Cell Flow On
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool CellFlowValveOn(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CELL_FLOW_VALVE}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
        }
        /// <summary>
        /// Cell Flow Off
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public bool CellFlowValveOff(string cmd, object[] param)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CELL_FLOW_VALVE}");
            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
        }
        #endregion

        #region AN Fill
        /// <summary>
        /// 阳极A面Fill
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="objects"></param>
        /// <returns></returns>
        private bool ANSideAFillOperation(string cmd, object[] objects)
        {
            if (_currentANACellOperation != ANCellOperation.None)
            {
                LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANACellOperation},cannot execute AN Side A Fill");
                return false;
            }
            bool result = _anANACellFillRoutine.Start() == RState.Running;
            if (result)
            {
                _currentANACellOperation = ANCellOperation.Fill;
            }
            return result;
        }
        /// <summary>
        /// 阳极B面Fill
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="objects"></param>
        /// <returns></returns>
        private bool ANSideBFillOperation(string cmd, object[] objects)
        {
            if (_currentANBCellOperation != ANCellOperation.None)
            {
                LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANBCellOperation},cannot execute AN Side B Fill");
                return false;
            }
            bool result = _anANBCellFillRoutine.Start() == RState.Running;
            if (result)
            {
                _currentANBCellOperation = ANCellOperation.Fill;
            }
            return result;
        }
        #endregion

        #region AN Drain
        /// <summary>
        /// 阳极A面Drain
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="objects"></param>
        /// <returns></returns>
        private bool ANSideADrainOperation(string cmd, object[] objects)
        {
            if (_currentANACellOperation != ANCellOperation.None)
            {
                LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANACellOperation},cannot execute AN Side A Drain");
                return false;
            }

            bool result = true;
            CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
            if (CheckOtherMetalDeviceDrainStatus(reservoirDevice, "A"))
            {
                return false;
            }
            if (reservoirDevice != null && reservoirDevice.ReservoirData.ANADrainPump == 0)
            {
                result = reservoirDevice.AnADrainPumpOn("", null);
            }
            if (result)
            {
                result = AnSideADrainOn("", null);
                if (result)
                {
                    ANACellFlow.Status = ANCellStatus.Emptying.ToString();
                    _anATotalFillFlow = 0;
                    _anADrainTime = DateTime.Now;
                }
                else
                {
                    reservoirDevice.AnADrainPump(0);
                }
            }
            return result;
        }
        /// <summary>
        /// 其他Metal Drain是否打开
        /// </summary>
        /// <param name="reservoirDevice"></param>
        /// <param name="side"></param>
        /// <returns></returns>
        private bool CheckOtherMetalDeviceDrainStatus(CompactMembranReservoirDevice reservoirDevice, string side)
        {
            if (reservoirDevice == null)
            {
                return false;
            }
            ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(reservoirDevice.Module);
            if (reservoirItem != null)
            {
                foreach (var item in reservoirItem.MetalCells)
                {
                    if (item.ModuleName != Module)
                    {
                        CompactMembranMetalDevice metalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(item.ModuleName);
                        if (metalDevice != null)
                        {
                            if (side == "A" && metalDevice.MetalDeviceData.ANAPoutEnable)
                            {
                                LOG.WriteLog(eEvent.ERR_METAL, Module, $"{item.ModuleName} A Drain is on");
                                return true;
                            }
                            if (side == "B" && metalDevice.MetalDeviceData.ANBPoutEnable)
                            {
                                LOG.WriteLog(eEvent.ERR_METAL, Module, $"{item.ModuleName} B Drain is on");
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// 阳极A面Drain
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="objects"></param>
        /// <returns></returns>
        private bool ANSideBDrainOperation(string cmd, object[] objects)
        {
            if (_currentANBCellOperation != ANCellOperation.None)
            {
                LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANBCellOperation},cannot execute AN Side A Drain");
                return false;
            }

            bool result = true;
            CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
            if (CheckOtherMetalDeviceDrainStatus(reservoirDevice, "B"))
            {
                return false;
            }
            if (reservoirDevice != null && reservoirDevice.ReservoirData.ANBDrainPump == 0)
            {
                result = reservoirDevice.AnBDrainPumpOn("", null);
            }
            if (result)
            {
                result = AnSideBDrainOn("", null);
                if (result)
                {
                    ANBCellFlow.Status = ANCellStatus.Emptying.ToString();
                    _anBTotalFillFlow = 0;
                    _anBDrainTime = DateTime.Now;
                }
                else
                {
                    reservoirDevice.AnBDrainPump(0);
                }
            }
            return result;
        }
        #endregion

        #region AN Stop
        /// <summary>
        /// 阳面A停止 
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="objs"></param>
        /// <returns></returns>
        private bool ANSideAStopOperation(string cmd, object[] objs)
        {
            CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
            if (reservoirDevice != null)
            {
                if (reservoirDevice.ReservoirData.ANPump != 0)
                {
                    reservoirDevice.AnPump(0);
                }
                if (reservoirDevice.ReservoirData.ANADrainPump != 0)
                {
                    reservoirDevice.AnADrainPump(0);
                }
            }
            if (MetalDeviceData.ANAPinEnable)
            {
                AnSideAFillOff("", null);
            }
            if (MetalDeviceData.ANAPoutEnable)
            {
                AnSideADrainOff("", null);
            }
            ANACellFlow.Status = ANCellStatus.Unknow.ToString();
            _anATotalFillFlow = 0;
            return true;
        }
        /// <summary>
        /// 阳面A停止 
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="objs"></param>
        /// <returns></returns>
        private bool ANSideBStopOperation(string cmd, object[] objs)
        {
            CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
            if (reservoirDevice != null)
            {
                if (reservoirDevice.ReservoirData.ANPump != 0)
                {
                    reservoirDevice.AnPump(0);
                }
                if (reservoirDevice.ReservoirData.ANBDrainPump != 0)
                {
                    reservoirDevice.AnBDrainPump(0);
                }
            }
            if (MetalDeviceData.ANBPinEnable)
            {
                AnSideBFillOff("", null);
            }
            if (MetalDeviceData.ANBPoutEnable)
            {
                AnSideBDrainOff("", null);
            }
            ANBCellFlow.Status = ANCellStatus.Unknow.ToString();
            _anBTotalFillFlow = 0;
            return true;
        }
        #endregion

        #region Timer定时器
        /// <summary>
        /// 定时器
        /// </summary>
        /// <returns></returns>
        public override bool OnTimer(int interval)
        {
            if (_currentANACellOperation == ANCellOperation.Fill)
            {
                SideFillRoutineMonitor(_anANACellFillRoutine, "A", ANACellFlow, ref _currentANACellOperation);
            }
            if (_currentANBCellOperation == ANCellOperation.Fill)
            {
                SideFillRoutineMonitor(_anANBCellFillRoutine, "B", ANBCellFlow, ref _currentANBCellOperation);
            }
            //正在Filing
            if (ANACellFlow.Status == ANCellStatus.Filling.ToString())
            {
                JudgeFillFull(ANACellFlow, interval, ref _anATotalFillFlow);
            }
            if (ANBCellFlow.Status == ANCellStatus.Filling.ToString())
            {
                JudgeFillFull(ANBCellFlow, interval, ref _anBTotalFillFlow);
            }

            if (ANACellFlow.Status == ANCellStatus.Emptying.ToString())
            {
                JudgeDrainEmpty("A");
            }
            if (ANBCellFlow.Status == ANCellStatus.Emptying.ToString())
            {
                JudgeDrainEmpty("B");
            }
            return true;
        }
        /// <summary>
        /// 单面Fill Routine监控
        /// </summary>
        /// <param name="routine"></param>
        /// <param name="side"></param>
        /// <param name="operation"></param>
        private void SideFillRoutineMonitor(IRoutine routine, string side, CounterFlowData counterFlowData, ref ANCellOperation operation)
        {
            RState state = routine.Monitor();
            if (state == RState.Failed || state == RState.Timeout)
            {
                CloseReservoirPumpAndMetalFill(side);
                operation = ANCellOperation.None;
            }
            else if (state == RState.End)
            {
                counterFlowData.Status = ANCellStatus.Filling.ToString();
                operation = ANCellOperation.None;
            }
        }
        /// <summary>
        /// 判定是否fill Full
        /// </summary>
        private void JudgeFillFull(CounterFlowData counterFlowData, int interval, ref double totalFillFlow)
        {
            double anodeFillVolume = SC.GetValue<double>($"Metal.AnodeFillVolume");
            totalFillFlow += counterFlowData.CounterValue / 60 * ((double)interval / 1000);
            if (totalFillFlow >= anodeFillVolume)
            {
                counterFlowData.Status = "Full";
            }
        }
        /// <summary>
        /// 判定是否Drain Empty
        /// </summary>
        /// <param name="counterFlowData"></param>
        private void JudgeDrainEmpty(string side)
        {
            if (side == "A")
            {
                JudgeSideADrain(ANACellFlow, _anADrainTime);
                if (ANACellFlow.Status == ANCellStatus.Empty.ToString())
                {
                    CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
                    if (reservoirDevice != null)
                    {
                        reservoirDevice.AnADrainPump(0);
                    }
                    AnSideADrainOff("", null);
                }
            }
            else
            {
                JudgeSideADrain(ANBCellFlow, _anBDrainTime);
                if (ANBCellFlow.Status == ANCellStatus.Empty.ToString())
                {
                    CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
                    if (reservoirDevice != null)
                    {
                        reservoirDevice.AnBDrainPump(0);
                    }
                    AnSideBDrainOff("", null);
                }
            }
        }
        /// <summary>
        /// 判定单面Drain的情况
        /// </summary>
        /// <param name="counterFlowData"></param>
        /// <param name="drainDateTime"></param>
        private void JudgeSideADrain(CounterFlowData counterFlowData, DateTime drainDateTime)
        {
            double anodeDrainTime = SC.GetValue<double>("Metal.AnodeDrainTime");
            if (DateTime.Now.Subtract(drainDateTime).TotalMilliseconds >= anodeDrainTime * 1000)
            {
                counterFlowData.Status = ANCellStatus.Empty.ToString();
            }
        }
        /// <summary>
        /// 关闭Reservoir Pump和Metal Fill
        /// </summary>
        private void CloseReservoirPumpAndMetalFill(string side)
        {
            CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
            if (reservoirDevice != null)
            {
                reservoirDevice.AnPump(0);
                if (side == "A")
                {
                    AnSideAFillOff("", null);
                }
                else
                {
                    AnSideBDrainOff("", null);
                }
            }
        }

        /// <summary>
        /// 获取Reservoir设备
        /// </summary>
        /// <returns></returns>
        private CompactMembranReservoirDevice GetReservoirDevice()
        {
            string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module);
            return DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoir);
        }
        #endregion

        /// <summary>
        /// Enter Disabled Operation
        /// </summary>
        /// <returns></returns>
        public void EnterDisabledOperation()
        {
            ANSideAStopOperation("", null);
            ANSideBStopOperation("", null);
            if (_metalDeviceData.CellFlowValve)
            {
                CellFlowValveOff("", null);
            }
        }
        #region 设备接口
        public override void Monitor()
        {
        }

        public override void Reset()
        {
        }

        public override void Terminate()
        {
        }
        #endregion
    }
}