using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using CyberX8_Core;
using CyberX8_RT.Devices.AXIS;
using CyberX8_RT.Devices.Facilities;
using CyberX8_RT.Devices.SRD;
using MECF.Framework.Common.Beckhoff.AxisProvider;
using MECF.Framework.Common.RecipeCenter;
using MECF.Framework.Common.Routine;
using MECF.Framework.Common.Utilities;
using System;
namespace CyberX8_RT.Modules.SRD
{
    public class SRDRunRecipeRoutine : RoutineBase, IRoutine
    {
        private enum SRDRunRecipeStep
        {
            RunRecipe_CloseDoor,
            RunRecipe_CheckOtherSRD,
            RunRecipe_CheckWaterPressure,
            RunRecipe_WaterOn,
            RunRecipe_CheckWaterFlow,
            RunRecipe_StartRotation,
            RunRecipe_MonitorWaterFlow,
            RunRecipe_WashingFinished,
            RunRecipe_ChangeDrySpeed,
            RunRecipe_Drying,
            RunRecipe_StopRotation,
            RunRecipe_CheckRotationStopped,
            RunRecipe_CheckRotationHomed,
            End
        }
        #region 常量 
        /// 
        /// 旋转增加时长
        /// 
        private const int ROTATION_PLUS_TIME = 10;
        /// 
        /// ROTATION电机转速比例
        /// 
        private const int SPEED_RATIO = 1;
        #endregion
        #region 内部变量
        /// 
        /// Rotation Axis
        /// 
        private JetAxisBase _rotationAxis;
        /// 
        /// SRD Common
        /// 
        private SrdCommonDevice _srdCommon;
        /// 
        /// Total SRD
        /// 
        private TotalSRDDevice _totalSRDDevice;
        /// 
        /// 另外SRD实例 
        /// 
        private SRDEntity _otherSrdEntity;
        /// 
        /// Loader Common
        /// 
        private SystemFacilities _systemFacilities;
        /// 
        /// 是否正在用水
        /// 
        private bool _isUsingWater;
        /// 
        /// Recipe
        /// 
        private SrdRecipe _srdRecipe;
        /// 
        /// SRD rotation Provider对象
        /// 
        private BeckhoffProviderAxis _rotationProviderAxis;
        /// 
        /// enterTime
        /// 
        private int _enterTime;
        /// 
        /// 转换增加的时间
        /// 
        private int _rotationPlusSecond = ROTATION_PLUS_TIME;
        /// 
        /// Dry速度
        /// 
        private int _drySpeed;
        #endregion
        #region 属性
        /// 
        /// 是否正在用水
        /// 
        public bool IsUsingWater { get { return _isUsingWater; } }
        #endregion
        /// 
        /// 构造函数
        /// 
        /// 
        public SRDRunRecipeRoutine(string module) : base(module)
        {
        }
        /// 
        /// 中止
        /// 
        public void Abort()
        {
            Runner.Stop("SRD Run Recipe Abort");
        }
        /// 
        /// 监控
        /// 
        /// 
        public RState Monitor()
        {
            Runner.Run(SRDRunRecipeStep.RunRecipe_CloseDoor, CloseDoor, CheckDoorClosedEndStatus, CheckDoorClosedStopStatus)
                .Wait(SRDRunRecipeStep.RunRecipe_CheckOtherSRD, CheckOtherSRD, _delay_60s)
                .Run(SRDRunRecipeStep.RunRecipe_CheckWaterPressure, CheckWaterPressure, _delay_1ms)
                .Run(SRDRunRecipeStep.RunRecipe_WaterOn, WaterOn, _delay_1ms)
                .WaitWithStopCondition(SRDRunRecipeStep.RunRecipe_CheckWaterFlow, CheckFlowEndStatus, CheckFlowStopStatus)
                .Run(SRDRunRecipeStep.RunRecipe_StartRotation, StartRotation, _delay_1ms)
                .WaitWithStopCondition(SRDRunRecipeStep.RunRecipe_MonitorWaterFlow, MonitorWaterFlowEndStatus, MonitorWaterFlowStopStatus)
                .Run(SRDRunRecipeStep.RunRecipe_WashingFinished, WashingFinished, _delay_1ms)
                .Run(SRDRunRecipeStep.RunRecipe_ChangeDrySpeed, ChangeSpeed, _delay_1ms)
                .Delay(SRDRunRecipeStep.RunRecipe_Drying, _srdRecipe.DryTime * 1000)
                .Run(SRDRunRecipeStep.RunRecipe_StopRotation, StopRotation, _delay_1ms)
                .Wait(SRDRunRecipeStep.RunRecipe_CheckRotationStopped, CheckRotationStopEndStatus, _delay_10s)
                .WaitWithStopCondition(SRDRunRecipeStep.RunRecipe_CheckRotationHomed, CheckRotationHomeEndStatus, CheckRotationHomedStopStatus)
                .End(SRDRunRecipeStep.End, NullFun, _delay_1ms);
            return Runner.Status;
        }
        /// 
        /// 启动
        /// 
        /// 
        /// 
        public RState Start(params object[] objs)
        {
            _srdRecipe = (SrdRecipe)objs[0];
            if (_srdRecipe == null)
            {
                NotifyError(eEvent.ERR_SRD, "srd recipe is null", 0);
                return RState.Failed;
            }
            _rotationAxis = DEVICE.GetDevice($"{Module}.Rotation");           
            _srdCommon = DEVICE.GetDevice($"{Module}.Common");
            _totalSRDDevice = DEVICE.GetDevice("SRD");
            _systemFacilities = DEVICE.GetDevice("System.Facilities");
            string otherSRD = Module == "SRD1" ? "SRD2" : "SRD1";
            _otherSrdEntity = Singleton.Instance.GetModule(otherSRD);
            
            _rotationProviderAxis = BeckhoffAxisProviderManager.Instance.GetAxisProvider($"{Module}.Rotation");
            if (_rotationProviderAxis == null)
            {
                NotifyError(eEvent.ERR_SRD, $"{Module}.Rotation Provider is not exist", 0);
                return RState.Failed;
            }
            if (!CheckPreCondition())
            {
                return RState.Failed;
            }
            return Runner.Start(Module, "SRD Run Recipe Start");
        }
        /// 
        /// Check Pre Condition
        /// 
        /// 
        private bool CheckPreCondition()
        {
            //Check Rotation Home
            if (!_rotationAxis.IsHomed)
            {
                NotifyError(eEvent.ERR_SRD, "Rotation is not homed", 0);
                return false;
            }
            //Check LiftUp
            if (_srdCommon.CommonData.LiftUp)
            {
                NotifyError(eEvent.ERR_SRD, "LiftUp is on", 0);
                return false;
            }
            //Check LiftUp Status
            if (_srdCommon.CommonData.LiftUpStatus)
            {
                NotifyError(eEvent.ERR_SRD, "LiftUp sensor is on", 0);
                return false;
            }
            //Check Wafer Present
            if (!_srdCommon.CommonData.WaferPresent)
            {
                NotifyError(eEvent.ERR_SRD, "WaferPresent sensor is off", 0);
                return false;
            }
            //Check LoaderDI
            if (!_systemFacilities.LoaderDiEnable)
            {
                NotifyError(eEvent.ERR_SRD, "Load DI Is Disable", 0);
                return false;
            }
            //Check Vacuum
            int vacuumOnLimit = SC.GetValue("SRD.ChuckVacuumOnLimit");
            if (!_srdCommon.CommonData.ChuckVacuum)
            {
                if (_srdCommon.CommonData.VacuumValue >= vacuumOnLimit)
                {
                    LOG.WriteLog(eEvent.ERR_SRD, Module, $"VacuumValue:{_srdCommon.CommonData.VacuumValue}, VacuumOn Limit:{vacuumOnLimit}");
                    return false;
                }
            }
            else
            {
                LOG.WriteLog(eEvent.ERR_SRD, Module, $"Chuck Vacuum is off");
                return false;
            }
            //Check Flippers
            if (_srdCommon.CommonData.FlippersIn150 || _srdCommon.CommonData.FlippersIn200) //|| _srdCommon.CommonData.FlippersIn100
            {
                NotifyError(eEvent.ERR_SRD, "FlippersIn is on", 0);
                return false;
            }
            if (!_srdCommon.CommonData.Flipper1Out150Status || !_srdCommon.CommonData.Flipper2Out150Status || !_srdCommon.CommonData.Flipper3Out150Status
                || !_srdCommon.CommonData.Flipper1Out200Status || !_srdCommon.CommonData.Flipper2Out200Status || !_srdCommon.CommonData.Flipper3Out200Status)
            //|| !_srdCommon.CommonData.Flipper1Out100Status || !_srdCommon.CommonData.Flipper2Out100Status || !_srdCommon.CommonData.Flipper3Out100Status
            {
                NotifyError(eEvent.ERR_SRD, "Flippers are at In position", 0);
                return false;
            }
            return true;
        }
        /// 
        /// Close Door
        /// 
        /// 
        /// 
        private bool CloseDoor()
        {
            if (_srdCommon.CommonData.DoorOpened)
            {
                bool result = _srdCommon.DoorCloseAction("", null);
                if (!result)
                {
                    NotifyError(eEvent.ERR_SRD, "Door Close Action is failed", 0);
                    return result;
                }
            }
            return true;
        }
        /// 
        /// 检验DoorClosed结束状态
        /// 
        /// 
        /// 
        private bool CheckDoorClosedEndStatus()
        {
            return _srdCommon.Status == RState.End && _srdCommon.CommonData.DoorClosed;
        }
        /// 
        /// 检验DoorClosed结束状态
        /// 
        /// 
        /// 
        private bool CheckDoorClosedStopStatus()
        {
            if (_srdCommon.Status == RState.Failed || _srdCommon.Status == RState.Timeout)
            {
                NotifyError(eEvent.ERR_SRD, "Check Door Closed is failed", 0);
                return true;
            }
            return false;
        }
        /// 
        /// 检验另外一个SRD是否在用水
        /// 
        /// 
        /// 
        private bool CheckOtherSRD()
        {
            return (_otherSrdEntity == null || !_otherSrdEntity.IsUsingWater);
        }
        /// 
        /// CheckWaterPressure
        /// 
        /// 
        private bool CheckWaterPressure()
        {
            if (_srdRecipe.MinWaterPressure == 0 && _srdRecipe.MaxWaterPressure == 0) return true;
            if (_srdCommon.CommonData.WaterPressure < _srdRecipe.MinWaterPressure)
            {
                NotifyError(eEvent.ERR_SRD, $"Water Pressure {_srdCommon.CommonData.WaterPressure} is less than recipe's MinWaterPressure {_srdRecipe.MinWaterPressure}", 0);
                return false;
            }
            else if(_srdCommon.CommonData.WaterPressure > _srdRecipe.MaxWaterPressure)
            {
                NotifyError(eEvent.ERR_SRD, $"Water Pressure {_srdCommon.CommonData.WaterPressure} is over recipe's MaxWaterPressure {_srdRecipe.MaxWaterPressure}", 0);
                return false;
            }
            return true;
        }
        /// 
        /// Water On
        /// 
        /// 
        /// 
        private bool WaterOn()
        {
            if (_srdRecipe.RinseTime > 0)
            {
                if (!_srdCommon.CommonData.WaterOn)
                {
                    bool result = _srdCommon.WaterOn();
                    if (result)
                    {
                        LOG.WriteLog(eEvent.INFO_SRD, Module, "Water On");
                        _isUsingWater = true;
                        _enterTime = Environment.TickCount;
                    }
                    else
                    {
                        NotifyError(eEvent.ERR_SRD, "Water On is failed", 0);
                    }
                    return result;
                }
                return true;
            }
            return true;
        }
        /// 
        /// Check Flow End
        /// 
        /// 
        private bool CheckFlowEndStatus()
        {
            if (_srdRecipe.FlowCheckDelay == 0)
            {
                return true;
            }
            int ticks = Environment.TickCount - _enterTime;
            if (ticks >= _srdRecipe.FlowCheckDelay * 1000)
            {
                if (WaterFlowCheck()) return true;
            }
            return false;
        }
        /// 
        /// Check Flow Stop
        /// 
        /// 
        /// 
        private bool CheckFlowStopStatus()
        {
            int ticks = Environment.TickCount - _enterTime;
            if (ticks >= _srdRecipe.FlowCheckDelay * 1000)
            {
                if (!WaterFlowCheck()) return true;
            }
            return false;
        }
        /// 
        /// WaterFlow检测
        /// 
        /// 
        private bool WaterFlowCheck()
        {
            if (_srdRecipe.MaxSRDWaterFlow == 0 && _srdRecipe.MinSRDWaterFlow == 0) return true;
            if (_srdCommon.CommonData.WaterFlow > _srdRecipe.MaxSRDWaterFlow)
            {
                NotifyError(eEvent.ERR_SRD, $"{Module} Water Flow:{_srdCommon.CommonData.WaterFlow} is over recipe's MaxSRDWaterFlow:{_srdRecipe.MaxSRDWaterFlow}", 0);
                return false;
            }
            else if (_srdCommon.CommonData.WaterFlow < _srdRecipe.MinSRDWaterFlow)
            {
                NotifyError(eEvent.ERR_SRD, $"{Module} Water Flow:{_srdCommon.CommonData.WaterFlow} is less than recipe's MinSRDWaterFlow:{_srdRecipe.MinSRDWaterFlow}", 0);
                return false;
            }
            return true;
        }
        /// 
        /// 开始旋转
        /// 
        /// 
        /// 
        private bool StartRotation()
        {
            if (!_srdCommon.RotationInterLock())
            {
                return false;
            }
            double _scale = _rotationProviderAxis.ScaleFactor;
            //rinse 目标位置 
            double rinsePosition = _srdRecipe.RinseTime * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.RinseSpeed);
            //dry目标位置
            double dryPosition = BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.DrySpeed) * _srdRecipe.DryTime;
            //为了让 rotation 不停止,增加了旋转时间(覆盖Arm运动时间)
            double plusPosition = BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.DrySpeed) * _rotationPlusSecond;
            int targetPosition = (int)Math.Round((rinsePosition + dryPosition + plusPosition) * _scale, 0);
            int rotationSpeed = (int)Math.Round(_scale * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.RinseSpeed), 0);
            _drySpeed = (int)Math.Round(_scale * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.DrySpeed * SPEED_RATIO), 0);
            bool result = _rotationAxis.ProfilePosition(targetPosition, rotationSpeed * SPEED_RATIO, 0, 0);
            if (!result)
            {
                NotifyError(eEvent.ERR_SRD, "Start Rotation is failed", 0);
                return false;
            }
            LOG.WriteLog(eEvent.INFO_SRD, Module, "Start Rotation");
            //Rinse开始时间
            _enterTime = Environment.TickCount;
            return true;
        }
        /// 
        /// WaterFlow End Monitor
        /// 
        /// 
        private bool MonitorWaterFlowEndStatus()
        {
            int ticks = Environment.TickCount - _enterTime;
            if (ticks >= _srdRecipe.RinseTime * 1000)
            {
                return true;
            }
            return false;
        }
        /// 
        /// WaterFlow Stop Monitor
        /// 
        /// 
        private bool MonitorWaterFlowStopStatus()
        {
            int ticks = Environment.TickCount - _enterTime;
            if (ticks < _srdRecipe.RinseTime * 1000)
            {
                if (!WaterFlowCheck()) return true;
            }
            return false;
        }
        /// 
        /// Washing Finished
        /// 
        /// 
        private bool WashingFinished()
        {
            if (_srdCommon.CommonData.WaterOn)
            {
                if (!_srdCommon.WaterOff())
                {
                    NotifyError(eEvent.ERR_SRD, "Water Off is failed", 0);
                    return false;
                }
            }
            _isUsingWater = false;
            return true;
        }
        /// 
        /// change Dry speed
        /// 
        /// 
        private bool ChangeSpeed()
        {
            //调整速度为 drySpeed
            bool result = _rotationAxis.WriteSpeed(_drySpeed);
            if (!result)
            {
                NotifyError(eEvent.ERR_SRD, "Change Speed to Dry Speed is failed", 0);
                return false;
            }
            return true;
        }
        /// 
        /// 停止旋转
        /// 
        /// 
        private bool StopRotation()
        {
            bool result = _rotationAxis.StopPositionOperation();
            LOG.WriteLog(eEvent.INFO_SRD, Module, "Stop Rotation is done");
            return result;
        }
        /// 
        /// 检验Rotation是否停止
        /// 
        /// 
        private bool CheckRotationStopEndStatus()
        {
            if (!_rotationAxis.IsRun && _rotationAxis.Status == RState.End)
            {
                bool homeResult = _rotationAxis.Home();
                if (!homeResult)
                {
                    NotifyError(eEvent.ERR_SRD, $"{Module}.Rotation home action is failed", 0);
                    return false;
                }
                return true;
            }
            return false;
        }
        /// 
        /// 检验RotationHome是否完成
        /// 
        /// 
        private bool CheckRotationHomeEndStatus()
        {
            if (_rotationAxis.IsHomed && _rotationAxis.Status == RState.End)
            {                
                return true;
            }
            return false;
        }
        /// 
        /// 检验Rotation Home 停止状态
        /// 
        /// 
        private bool CheckRotationHomedStopStatus()
        {
            if(_rotationAxis.Status == RState.Failed || _rotationAxis.Status == RState.Timeout)
            {
                NotifyError(eEvent.ERR_SRD, $"{Module}.Rotation home is failed", 0);
                return true;
            }
            return false;
        }
        
    }
    
}