using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Device.Devices;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadLocks;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.TMs;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.UnLoad;
using SicModules.LLs;
using SicModules.LLs.Routines;
using SicModules.UnLoads;
using SicModules.UnLoads.Routines;
using System;
using Aitex.Core.RT.Log;

namespace SicModules.TMs.Routines
{
    public class TMSlitValveRoutine : TMBaseRoutine
    {
        enum RoutineStep
        {
            ChamberBalance,
            OpenTMToLLVent,
            OpenTMToPMV70,
            CheckPressureCondition,

            SetSlitValve,

            SetSlowVentValve,
            SetM40,

            LLRoutine,

            Delay, 
            Delay1, Delay2, Delay3, Delay4,
            CloseTMToLLVent, 
            CloseTMToPMV70,
            PumpDownToBase,
            CheckConfinementIsDown,

            SetConfinementRingUp,
            SetConfinementRingDown,
            SetPostTransfer,
            SetPmPreTrasfer,
            SetV77,
            SetV77Close,
            SetTmMfc,

            WaitTempBelow900,
            WaitPVTempBelowSet,
            WaitPMIdle,
            SkipSlitOpenInterlock
        }


        private int _timeout;

        private SicTM _tm;
        private LoadLock _ll;
        private UnLoad _unLoad;
        private IoValve PMToTm_V70;
        private IoPressure _pmPT1;
        private IoConfinementRing _confinementRing;
        private SicServo _sicServo;
        private IoInterLock _pmIoInterLock;
        private IoTC _tc1;

        private string _paramTarget;
        private bool _paramIsOpen;
        private bool _confinementIsDown = false;


        //private TMPumpWithTurboRoutine _pumpDownRoutine;

        private TMPressureBalanceRoutine _balanceRoutine;
        private LoadLockServoToRoutine _llVentTo;
        private UnLoadServoToRoutine _unLoadVentTo;
        private IoMFC _m40;

        private bool _needPressureBalance;

        private int _rotationStopTimeout = 120;

        private double _maxPressureDiffOpenSlitValve;
        private bool _isAtmMode;
        private bool _isLockLock;
        private bool _isUnLoad;
        private bool _isPM;
        private bool _isBuffer;
        private int _tmV77DelayTime = 5;
        private double _tmMfcFlow = 10;

        private bool _pmPostTrasferNeedEnableHeat = true; 
        private bool _preTransferPSUEnable = false;
        private bool _preTransferSCREnable = false;
        public IoPSU PSU1 = null;
        public IoPSU PSU2 = null;
        public IoPSU PSU3 = null;
        public IoSCR SCR1 = null;
        public IoSCR SCR2 = null;
        public IoSCR SCR3 = null;

        private DOAccessor _doProcessIdleRunning;
        private DOAccessor _doPreProcessRunning;

        private double _pmPVTempLimit = 0;

        public TMSlitValveRoutine()
        {
            Module = ModuleName.TM.ToString();
            Name = "Slit Valve";
            _tm = DEVICE.GetDevice<SicTM>($"{ ModuleName.System.ToString()}.{ ModuleName.TM.ToString()}");
            _ll = DEVICE.GetDevice<SicLoadLock>($"{ModuleName.LoadLock}.{ModuleName.LoadLock}");
            _unLoad= DEVICE.GetDevice<SicUnLoad>($"{ModuleName.UnLoad}.{ModuleName.UnLoad}");
        }

        public void Init(string module, bool isOpen, bool needEnableHeat)
        {
            _pmPostTrasferNeedEnableHeat = needEnableHeat;
            Init(module, isOpen);
        }

        public void Init(string module, bool isOpen)
        {
            _paramTarget = module;
            _paramIsOpen = isOpen;
            Name = isOpen ? "Open Slit Valve Routine" : "Close Slit Valve Routine";

            _balanceRoutine = new TMPressureBalanceRoutine();
            _llVentTo = new LoadLockServoToRoutine(ModuleName.LoadLock);
            _unLoadVentTo = new UnLoadServoToRoutine(ModuleName.UnLoad);
            _balanceRoutine.Init(ModuleHelper.Converter(module));

            _needPressureBalance = SC.GetValue<bool>("TM.NeedPressureBalance");  
        }

        public override Result Start(params object[] objs)
        {
            Reset();

            if(DATA.Poll("TM.Status").ToString() == "Alarm")
            {
                EV.PostAlarmLog(Module, $"TM Status is Alarm,do not action Slit valve");
                return Result.FAIL;
            }

            _isLockLock = ModuleHelper.IsLoadLock(_paramTarget);
            _isUnLoad = _paramTarget == ModuleName.UnLoad.ToString();
            _isPM = ModuleHelper.IsPm(_paramTarget);
            _isBuffer = _paramTarget == ModuleName.Buffer.ToString();

            if (_isPM)
            {
                PMToTm_V70 = DEVICE.GetDevice<IoValve>($"{_paramTarget}.V70");
                _confinementRing = DEVICE.GetDevice<IoConfinementRing>($"{_paramTarget}.ConfinementRing");
                _sicServo = DEVICE.GetDevice<SicServo>($"{_paramTarget}.PMServo");
                _pmIoInterLock = DEVICE.GetDevice<IoInterLock>($"{_paramTarget}.PMInterLock");
                _tc1 = DEVICE.GetDevice<IoTC>($"{_paramTarget}.TC1");
            }

            if (TMDevice.GetSlitValve(ModuleHelper.Converter(_paramTarget)) == null)
            {
                EV.PostWarningLog(Module, $"do not find slit valve info");
                return Result.FAIL;
            }

            if ((_paramIsOpen && TMDevice.CheckSlitValveOpen(ModuleHelper.Converter(_paramTarget)))
                || (!_paramIsOpen && TMDevice.CheckSlitValveClose(ModuleHelper.Converter(_paramTarget))))
            {
                string message = _paramIsOpen ? "open" : "close";                
                return Result.DONE;
            }

            _tm.CloseAllVentPumpValue();

            if (_paramIsOpen)
            {
                bool isAtmMode = SC.GetValue<bool>("System.IsATMMode");
                if (ModuleHelper.IsLoadLock(_paramTarget))
                {
                    LoadLock ll = DEVICE.GetDevice<LoadLock>($"{_paramTarget}.{_paramTarget}");

                    if (isAtmMode)
                    {
                        if (!ll.CheckAtm())
                        {
                            EV.PostWarningLog(Module, $"can not open slit valve, running in ATM mode, but {_paramTarget} not in ATM");
                            return Result.FAIL;
                        }
                    }
                    else
                    {
                        if (!ll.CheckVacuum())
                        {
                            EV.PostWarningLog(Module, $"can not open slit valve, {_paramTarget} not in vacuum");
                            return Result.FAIL;
                        }
                    }
                }

                if (ModuleHelper.IsPm(_paramTarget))
                {
                    _pmPT1 = DEVICE.GetDevice<IoPressure>($"{_paramTarget}.PT1");
                    double atmBase = SC.GetValue<double>($"PM.AtmPressureBase");
                    double vacBase = SC.GetValue<double>($"PM.VacuumPressureBase");

                    PSU1 = DEVICE.GetDevice<IoPSU>($"{_paramTarget}.PSU1");
                    PSU2 = DEVICE.GetDevice<IoPSU>($"{_paramTarget}.PSU2");
                    PSU3 = DEVICE.GetDevice<IoPSU>($"{_paramTarget}.PSU3");
                    SCR1 = DEVICE.GetDevice<IoSCR>($"{_paramTarget}.SCR1");
                    SCR2 = DEVICE.GetDevice<IoSCR>($"{_paramTarget}.SCR2");
                    SCR3 = DEVICE.GetDevice<IoSCR>($"{_paramTarget}.SCR3");

                    if (WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(_paramTarget), 0))
                    {
                        _pmPVTempLimit = SC.GetValue<double>($"PM.{_paramTarget}.Heater.PickPVTempLimit");
                    }
                    else
                    {
                        _pmPVTempLimit = SC.GetValue<double>($"PM.{_paramTarget}.Heater.PlacePVTempLimit");
                    }

                    if (isAtmMode)
                    {
                        if (_pmPT1.FeedBack < atmBase)
                        {
                            EV.PostWarningLog(Module, $"can not open slit valve, running in ATM mode, but {_paramTarget} not in ATM");
                            return Result.FAIL;
                        }
                    }
                    else
                    {
                        if (_pmPT1.FeedBack > vacBase)
                        {
                            EV.PostWarningLog(Module, $"can not open slit valve, {_paramTarget} not in vacuum");
                            return Result.FAIL;
                        }
                    }
                }

                ModuleName[] slitValveModules = new ModuleName[]
                {
                        ModuleName.LoadLock,ModuleName.PM1,ModuleName.PM2
                };
                foreach (var slitValveModule in slitValveModules)
                {
                    if (slitValveModule.ToString() == _paramTarget)
                        continue;

                    if (!_tm.CheckSlitValveClose(slitValveModule))
                    {
                        EV.PostWarningLog(Module, $"can not open slit valve {_paramTarget},  {slitValveModule} slit valve not closed, can not open at same time");
                        return Result.FAIL;
                    }
                }
            }

            if (ModuleHelper.IsPm(_paramTarget))
            {
                _preTransferPSUEnable = SC.GetValue<bool>($"PM.{_paramTarget}.PreTransferPSUEnable");
                _preTransferSCREnable = SC.GetValue<bool>($"PM.{_paramTarget}.PreTransferSCREnable");

                // 如果闸板阀是PM腔，提前关闭DO，以免报警
                _doProcessIdleRunning = IO.DO[$"{_paramTarget}.DO_ProcessIdleRunning"];
                _doPreProcessRunning = IO.DO[$"{_paramTarget}.DO_PreprocessRunning"];
            }

            _maxPressureDiffOpenSlitValve = SC.GetValue<double>("TM.MaxPressureDiffOpenSlitValve");
            _timeout = SC.GetValue<int>("System.SlitValveMotionTimeout");
            _isAtmMode = SC.GetValue<bool>("System.IsATMMode");

         
            _tmV77DelayTime= SC.GetValue<int>($"TM.OpenSlitValveDelayTimeForPM");
            _tmMfcFlow = SC.GetValue<double>($"TM.MFCFlowWhenV77Open");

            Notify("Start");

            return Result.RUN;
        }


        public override Result Monitor()
        {
            try
            {
                if (_isLockLock)
                {
                    if (_paramIsOpen)
                    {
                        TimeDelay((int)RoutineStep.Delay1, 1);

                         ExecuteRoutine((int)RoutineStep.ChamberBalance, _balanceRoutine);

                        if (_needPressureBalance && !_isAtmMode)
                        {
                            TimeDelay((int)RoutineStep.Delay2, 1);
                            ExecuteRoutine((int)RoutineStep.LLRoutine, _llVentTo);
                        }

                        SetTmToLoadLockVent((int)RoutineStep.OpenTMToLLVent, true, _tm, _paramTarget, 10);

                        TimeDelay((int)RoutineStep.Delay3, 5);
                        CheckPressureCondition((int)RoutineStep.CheckPressureCondition, _tm, _paramTarget);
                    }
                    SetSlitValve((int)RoutineStep.SetSlitValve, TMDevice, _paramTarget, _paramIsOpen, _timeout);

                    if (_paramIsOpen)
                    {
                        TimeDelay((int)RoutineStep.Delay4, 1);
                        SetTmToLoadLockVent((int)RoutineStep.CloseTMToLLVent, false, _tm, _paramTarget, 10);
                    }
                }
                else if (_isUnLoad)
                {
                    if (_paramIsOpen)
                    {
                        TimeDelay((int)RoutineStep.Delay1, 1);

                        ExecuteRoutine((int)RoutineStep.ChamberBalance, _balanceRoutine);

                        if (_needPressureBalance && !_isAtmMode)
                        {
                            TimeDelay((int)RoutineStep.Delay2, 1);
                            ExecuteRoutine((int)RoutineStep.LLRoutine, _unLoadVentTo);
                            SetTmToUnLoadVent((int)RoutineStep.OpenTMToLLVent, true, _tm, _paramTarget, 10);
                        }

                        TimeDelay((int)RoutineStep.Delay3, 1);
                        CheckPressureCondition((int)RoutineStep.CheckPressureCondition, _tm, _paramTarget);
                    }
                    SetSlitValve((int)RoutineStep.SetSlitValve, TMDevice, _paramTarget, _paramIsOpen, _timeout);

                    if (_paramIsOpen)
                    {
                        TimeDelay((int)RoutineStep.Delay4, 1);
                        SetTmToUnLoadVent((int)RoutineStep.CloseTMToLLVent, false, _tm, _paramTarget, 10);
                    }
                }
                else if (_isPM)
                {
                    if (_paramIsOpen)
                    {
                        SetPreTransfer((int)RoutineStep.SetPmPreTrasfer, _rotationStopTimeout);//旋转停止,加热停止

                        WaitPVTempratureBelowSet((int)RoutineStep.WaitPVTempBelowSet, 600);

                        if (_needPressureBalance && !_isAtmMode)
                        {
                            ExecuteRoutine((int)RoutineStep.ChamberBalance, _balanceRoutine);

                            SetTmMfc((int)RoutineStep.SetTmMfc, _tmMfcFlow);
                            SetPmToTmV70((int)RoutineStep.OpenTMToPMV70, true, _tm, _paramTarget, 5);
                            SetSlowVentValve((int)RoutineStep.SetV77, _tm, _paramIsOpen, _timeout);
                            TimeDelay((int)RoutineStep.Delay1, _tmV77DelayTime); //5秒可配置
                        }
                        CheckPressureCondition((int)RoutineStep.CheckPressureCondition, _tm, _paramTarget);

                        SkipInterlock((int)RoutineStep.SkipSlitOpenInterlock);
                    }


                    SetSlitValve((int)RoutineStep.SetSlitValve, TMDevice, _paramTarget, _paramIsOpen, _timeout);
                    if (!_paramIsOpen)
                    {
                        //关闭闸板阀需要关闭V77
                        SetSlowVentValve((int)RoutineStep.SetV77Close, _tm, _paramIsOpen, _timeout);
                    }

                    if (_paramIsOpen)
                    {
                        SetPmToTmV70((int)RoutineStep.CloseTMToPMV70, false, _tm, _paramTarget, 5);
                        WaitPMIdle((int)RoutineStep.WaitPMIdle, _paramTarget, 20);
                        SetConfinementRingDownAndWait((int)RoutineStep.SetConfinementRingDown, 30); //隔热罩下降
                    }

                    if (!_paramIsOpen)
                    {
                        SetPostTransfer((int)RoutineStep.SetPostTransfer, _pmPostTrasferNeedEnableHeat);
                        TimeDelay((int)RoutineStep.Delay4, 2);
                    }
                }
                else if(_isBuffer)
                {
                    //CheckPressureCondition((int)RoutineStep.CheckPressureCondition, _tm, _paramTarget);
                    SetSlitValve((int)RoutineStep.SetSlitValve, TMDevice, _paramTarget, _paramIsOpen, _timeout);
                }

            }
            catch (RoutineBreakException)
            {
                return Result.RUN;
            }
            catch (RoutineFaildException)
            {
                return Result.FAIL;
            }


            Notify("Finished");

            return Result.DONE;
        }

        public override void Abort()
        {
            _tm.CloseAllVentPumpValue();
        }

        private void SkipInterlock(int id)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                Notify($"Skip slit valve open interlock");
                if (_doPreProcessRunning == null)
                    LOG.Error("Unable to find DO object of 'DO_PreprocessRunning'");
                else if (_doProcessIdleRunning == null)
                    LOG.Error("Unable to find DO object of 'DO_ProcessIdleRunning'");
                else
                {
                    _doPreProcessRunning.Value = false;
                    _doProcessIdleRunning.Value = false;
                }


                return true;
            });

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }


        /// <summary>
        /// 打开或关闭V85
        /// </summary>
        /// <param name="id"></param>
        /// <param name="isOpen"></param>
        /// <param name="timeDelay"></param>
        private void SetTmToLoadLockVent(int id,bool isOpen, TM tm, string module, int timeDelay)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify((isOpen ? "Open" : "Close") + " TM to LoadLock Vent");

                if (!_tm.SetTmToLLVent(isOpen, out string reason))
                {
                    Stop(reason);
                    return false;
                }

                return true;
            }, () =>
            {
                double tmPressure = tm.ChamberPressure;
                double targetPressure = 0.0;
                if (ModuleHelper.IsLoadLock(_paramTarget))
                {
                    targetPressure = _ll.ChamberPressure;
                }
                else
                {
                    Stop($"{module} not define pressure condition");
                    return false;
                }

                return Math.Abs(tmPressure - targetPressure) <= _maxPressureDiffOpenSlitValve;
            },
            timeDelay * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"can not complete in {timeDelay} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        private void SetTmToUnLoadVent(int id, bool isOpen, TM tm, string module, int timeDelay)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify((isOpen ? "Open" : "Close") + " TM to UnLoad Vent");

                if (!_tm.SetTmToUnLoadVent(isOpen, out string reason))
                {
                    Stop(reason);
                    return false;
                }

                return true;
            }, () =>
            {
                double tmPressure = tm.ChamberPressure;
                double targetPressure = _unLoad.ChamberPressure; 

                return Math.Abs(tmPressure - targetPressure) <= _maxPressureDiffOpenSlitValve;
            },
            timeDelay * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"can not complete in {timeDelay} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        public void SetPmToTmV70(int id, bool isOpen, TM tm, string module, int timeDelay)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify($"set V70 " + (isOpen ? "Open" : "Close"));

                if (!PMToTm_V70.TurnValve(isOpen, out string reason))
                {
                    Stop(reason);
                    return false;
                }

                return true;
            }, () =>
            {
                if (isOpen)
                {
                    double tmPressure = tm.ChamberPressure;
                    double targetPressure = 0.0;

                    if (ModuleHelper.IsPm(_paramTarget))
                    {
                        targetPressure = DEVICE.GetDevice<IoPressure>($"{module}.PT1").FeedBack;
                    }
                    else
                    {
                        Stop($"{module} not define pressure condition");
                        return false;
                    }
                    return Math.Abs(tmPressure - targetPressure) <= _maxPressureDiffOpenSlitValve;
                }

                return true;
                
            },
            timeDelay * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"can not complete in {timeDelay} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        public void SetSlitValve(int id, TM tm, string module, bool isOpen, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify($"set slit valve {module} " + (isOpen ? "Open" : "Close"));

                if (!tm.SetSlitValve(ModuleHelper.Converter(module), isOpen, out string reason))
                {
                    Stop(reason);
                    return false;
                }

                return true;
            }, () =>
            {
                return isOpen ? tm.CheckSlitValveOpen(ModuleHelper.Converter(module)) : tm.CheckSlitValveClose(ModuleHelper.Converter(module));

            }, timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"can not complete in {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        public void CheckPressureCondition(int id, TM tm, string target)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
                {
                    Notify($"check pressure condition to open {target} slit valve");

                    double tmPressure = tm.ChamberPressure;
                    double targetPressure = 0.0;
                    if (ModuleHelper.IsLoadLock(_paramTarget))
                    {
                        targetPressure = _ll.ChamberPressure;
                    }
                    else if(_paramTarget == ModuleName.UnLoad.ToString())
                    {
                        targetPressure = _unLoad.ChamberPressure;
                    }
                    else if (ModuleHelper.IsPm(_paramTarget))
                    {
                        targetPressure = DEVICE.GetDevice<IoPressure>($"{target}.PT1").FeedBack;
                    }
                    else if (_paramTarget == ModuleName.Buffer.ToString())
                    {
                        targetPressure = tm.ChamberPressure;
                    }
                    else
                    {
                        Stop($"{target} not define pressure condition");
                        return false;
                    }

                    double pressureDiff = Math.Abs(tmPressure - targetPressure);
                    if (pressureDiff > _maxPressureDiffOpenSlitValve)
                    {
                        Stop($"pressure difference {pressureDiff:F3}  between TM and {target} exceed tolerance {_maxPressureDiffOpenSlitValve}");
                        return false;
                    }

                    return true;
                });

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        public void SetSlowVentValve(int id, SicTM tm, bool isOpen, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                string op = isOpen ? "Open" : "Close";

                Notify($"{op} Slow Vent Valve");

                if (!tm.SetSlowVentValve(isOpen, out string reason))
                {
                    Stop(reason);
                    return false;
                }

                return true;
            }, () =>
            {
                return tm.CheckSlowVentValve(isOpen);

            }, timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"Set Slow Vent Valve timeout, over {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        public void SetTmMfc(int id, double flow)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                Notify($"Set TM MFC flow to {flow} ");

                _tm.SetVentMfc(flow, out string reason);

                return true;
            });

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        public void SetConfinementRingUp(int id, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify($"Set Confinement RingUp");

                _confinementRing.MoveUpPos(out string reason);

                return true;
            }, () =>
            {
                 return _confinementRing.RingDone && _confinementRing.RingUpSensor;

            }, timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"Set Confinement RingUp timeout, over {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        public void WaitPMIdle(int id, string _targetModule, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                return true;
            }, () =>
            {
                string pm1Status = DATA.Poll($"{_targetModule}.Status") == null ? "" : DATA.Poll($"{_targetModule}.Status").ToString();
                return pm1Status == "ProcessIdle" || pm1Status == "Idle";

            }, timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"Wait PM Idle timeout, over {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }


        protected void SetConfinementRingDownAndWait(int id, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify($"Set ConfinementRing Down");

                if (!_confinementRing.MoveDownPos(out string reason))
                {
                    Stop(reason);
                    return false;
                }
                return true;
            }, () =>
            {
                return _confinementRing.RingDone && _confinementRing.RingDownSensor;
            },
             timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT)
                {
                    Stop($"Set ConfinementRing Down, over {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }


        public void SetPostTransfer(int id, bool postTransferEnableHeat)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                Notify($"Set PostTransfer");

                OP.DoOperation($"{_paramTarget}.PostTransfer", new object[] { postTransferEnableHeat });

                return true;
            });

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        public void SetPreTransfer(int id, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify($"Set PSU and SCR Disable");

                if (_sicServo != null)
                {
                    _sicServo.SetActualSpeed(0, 0);
                }
                if (!_preTransferPSUEnable)
                {
                    PSU1.SetPSUEnable(false, out _);
                    PSU2.SetPSUEnable(false, out _);
                    PSU3.SetPSUEnable(false, out _);
                }
                if (!_preTransferSCREnable)
                {
                    SCR1.SetEnable(false, out _);
                    SCR2.SetEnable(false, out _);
                    SCR3.SetEnable(false, out _);
                }
                return true;
            }, () =>
            {
                if (_sicServo.ActualSpeedFeedback > 0)
                {
                    return false;
                }
                if (!_preTransferPSUEnable)
                {
                    if (PSU1 != null && PSU1.StatusFeedBack)
                    {
                        return false;
                    }
                    if (PSU2 != null && PSU2.StatusFeedBack)
                    {
                        return false;
                    }
                    if (PSU3 != null && PSU3.StatusFeedBack)
                    {
                        return false;
                    }
                }
                if (!_preTransferSCREnable)
                {
                    if (SCR1 != null && SCR1.StatusFeedBack)
                    {
                        return false;
                    }
                    if (SCR2 != null && SCR2.StatusFeedBack)
                    {
                        return false;
                    }
                    if (SCR3 != null && SCR3.StatusFeedBack)
                    {
                        return false;
                    }
                }
                return true;

            }, timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"Set PreTransfer timeout, over {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }


        private void WaitTempratureBelow900(int id, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify($"Wait DiHeaterTempBelow900CSW");
                return true;

            }, () =>
            {
                if (_pmIoInterLock != null)
                {
                    return _pmIoInterLock.DiHeaterTempBelow900CSW;
                }
                else
                {
                    return true;
                }
            },
            timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT)
                {
                    Stop($"Wait PM Temprature below 900 timeout, over {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

        private void WaitPVTempratureBelowSet(int id, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, ()=>
            {
                Notify($"Wait PV2Temp below{_pmPVTempLimit}℃ and PV3Temp below{_pmPVTempLimit}℃");
                return true;

            }, () =>
            {
                if (_tc1 != null && _pmPVTempLimit > 0)
                {
                    return _tc1.L2PVFeedBack < _pmPVTempLimit && _tc1.L3PVFeedBack < _pmPVTempLimit;
                }
                else
                {
                    return true;
                }
            },
            timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT)
                {
                    Stop($"Wait PM Temprature below 900 timeout, over {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }
    }


}
