using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using CyberX8_Core;
using CyberX8_RT.Devices.Reservoir;
using MECF.Framework.Common.Persistent.Reservoirs;
using MECF.Framework.Common.RecipeCenter;
using MECF.Framework.Common.Routine;
using System;
namespace CyberX8_RT.Modules.Reservoir
{
    public class ReservoirDosingRoutine : RoutineBase, IRoutine
    {
        private enum DosingStep
        {
            Dosing_Check_Status,
            Dosing_Dispensing,
            Dosing_Wait_Complete,
            Dosing_Done,
            End
        }
        #region 内部变量
        /// 
        /// 模块名称
        /// 
        private string _moduleName;
        /// 
        /// Replen名称
        /// 
        private string _replenName;
        /// 
        /// Replen ID
        /// 
        private int _replenId;
        /// 
        /// SHReservoirDevice
        /// 
        private StandardHotReservoirDevice _standardHotReservoirdevice;
        /// 
        /// 本次需要补充的液体体积(mL)
        /// 
        private double _targetVolume;
        /// 
        /// RDS Recipe
        /// 
        private RdsRecipe _rdsRecipe;
        /// 
        /// 补液开始时间(ms)
        /// 
        private int _dosingStartTime;
        /// 
        /// 补液需要消耗的时间(ms)
        /// 
        private int _dosingTime;
        /// 
        /// InitialDosingSpeed(mL/min)
        /// 
        private double _initialDosingSpeed;
        /// 
        /// Replen Persistent Value
        /// 
        private ReplenPersistentValue _persistentValue;
        /// 
        /// 是否为Auto模式
        /// 
        private bool _isAutoMode;
        /// 
        /// Dosing超时时间
        /// 
        private int _dosingOutTime;
        #endregion
        #region 属性
        /// 
        /// 状态
        /// 
        public string State { get { return Runner.CurrentStep.ToString(); } }
        #endregion
        /// 
        /// 构造函数
        /// 
        /// 
        public ReservoirDosingRoutine(string module, string replenName) : base(module)
        {
            _moduleName = module;
            _replenName = replenName;
            _replenId = int.Parse(_replenName.Substring(6, 1));
        }
        public void Abort()
        {
            if (_standardHotReservoirdevice.ReplenDatas[_replenId - 1].ReplenPumpEnable)
            {
                //关闭Replen Pump
                Object[] args = new object[1];
                args[0] = _replenName;
                bool result = _standardHotReservoirdevice.ReplenPumpOffOperation("", args);
                if (result)
                {
                    LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump Off");
                }
                else
                {
                    LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump Off is failed");
                }
                _persistentValue.RemainDosingVolume -= _persistentValue.CurrentDosingVolume;
            }
            Runner.Stop($"{_moduleName}_{_replenName} Stop Dosing");
        }
        public RState Monitor()
        {
            Runner.Run(DosingStep.Dosing_Check_Status, CheckStatus, _delay_1ms)
                .Run(DosingStep.Dosing_Dispensing, Dispensing, _delay_1ms)
                .WaitWithStopCondition(DosingStep.Dosing_Wait_Complete, WaitCompleteEndStatus, WaitCompleteErrorStatus, _dosingTime + _dosingOutTime)
                .End(DosingStep.Dosing_Done, DoneOperation, _delay_1ms);
            return Runner.Status;
        }
        /// 
        /// 启动
        /// 
        /// 
        /// 
        public RState Start(params object[] objs)
        {
            _targetVolume = (double)objs[0];
            _isAutoMode = (bool)objs[1];
            //加载Reservoir设备
            _standardHotReservoirdevice = DEVICE.GetDevice($"{_moduleName}");
            if (_standardHotReservoirdevice == null)
            {
                LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Reservoir Device is not exist");
                return RState.Failed;
            }
            //加载持久化文件
            _persistentValue = ReplenPersistentManager.Instance.GetReplenPersistentValue(_moduleName, _replenName);
            if (_persistentValue == null)
            {
                LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Persistent Value Object is not exist");
                return RState.Failed;
            }          
            //加载Recipe
            _rdsRecipe = _standardHotReservoirdevice.RdsRecipe[_replenId - 1];
            //手动模式下无需Recipe
            if (_isAutoMode && _rdsRecipe == null)
            {
                LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "RDS recipe is null");
                return RState.Failed;
            }
            if (SC.ContainsItem($"Reservoir.{_moduleName}.DosingOutTime"))
            {
                _dosingOutTime = (int)SC.GetValue($"Reservoir.{_moduleName}.DosingOutTime") * 60 * 1000;
            }
            return Runner.Start(_moduleName +"_"+_replenName, "Dosing");
        }
        #region Operation
              
        /// 
        /// Check Status
        /// 
        /// 
        /// 
        private bool CheckStatus()
        {
            if (!_standardHotReservoirdevice.CheckandUpdateBottleLevel(_replenName, _targetVolume))
            {
                LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, $"Current Bottle is not in Full Level!");
                return false;
            }
            return true;
        }
        /// 
        /// Dispensing
        /// 
        /// 
        /// 
        private bool Dispensing()
        {
            //计算Dosing时间
            if (SC.ContainsItem($"Reservoir.{_moduleName}.InitialDosingSpeed"))
            {
                _initialDosingSpeed = SC.GetValue($"Reservoir.{_moduleName}.InitialDosingSpeed");
                
                double pumpFactor = _persistentValue.ReplenPumpFactor;
                double adjustSpeed = pumpFactor * _initialDosingSpeed;
                SCConfigItem item = SC.GetConfigItem($"Reservoir.{Module}.InitialDosingSpeed");
                double speedMax = double.Parse(item.Max);
                if(adjustSpeed > speedMax)
                {
                    _dosingTime = (int)((pumpFactor * _targetVolume / speedMax) * 60 * 1000);
                    _initialDosingSpeed = speedMax / pumpFactor;
                }
                else
                {
                    _dosingTime = (int)((_targetVolume / _initialDosingSpeed) * 60 * 1000);
                }              
                   
                
            }
            //记录Dosing开始时刻
            _dosingStartTime = Environment.TickCount;
            //打开Replen Pump
            Object[] args = new object[1];
            args[0] = _replenName;
            bool result = _standardHotReservoirdevice.ReplenPumpOnOperation("", args);
            if (result)
            {
                LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump On");
            }
            else
            {
                LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump On is failed");
            }
            return result;
        }              
        /// 
        ///  WaitComplete End
        /// 
        /// 
        private bool WaitCompleteEndStatus()
        {
            int tick = Environment.TickCount - _dosingStartTime;
            //更新实时DosingVolume
            _persistentValue.CurrentDosingVolume = Math.Round(tick * (_initialDosingSpeed / 1000 / 60), 2);
            ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName);
            if (tick >= _dosingTime)
            {
                //关闭Replen Pump
                Object[] args = new object[1];
                args[0] = _replenName;
                bool result = _standardHotReservoirdevice.ReplenPumpOffOperation("", args);
                if (result)
                {
                    LOG.WriteLog(eEvent.INFO_RESERVOIR, _moduleName, "Replen Pump Off");
                }
                else
                {
                    LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump Off is failed");
                }
                return true;
            }
            return false;
        }
        /// 
        ///  WaitComplete Error
        /// 
        /// 
        private bool WaitCompleteErrorStatus()
        {
            //若Pump被关闭则报错
            if (!_standardHotReservoirdevice.ReplenDatas[_replenId - 1].ReplenPumpEnable)
            {
                _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _persistentValue.CurrentDosingVolume, 2);
                ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName);
                LOG.WriteLog(eEvent.ERR_RESERVOIR, _moduleName, "Replen Pump is off. Stop Dosing");
                return true;
            }
            //若BottleLevel not full则报错
            if (!_standardHotReservoirdevice.CheckandUpdateBottleLevel(_replenName, _targetVolume))
            {
                _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _persistentValue.CurrentDosingVolume, 2);
                ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName);
                return true;
            }
            return false;
        }
        /// 
        /// Done Operation
        /// 
        /// 
        /// 
        private bool DoneOperation()
        {
            //数据清零           
            _persistentValue.CurrentDosingVolume = 0;
            _persistentValue.IsDosingRunning = false;
            _persistentValue.AutoDosingStartAmpHour = 0;
            _persistentValue.AutoDosingStartTime = DateTime.MinValue;
            _persistentValue.RemainDosingVolume = Math.Round(_persistentValue.RemainDosingVolume - _targetVolume, 2);
            ReplenPersistentManager.Instance.UpdatePersistentValue(_moduleName, _replenName);
            _targetVolume = 0;
            _dosingTime = 0;
            _dosingStartTime = 0;
            return true;
        }
        
        #endregion
    }
}