using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Aitex.Core.Common;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Fsm;
using Aitex.Core.RT.IOCore.Interlock;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Core.Utilities;
using Aitex.Sorter.Common;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.MECF.Framework.Common.RecipeCenter.Recipe;
using MECF.Framework.Common.MultiProcess.ProcessCenter;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.RT.Core.Managers.PDS;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.GasFlow;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs;
using SicModules.PMs.RecipeExecutions;
using SicModules.PMs.Routines;
using SicModules.PMs.Routines.Recipe;

namespace SicModules.PMs
{
    public partial class PMModule : PMModuleBase, IRecipeExecutor
    {
        public enum STATE
        {
            NotInstall,
            NotConnected,
            Init,
            Idle,
            //Safety,
            ProcessIdle,
            Homing,
            ToAtmIdle,
            ToProcessIdle,
            Pump,
            Vent,
            Purge,
            OpenSlitValve,
            CloseSlitValve,
            Error,
            PrepareTransfer,
            PostTransfer,
            PreProcess,
            PostProcess,
            Process,
            ProcessAborting,
            Aborting,
            LeakCheck,
            MFCCali,
            Paused,
            LidMoving,
            LidMoving0,
            BottomMoving,
            OpenLid,
            Clean,
            Isolation,
            ExchangeMO,
            ServopUp,
            ServoDown,
            ServoHome,
            ServoReset,
            ToDefault,
            PcCalibration,
            ServoReset0,
            ServoReset1,
            ServoDown0,
            ServoDown1,
            ServopUp0,
            ServopUp1,
            ServoHome0,
            ServoHome1,
            PcCalibration0,
            PreTransfer,
            VacIdle,
            ToProcessIdle1,
            ToVacIdle1,
            ToVacIdle,
            ToProcessIdle2,
            PrePMMacro,
            PMMacro,
            PostPMMacro,
            PMMacroPause,
            ServiceIdle,
            StopHeat,
            CleanProcess,
            MfcRor,

        }
        public enum MSG
        {
            Home,
            Reset,
            Abort,
            ProcessAbort,
            Error,
            Error1,
            Connected,
            Disconnected,
            Transfer,
            PrepareTransfer,
            PostTransfer,
            Pump,
            Vent,
            Purge,
            OpenSlitValve,
            CloseSlitValve,
            SelectRecipe,
            RunRecipe,
            RecipeSkipStep,
            Pause,
            Continue,

            PostProcess,
            Process,
            LeakCheck,
            StartMFCCalibration,
            ChamberMoveBody,
            ChamberMoveBottom,
            ShowMessage,
            ToInit,
            ToSafety,
            AtmIdle,
            ToProcessIdle,
            OpenLid,
            Clean,
            Isolation,
            ExchangeMO,
            ServopUp,
            ServoDown,
            ServoHome,
            ServoReset,
            ToDefault,
            PreTransfer,
            PcCalibration,
            VacIdle,

            RunPMMacro,
            PMMacro,
            PostPMMacro,
            ToServiceIdle,
            StopHeat,
            CleanProcess,
            MfcRor,

        }
        public enum ServoState
        {
            Home,
            Homing,
            Up,
            Uping,
            Down,
            Downing
        }

        public bool IsServiceIdle { get; set; }

        public ServoState ServoStatus { get; set; }
        public bool IsMoRoutineRuning
        {
            get { return FsmState == (int)STATE.ExchangeMO; }
        }

        public bool IsServiceMode
        {
            get { return IsServiceIdle; }// !IsOnline; }
        }

        public bool DI206EqualsTrue_OR_DO177EqualsTrue
        {
            get { return (V73.Status || _pmInterLock.DoExchangeMoRoutineRunning); }
        }

        public override bool IsInit
        {
            get { return FsmState == (int)STATE.Init; }
        }

        public bool IsSafety
        {
            get { return false; }
            //get { return FsmState == (int)STATE.Safety; }
        }

        public bool IsBusy
        {
            get { return !IsInit && !IsSafety && !IsError && !IsIdle && !IsProcessIdle; }
        }
        public bool IsProcessing
        {
            get { return FsmState == (int)STATE.Process; }
        }

        public override bool IsIdle
        {
            get { return FsmState == (int)STATE.Idle && CheckAllMessageProcessed(); }
        }

        public override bool IsProcessIdle
        {
            get { return FsmState == (int)STATE.ProcessIdle && CheckAllMessageProcessed(); }
        }

        public RecipeRunningInfo RecipeRunningInfo
        {
            get
            {
                return _recipeRunningInfo;
            }
        }

        public override bool IsReady
        {
            get { return (FsmState == (int)STATE.Idle || FsmState == (int)STATE.ProcessIdle || FsmState == (int)STATE.VacIdle) && CheckAllMessageProcessed(); }
        }

        public override bool IsError
        {
            get { return FsmState == (int)STATE.Error; }
        }

        public override bool IsService
        {
            get { return IsServiceIdle; }
        }


        public bool IsAlarm
        {
            get
            {
                return FsmState == (int)STATE.Error;
            }
        }


        public bool IsWarning
        {
            get
            {
                int count = 0;
                var warnings = EV.GetAlarmEvent();
                foreach (var warm in warnings)
                {
                    if (warm.Level == EventLevel.Warning && warm.Source == Name)
                        count++;
                }

                return !IsAlarm && count > 0;
            }
        }

        public bool IsPaused { get; set; }

        public int CurrentRoutineLoop
        {
            get
            {
                if (FsmState == (int)STATE.Purge)
                {
                    return _purgeRoutine.LoopCounter + 1; // CurrentLoop从0开始
                }
                else if (FsmState == (int)STATE.Clean)
                {
                    return _cleanRoutine.LoopCounter + 1;
                }

                return 0;
            }
        }

        public int CurrentRoutineLoopTotal
        {
            get
            {
                if (FsmState == (int)STATE.Purge)
                {
                    return _purgeRoutine.LoopTotalTime;
                }
                else if (FsmState == (int)STATE.Clean)
                {
                    return _cleanRoutine.LoopTotalTime;
                }

                return 0;
            }
        }


        public void ResetToleranceChecker()
        {

        }

        public void OnProcessStart(string v1, string recipeName, bool v2)
        {

        }

        public void PauseRecipe(out string reason)
        {
            reason = string.Empty;
            StopRamp();
        }

        public bool CheckEndPoint()
        {
            return true;
        }

        public bool CheckAllDevicesStable(float v1, float v2, float v3, float v4, float v5, float v6, float v7, float v8, float v9)
        {
            return true;
        }

        public bool CheckEnableRunProcess(out string reason)
        {
            reason = string.Empty;
            return true;
        }

        public string GetWaferSequenceID()
        {
            WaferInfoRt waferInfo = WaferManager.Instance.GetWafer(ModuleHelper.Converter(Module), 0);
            return waferInfo != null ? waferInfo.PPID : string.Empty;
        }

        public string GetWaferLotID()
        {
            WaferInfoRt waferInfo = WaferManager.Instance.GetWafer(ModuleHelper.Converter(Module), 0);
            return waferInfo != null ? waferInfo.LotId : string.Empty;
        }

        public void AbortRunProcess(out string reason)
        {
            _pmInterLock.SetPMProcessRunning(false, out reason);
            _pmInterLock.SetPMPreProcessRunning(false, out reason);
            _pmInterLock.SetPMPostProcessRunning(false, out reason);
            reason = string.Empty;
            StopRamp();
            SetRotationServo(0, 0);

            
        }

        public event Action<string> OnEnterError;

        //PM真值表对象
        private PMGasTrueTableInitialize PMGasTrueTable;

        //private PMPumpRoutine _pumpRoutine;
        //private PMVentRoutine _ventRoutine;
        private PMChamberMoveBodyRoutine _chamberMoveBodyRoutine;
        private PMButttomSectionMoveRoutine pMButttomSectionMoveRoutine;
        private PMLeakCheckRoutine _leakCheckRoutine;
        private PMPumpRoutine _pumpRoutine;
        private PMPurgeRoutine _purgeRoutine;
        private PMMfcRorRoutine _mfcRorRoutine;
        private PMToAtmIdleRoutine _toAtmIdleRoutine;
        private PMVacIdleRoutine _vacIdleRoutine;
        private PMVentRoutine _ventRoutine;
        private PMToIsolationRoutine _toIsolationRoutine;
        private PMCleanRoutine _cleanRoutine;
        private PMExchangeMoRoutine _changeMoRoutine;

        private PreProcess _preprocessRoutine;
        private Process _processRoutine;
        private PostProcess _postprocessRoutine;
        private PMToProcessIdleRoutine _pmtoProcessIdle;
        private PMProcessAbortRoutine _pmProcessAbort;
        private ModuleName _module;

        private RecipeRunningInfo _recipeRunningInfo = new RecipeRunningInfo();

        private PMServoToPressure _pmServoToPressure;

        private PMPcCalibrationRoutine _pmPcCalibrationRoutine;

        private PMPostTransferRoutine _pmPostTransfer;
        private PMPrepareTransferRoutine _pmPreTransfer;

        private PMMacroRoutine _pMMacroRoutine;
        private PMStopHeatEnableRoutine _stopHeatEnableRoutine;
        private CleanRecipe _cleanRecipe;

        private bool _isInitFlag = false;

        private readonly ProcessDataStatManager _procDataStatManager;

        public PMModule(ModuleName module) : base(1)
        {
            _module = module;

            Module = module.ToString();
            Name = module.ToString();

            
            _procDataStatManager = new ProcessDataStatManager(module.ToString());

            IsOnline = false;

            EnumLoop<STATE>.ForEach((item) =>
            {
                MapState((int)item, item.ToString());
            });

            EnumLoop<MSG>.ForEach((item) =>
            {
                MapMessage((int)item, item.ToString());
            });

            EnableFsm(50, IsInstalled ? STATE.Init : STATE.NotInstall);
        }

        public override bool Initialize()
        {
            InitRoutine();

            InitDevice();

            InitInterlock();

            InitFsm();

            InitOp();

            InitData();

            InitalDeviceFunc();

            InitScChangeCallback();

            return base.Initialize();
        }

        private void InitScChangeCallback()
        {
            // Bypass Interlock时自动Offline
            SC.RegisterValueChangedCallback($"PM.{Module}.BypassInterlock", isBypassed =>
            {
                if (isBypassed is true && IsOnline)
                {
                    PutOffline();
                    EV.PostWarningLog(Module, "Offline automatically due to interlock bypassed");
                }
            });
        }   

        private void InitRoutine()
        {
            _purgeRoutine = new PMPurgeRoutine(ModuleHelper.Converter(Module), this);
            _leakCheckRoutine = new PMLeakCheckRoutine(ModuleHelper.Converter(Module), this);
            _chamberMoveBodyRoutine = new PMChamberMoveBodyRoutine(ModuleHelper.Converter(Module), this);
            pMButttomSectionMoveRoutine = new PMButttomSectionMoveRoutine(ModuleHelper.Converter(Module), this);

            _preprocessRoutine = new PreProcess(ModuleHelper.Converter(Module), this);
            _processRoutine = new Process(ModuleHelper.Converter(Module), this);
            _postprocessRoutine = new PostProcess(ModuleHelper.Converter(Module), this);

            _toAtmIdleRoutine = new PMToAtmIdleRoutine(ModuleHelper.Converter(Module), this);
            _vacIdleRoutine = new PMVacIdleRoutine(ModuleHelper.Converter(Module), this);
            _ventRoutine = new PMVentRoutine(ModuleHelper.Converter(Module), this);
            _pumpRoutine = new PMPumpRoutine(ModuleHelper.Converter(Module), this);
            _cleanRoutine = new PMCleanRoutine(ModuleHelper.Converter(Module), this);
            _purgeRoutine = new PMPurgeRoutine(ModuleHelper.Converter(Module), this);
            _mfcRorRoutine = new PMMfcRorRoutine(ModuleHelper.Converter(Module), this);
            _toIsolationRoutine = new PMToIsolationRoutine(ModuleHelper.Converter(Module), this);
            _changeMoRoutine = new PMExchangeMoRoutine(ModuleHelper.Converter(Module), this);

            _pmServoToPressure = new PMServoToPressure(ModuleHelper.Converter(Module), this);
            _pmtoProcessIdle = new PMToProcessIdleRoutine(ModuleHelper.Converter(Module), this);

            _pmPcCalibrationRoutine = new PMPcCalibrationRoutine(ModuleHelper.Converter(Module), this);
            _pmPostTransfer = new PMPostTransferRoutine(ModuleHelper.Converter(Module), this);
            _pmPreTransfer = new PMPrepareTransferRoutine(ModuleHelper.Converter(Module), this);

            _pMMacroRoutine = new PMMacroRoutine(ModuleHelper.Converter(Module), this);
            _stopHeatEnableRoutine = new PMStopHeatEnableRoutine(ModuleHelper.Converter(Module), this);
            _cleanRecipe = new CleanRecipe(ModuleHelper.Converter(Module), this);

            _pmProcessAbort = new PMProcessAbortRoutine(ModuleHelper.Converter(Module), this);

            //初始化加载真值表
            PMGasTrueTable = new PMGasTrueTableInitialize(Module, $"Config\\PM\\{Module}\\RealtimeGasFlow{Module}.xml");

        }

        private void InitData()
        {
            DATA.Subscribe($"{Module}.Status", () => StringFsmStatus.Replace("0", "").Replace("1", "").Replace("2", ""));
            DATA.Subscribe($"{Module}.IsOnline", () => IsOnline);
            DATA.Subscribe($"{Module}.IsProcessing", () => IsProcessing);   
            DATA.Subscribe($"{Module}.IsService", () => IsServiceIdle);
            DATA.Subscribe($"{Module}.DI206EqualsTrue_OR_DO177EqualsTrue", () => DI206EqualsTrue_OR_DO177EqualsTrue, SubscriptionAttribute.FLAG.IgnoreSaveDB);

            DATA.Subscribe($"{Module}.IsAlarm", () => IsAlarm);
            DATA.Subscribe($"{Module}.IsWarning", () => IsWarning);
            DATA.Subscribe($"{Module}.IsIdle", () => !IsWarning && (IsIdle || IsInit || IsSafety));
            DATA.Subscribe($"{Module}.IsBypassInterlock", () => IsBypassInterlock);
            DATA.Subscribe($"{Module}.IsBypassEnableTable", () => IsBypassEnableTable);

            DATA.Subscribe($"{Module}.WaferSize", () => WaferManager.Instance.GetWaferSize(_module, 0).ToString());

            DATA.Subscribe($"{Name}.LeakCheckElapseTime", () =>
            {
                if (FsmState == (int)STATE.LeakCheck)
                    return _leakCheckRoutine.ElapsedTime;
                return 0;
            });


            DATA.Subscribe($"{Name}.ChamberPressure", () => ChamberPressure);

            DATA.Subscribe($"{Name}.ServoStatus", () => ServoStatus.ToString());

            DATA.Subscribe($"{Name}.SelectedRecipeName", () => _recipeRunningInfo.RecipeName);
            DATA.Subscribe($"{Name}.RecipeStepNumber", () => _recipeRunningInfo.StepNumber);
            DATA.Subscribe($"{Name}.RecipeStepName", () => _recipeRunningInfo.StepName);
            DATA.Subscribe($"{Name}.RecipeStepElapseTime", () => _recipeRunningInfo.StepElapseTime);
            DATA.Subscribe($"{Name}.RecipeStepTime", () => _recipeRunningInfo.StepTime);
            DATA.Subscribe($"{Name}.RecipeTotalElapseTime", () => _recipeRunningInfo.TotalElapseTime);
            DATA.Subscribe($"{Name}.RecipeTotalTime", () => _recipeRunningInfo.TotalTime);
            DATA.Subscribe($"{Name}.CurrentRoutineLoop", () => CurrentRoutineLoop);
            DATA.Subscribe($"{Name}.CurrentRoutineLoopTotal", () => CurrentRoutineLoopTotal);
            DATA.Subscribe($"{Name}.RecipeStepList", () => _recipeRunningInfo.RecipeStepList);

            DATA.Subscribe($"{Name}.RecipeStepElapseTime2", () => _recipeRunningInfo.StepElapseTime2);
            DATA.Subscribe($"{Name}.RecipeTotalElapseTime2", () => _recipeRunningInfo.TotalElapseTime2);

            //DATA.Subscribe($"{Name}.ArH2Switch", () => _recipeRunningInfo.ArH2Switch);
            //DATA.Subscribe($"{Name}.N2FlowMode", () => _recipeRunningInfo.N2FlowMode);

            //MfcRor测试数据
            DATA.Subscribe($"{Name}.StandardMfcRorData", () => _mfcRorRoutine.StandardMfcRorData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.MfcNameList", () => _mfcRorRoutine.MfcNameList, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.MfcRorList", () => _mfcRorRoutine.MfcRorList, SubscriptionAttribute.FLAG.IgnoreSaveDB);
        }

        private void InitOp()
        {
            OP.Subscribe($"{Module}.Home", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Home));
            OP.Subscribe($"{Module}.Reset", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Reset));
            OP.Subscribe($"{Module}.Abort", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Abort));

            OP.Subscribe($"{Module}.Pump", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Pump));
            OP.Subscribe($"{Module}.Vent", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Vent));
            OP.Subscribe($"{Module}.Purge", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Purge));

            OP.Subscribe($"{Module}.OpenLid", (string cmd, object[] args) => CheckToPostMessage((int)MSG.OpenLid));
            OP.Subscribe($"{Module}.Isolation", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Isolation));
            OP.Subscribe($"{Module}.Clean", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Clean));
            OP.Subscribe($"{Module}.ExchangeMO", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ExchangeMO, (string)args[0]));
            OP.Subscribe($"{Module}.ToDefault", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ToDefault));

            OP.Subscribe($"{Module}.SetOnline", (string cmd, object[] args) => PutOnline());
            OP.Subscribe($"{Module}.SetOffline", (string cmd, object[] args) => PutOffline());

            OP.Subscribe($"{Name}.SelectRecipe", (string cmd, object[] args) => CheckToPostMessage((int)MSG.SelectRecipe, args[0]));
            OP.Subscribe($"{Name}.RunRecipe", (string cmd, object[] args) => CheckToPostMessage((int)MSG.RunRecipe, (string)args[0], (bool)args[1], (bool)args[2]));
            OP.Subscribe($"{Name}.RecipeSkipStep", (string cmd, object[] args) => CheckToPostMessage((int)MSG.RecipeSkipStep));
            OP.Subscribe($"{Name}.Pause", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Pause));
            OP.Subscribe($"{Name}.Continue", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Continue, args[0].ToString()));

            OP.Subscribe($"{Name}.LeakCheck", (string cmd, object[] args) => CheckToPostMessage((int)MSG.LeakCheck, args));

            OP.Subscribe($"{Module}.ChamberMoveBodyOpen", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ChamberMoveBody, args));
            OP.Subscribe($"{Module}.ChamberBottomOpen", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ChamberMoveBottom, args));
            OP.Subscribe($"{Module}.ShowMessage", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ShowMessage, args));

            OP.Subscribe($"{Module}.ToAtmIdle", (string cmd, object[] args) => CheckToPostMessage((int)MSG.AtmIdle));
            OP.Subscribe($"{Module}.ToVacIdle", (string cmd, object[] args) => CheckToPostMessage((int)MSG.VacIdle));
            OP.Subscribe($"{Module}.ToProcessIdle", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ToProcessIdle));

            OP.Subscribe($"{Module}.ServoHome", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ServoHome));
            OP.Subscribe($"{Module}.ServoUp", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ServopUp));
            OP.Subscribe($"{Module}.ServoDown", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ServoDown));
            OP.Subscribe($"{Module}.ServoReset", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ServoReset));


            OP.Subscribe($"{Module}.PostTransfer", (string cmd, object[] args) => CheckToPostMessage((int)MSG.PostTransfer));
            OP.Subscribe($"{Module}.PreTransfer", (string cmd, object[] args) => CheckToPostMessage((int)MSG.PreTransfer));
            OP.Subscribe($"{Module}.SetToServiceIdle", (string cmd, object[] args) => CheckToPostMessage((int)MSG.ToServiceIdle));

            OP.Subscribe($"{Module}.PcCalibration", (string cmd, object[] args) => CheckToPostMessage((int)MSG.PcCalibration));
            OP.Subscribe($"{Module}.RunPMMacro", (string cmd, object[] args) => CheckToPostMessage((int)MSG.RunPMMacro, (string)args[0]));

            OP.Subscribe($"{Module}.CleanRecipe", (string cmd, object[] args) => CheckToPostMessage((int)MSG.CleanProcess, (string)args[0]));

            OP.Subscribe($"{Module}.ReloadRecipe", (string cmd, object[] args) => ReloadRecipe((string)args[0], (Dictionary<string, List<string>>)args[1]));

            OP.Subscribe($"{Module}.MfcRor", (string cmd, object[] args) => CheckToPostMessage((int)MSG.MfcRor, args));


            OP.Subscribe($"{Module}.ClearMfcRorData", (string cmd, object[] args) => ClearMfcRorData());
        }

        private bool ReloadRecipe(string reloadedRecipe, Dictionary<string, List<string>> highlightlist)
        {
            _recipeRunningInfo.XmlRecipeToReload = reloadedRecipe;
            _recipeRunningInfo.HighlightDic = highlightlist;
            _recipeRunningInfo.NeedReloadRecipe = true;
            return true;
        }
        private bool PutOnline()
        {
            if (IsService)
            {
                EV.PostWarningLog(Module, $"{Module} is Service State, can not be Online");
                return false;
            }

            // 检查互锁，如果互锁旁路，则不能Online
            DoIfInterlockNotBypassed(() =>
            {
                IsOnline = true;
                NotifyModuleOfflineCancellation.Cancel();
            });
            return true;
        }

        private bool PutOffline()
        {
            //if (StringFsmStatus != "Process")
            {
                IsOnline = false;
                NotifyModuleOfflineCancellation?.Dispose();
                NotifyModuleOfflineCancellation = new CancellationTokenSource();
                NotifyModuleOfflineTask(5 * 60 * 1000);//5min
                return true;
            }
            //return true;
        }

        private void InitFsm()
        {
            //Error
            Transition(STATE.Error, MSG.Reset, FsmReset, STATE.Idle);
            AnyStateTransition(MSG.Error, FsmOnError, STATE.Error);        //在Service模式下,不成功
            AnyStateTransition(FSM_MSG.ALARM, FsmOnError, STATE.Error);
            AnyStateTransition(MSG.Error1, FsmOnError1, STATE.Error);      //在Routine失败时生效
            AnyStateTransition(MSG.ToInit, FsmToInit, STATE.Init);

            EnterExitTransition<STATE, FSM_MSG>(STATE.Error, FsmEnterError, FSM_MSG.NONE, FsmExitError);

            Transition(STATE.Init, MSG.Disconnected, null, STATE.NotConnected);
            Transition(STATE.Init, MSG.Home, FsmStartHome, STATE.Homing);

            //not connected
            Transition(STATE.NotConnected, MSG.Connected, null, STATE.Init);

            //Home(ToSafety过程)
            EnterExitTransition((int)STATE.Homing, FsmEnterHome, (int)FSM_MSG.NONE, FsmExitHome);
            Transition(STATE.Error, MSG.Home, FsmStartHome, STATE.Homing);
            Transition(STATE.Homing, FSM_MSG.TIMER, FsmMonitorHomeTask, STATE.Idle);
            Transition(STATE.Homing, MSG.Error, null, STATE.Init);
            Transition(STATE.Homing, MSG.Abort, FsmAbortTask, STATE.Init);

            //AtmIdle
            Transition(STATE.Idle, MSG.AtmIdle, FsmToAtmIdle, STATE.ToAtmIdle);
            Transition(STATE.VacIdle, MSG.AtmIdle, FsmToAtmIdle, STATE.ToAtmIdle);
            Transition(STATE.ProcessIdle, MSG.AtmIdle, FsmToAtmIdle, STATE.ToAtmIdle);
            Transition(STATE.ToAtmIdle, FSM_MSG.TIMER, FsmMonitorSafetyTask, STATE.Idle);
            Transition(STATE.ToAtmIdle, MSG.Abort, FsmAbortTask, STATE.Idle);

            //Idle
            Transition(STATE.Idle, MSG.ToProcessIdle, FsmToProcessIdle, STATE.ToProcessIdle); //ToProcessIdle
            Transition(STATE.ToProcessIdle, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.ToProcessIdle, MSG.Abort, FsmAbortTask, STATE.Idle);
            Transition(STATE.Idle, MSG.Home, FsmStartHome, STATE.Homing);                   //ToSafety (Homing过程)


            //VacIdle
            Transition(STATE.Idle, MSG.VacIdle, FsmVacIdle, STATE.ToVacIdle);
            Transition(STATE.VacIdle, MSG.VacIdle, FsmVacIdle, STATE.ToVacIdle);
            Transition(STATE.ToVacIdle, FSM_MSG.TIMER, FsmMonitorTask, STATE.VacIdle);
            Transition(STATE.ToVacIdle, MSG.Abort, FsmAbortTask, STATE.Idle);

            Transition(STATE.ProcessIdle, MSG.VacIdle, FsmVacIdle, STATE.ToVacIdle1);
            Transition(STATE.VacIdle, MSG.ToProcessIdle, FsmToProcessIdle, STATE.ToProcessIdle1);
            Transition(STATE.ToProcessIdle1, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.ToProcessIdle1, MSG.Abort, FsmAbortTask, STATE.VacIdle);
            Transition(STATE.ToVacIdle1, FSM_MSG.TIMER, FsmMonitorTask, STATE.VacIdle);
            Transition(STATE.ToVacIdle1, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);

            //ToServiceIdle
            Transition(STATE.Idle, MSG.ToServiceIdle, FsmToService, STATE.Idle);
            Transition(STATE.VacIdle, MSG.ToServiceIdle, FsmToService, STATE.VacIdle);
            Transition(STATE.Error, MSG.ToServiceIdle, FsmToService, STATE.Error);


            //ProcessIdle
            Transition(STATE.ProcessIdle, MSG.ToProcessIdle, FsmToProcessIdle, STATE.ToProcessIdle);
            EnterExitTransition<STATE, FSM_MSG>(STATE.ProcessIdle, FsmEnterProcessIdle, FSM_MSG.NONE, FsmExitProcessIdle);

            Transition(STATE.ProcessIdle, MSG.PrepareTransfer, FsmStartPrepareTransfer, STATE.PrepareTransfer);
            Transition(STATE.PrepareTransfer, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.PrepareTransfer, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);

            Transition(STATE.ProcessIdle, MSG.PreTransfer, FsmStartPreTransfer2, STATE.PreTransfer);
            Transition(STATE.PreTransfer, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.PreTransfer, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);

            Transition(STATE.ProcessIdle, MSG.PostTransfer, FsmStartPostTransfer, STATE.PostTransfer);
            Transition(STATE.PostTransfer, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.PostTransfer, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);

            Transition(STATE.ProcessIdle, MSG.OpenSlitValve, FsmStartOpenSlitValve, STATE.OpenSlitValve);
            Transition(STATE.OpenSlitValve, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.OpenSlitValve, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);

            Transition(STATE.ProcessIdle, MSG.CloseSlitValve, FsmStartCloseSlitValve, STATE.CloseSlitValve);
            Transition(STATE.CloseSlitValve, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.CloseSlitValve, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);

            Transition(STATE.ProcessIdle, MSG.CleanProcess, FsmStartCleanRecipe, STATE.CleanProcess);
            Transition(STATE.CleanProcess, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.CleanProcess, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);

            //MoveBody
            Transition(STATE.Idle, MSG.ChamberMoveBody, FsmStartMoveBody, STATE.LidMoving);
            Transition(STATE.LidMoving, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.LidMoving, MSG.Abort, FsmAbortTask, STATE.Idle);


            //PcCalibration
            Transition(STATE.Idle, MSG.PcCalibration, FsmStartPcCalibration, STATE.PcCalibration);
            Transition(STATE.PcCalibration, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.PcCalibration, MSG.Abort, FsmAbortTask, STATE.Idle);



            //ShowMessage
            Transition(STATE.Idle, MSG.ShowMessage, ShowMessage, STATE.Idle);
            Transition(STATE.Init, MSG.ShowMessage, ShowMessage, STATE.Init);  //测试时防报错

            //Pump
            Transition(STATE.Idle, MSG.Pump, FsmStartPump, STATE.Pump);
            Transition(STATE.Pump, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.Pump, MSG.Abort, FsmAbortTask, STATE.Idle);

            //Vent
            Transition(STATE.Idle, MSG.Vent, FsmStartVent, STATE.Vent);
            Transition(STATE.Vent, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.Vent, MSG.Abort, FsmAbortTask, STATE.Idle);

            //Purge
            Transition(STATE.Idle, MSG.Purge, FsmStartPurge, STATE.Purge);
            Transition(STATE.Purge, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.Purge, MSG.Abort, FsmAbortTask, STATE.Idle);

            //MfcRor
            Transition(STATE.VacIdle, MSG.MfcRor, FsmStartMfcRor, STATE.MfcRor);
            Transition(STATE.Idle, MSG.MfcRor, FsmStartMfcRor, STATE.MfcRor);
            Transition(STATE.MfcRor, FSM_MSG.TIMER, FsmMonitorTask, STATE.VacIdle);
            Transition(STATE.MfcRor, MSG.Abort, FsmAbortTask, STATE.VacIdle);

            //Leak check
            Transition(STATE.Idle, MSG.LeakCheck, FsmStartLeakCheck, STATE.LeakCheck);
            Transition(STATE.LeakCheck, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.LeakCheck, MSG.Abort, FsmAbortTask, STATE.Idle);

            //OpenLid
            Transition(STATE.Idle, MSG.OpenLid, FsmStartPurge, STATE.OpenLid);
            Transition(STATE.OpenLid, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.OpenLid, MSG.Abort, FsmAbortTask, STATE.Idle);

            //Clean
            Transition(STATE.Idle, MSG.Clean, FsmStartClean, STATE.Clean);
            Transition(STATE.Clean, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.Clean, MSG.Abort, FsmAbortTask, STATE.Idle);

            //ExchangeMO
            Transition(STATE.Idle, MSG.ExchangeMO, FsmStartExchangeMO, STATE.ExchangeMO);
            Transition(STATE.ExchangeMO, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.ExchangeMO, MSG.Abort, FsmAbortTask, STATE.Idle);

            //Pump
            Transition(STATE.VacIdle, MSG.Pump, FsmStartPump, STATE.Pump);
            //Vent
            Transition(STATE.VacIdle, MSG.Vent, FsmStartVent, STATE.Vent);
            //Purge
            Transition(STATE.VacIdle, MSG.Purge, FsmStartPurge, STATE.Purge);
            //Leak check
            Transition(STATE.VacIdle, MSG.LeakCheck, FsmStartLeakCheck, STATE.LeakCheck);
            //OpenLid
            Transition(STATE.VacIdle, MSG.OpenLid, FsmStartPurge, STATE.OpenLid);
            //Clean
            Transition(STATE.VacIdle, MSG.Clean, FsmStartClean, STATE.Clean);
            //ExchangeMO
            Transition(STATE.VacIdle, MSG.ExchangeMO, FsmStartExchangeMO, STATE.ExchangeMO);

            //FsmStartToIsolation
            Transition(STATE.Idle, MSG.Isolation, FsmStartToIsolation, STATE.Isolation);
            Transition(STATE.Isolation, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.Isolation, MSG.Abort, FsmAbortTask, STATE.Idle);

            //ProcessIdle
            Transition(STATE.ProcessIdle, MSG.SelectRecipe, FsmSelectRecipe, STATE.ProcessIdle);
            Transition(STATE.ProcessIdle, MSG.RunRecipe, FsmStartPreProcess, STATE.PreProcess);
            //Transition(STATE.ProcessIdle, MSG.ProcessAbort, FsmStartProcessAbort, STATE.ProcessAborting);
            //Transition(STATE.ProcessIdle, MSG.Abort, FsmStartProcessAbort, STATE.ProcessAborting);

            //PreProcess
            Transition(STATE.PreProcess, FSM_MSG.TIMER, FsmMonitorTask, STATE.PreProcess);
            Transition(STATE.PreProcess, MSG.ProcessAbort, FsmStartProcessAbort, STATE.ProcessAborting);
            Transition(STATE.PreProcess, MSG.Abort, FsmStartProcessAbort, STATE.ProcessAborting);

            //Process
            Transition(STATE.PreProcess, MSG.Process, FsmStartProcess, STATE.Process);
            Transition(STATE.Process, FSM_MSG.TIMER, FsmMonitorTask, STATE.Process);
            Transition(STATE.Process, MSG.ProcessAbort, FsmStartProcessAbort, STATE.ProcessAborting);
            Transition(STATE.Process, MSG.Abort, FsmStartProcessAbort, STATE.Aborting);
            Transition(STATE.ProcessAborting, FSM_MSG.TIMER, FsmMonitorProcessAbortingTask, STATE.Error);
            Transition(STATE.Aborting, FSM_MSG.TIMER, FsmMonitorProcessAbortingTask, STATE.Idle);
            //Transition(STATE.ProcessAborting, MSG.Abort, FsmAbortTask, STATE.Error);
            EnterExitTransition<STATE, FSM_MSG>(STATE.Process, FsmEnterProcess, FSM_MSG.NONE, FsmExitProcess);

            Transition(STATE.Process, MSG.Pause, FsmRecipePause, STATE.Paused);

            Transition(STATE.Paused, FSM_MSG.TIMER, FsmMonitorTask, STATE.Paused);
            Transition(STATE.Paused, MSG.Continue, FsmStartContinue, STATE.Process);
            Transition(STATE.Paused, MSG.Error, null, STATE.Paused);

            Transition(STATE.Process, MSG.RecipeSkipStep, FsmSkipStep, STATE.Process);

            //PostProcess
            Transition(STATE.Process, MSG.PostProcess, FsmStartPostProcess, STATE.PostProcess);
            Transition(STATE.PostProcess, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.PostProcess, MSG.ProcessAbort, FsmStartProcessAbort, STATE.ProcessAborting);
            Transition(STATE.PostProcess, MSG.Abort, FsmStartProcessAbort, STATE.ProcessAborting);
            EnterExitTransition<STATE, FSM_MSG>(STATE.PostProcess, null, FSM_MSG.NONE, ExitPostProcess);

            //MFC Calibration
            Transition(STATE.ProcessIdle, MSG.StartMFCCalibration, FsmStartMFCCalibration, STATE.MFCCali);
            Transition(STATE.MFCCali, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.MFCCali, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);

            Transition(STATE.Idle, MSG.SelectRecipe, FsmSelectRecipe, STATE.Idle);

            //PMMacro相关状态
            Transition(STATE.Idle, MSG.RunPMMacro, FsmStartPMMacro, STATE.PMMacro);
            Transition(STATE.VacIdle, MSG.RunPMMacro, FsmStartPMMacro, STATE.PMMacro);
            Transition(STATE.ProcessIdle, MSG.RunPMMacro, FsmStartPMMacro, STATE.PMMacro);
            Transition(STATE.PMMacro, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle);
            Transition(STATE.PMMacro, MSG.Abort, FsmAbortTask, STATE.Idle);

            Transition(STATE.PMMacro, MSG.Pause, FsmPMMacroPause, STATE.PMMacroPause);
            Transition(STATE.PMMacroPause, FSM_MSG.TIMER, FsmMonitorTask, STATE.PMMacroPause);
            Transition(STATE.PMMacroPause, MSG.Continue, FsmPMMacroContinue, STATE.PMMacro);

            EnterExitTransition<STATE, FSM_MSG>(STATE.PMMacro, null, FSM_MSG.NONE, FsmExitPMMacro);

            //StopHeat
            Transition(STATE.ProcessIdle, MSG.StopHeat, FsmStartStopHeat, STATE.StopHeat);
            Transition(STATE.StopHeat, FSM_MSG.TIMER, FsmMonitorTask, STATE.ProcessIdle);
            Transition(STATE.StopHeat, MSG.Abort, FsmAbortTask, STATE.ProcessIdle);
        }

        private bool FsmEnterProcessIdle(object[] args)
        {
            if (!_pmInterLock.SetPMProcessIdleRunning(true, out var reason))
            {
                LOG.Error($"Failed to set DOProcessIdle to true due to {reason}");
            }

            return true;
        }


        private bool FsmExitProcessIdle(object[] args)
        {
            if (!_pmInterLock.SetPMProcessIdleRunning(false, out var reason))
            {
                LOG.Error($"Failed to set DOProcessIdle to false due to {reason}");
            }

            return true;
        }


        private bool FsmToInit(object[] param)
        {
            return true;
        }

        private bool FsmExitError(object[] param)
        {
            return true;
        }

        private bool FsmEnterError(object[] param)
        {
            AbortRoutine();
            InvokeOnEnterError(Module);
            if (IsOnline)
            {
                EV.PostWarningLog(Module, $"{Module}");
            }

            return true;
        }

        private bool FsmStartPostTransfer(object[] param)
        {
            bool needEnableHeat = false;
            if (param.Length > 0 && bool.TryParse(param[0].ToString(), out needEnableHeat))
            {
                _pmPostTransfer.Init(needEnableHeat);
            }
            Result ret = StartRoutine(_pmPostTransfer);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;

            return ret == Result.RUN;
        }

        private bool FsmStartPrepareTransfer(object[] param)
        {
            QueueRoutine.Clear();

            double targetPressure = SC.GetValue<double>($"TM.PressureBalance.BalancePressure");
            _pmServoToPressure.Init(targetPressure);
            QueueRoutine.Enqueue(_pmServoToPressure);

            Result ret = StartRoutine();
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartPreTransfer2(object[] param)
        {
            Result ret = StartRoutine(_pmPreTransfer);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;

            return ret == Result.RUN;
        }

        private bool FsmStartSetOffline(object[] param)
        {
            IsOnline = false;
            return true;
        }

        private bool FsmStartSetOnline(object[] param)
        {
            if (IsServiceIdle)
            {
                EV.PostWarningLog(Module, $"can not set {Module} online while in service mode");
                return false;
            }
            else
            {
                IsOnline = true;
                return true;
            }
        }

        private bool FsmToAtmIdle(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>("PM.IsAtmIdleRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.AtmIdleFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.AtmRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                ret = StartRoutine(_toAtmIdleRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;

            return ret == Result.RUN;
        }

        private bool FsmVacIdle(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>("PM.IsVacIdleRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.VacIdleFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.VacRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                ret = StartRoutine(_vacIdleRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;

            return ret == Result.RUN;
        }

        private bool FsmToProcessIdle(object[] param)
        {
            Result ret;

            if (IsService)
            {
                EV.PostWarningLog(Module, $"{Module} is Service State, can not do ProcessIdle");
                return false;
            }

            if (SC.GetValue<bool>("PM.IsProcessIdleRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.ProcessIdleFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.ProcessIdleRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                ret = StartRoutine(_pmtoProcessIdle);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;

            return ret == Result.RUN;
        }

        private bool FsmStartPump(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>("PM.IsPumpRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.PumpFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.PumpRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                ret = StartRoutine(_pumpRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartVent(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>("PM.IsVentRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.VentFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.VentRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                ret = StartRoutine(_ventRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;

            return ret == Result.RUN;
        }

        private bool FsmStartPurge(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>("PM.IsPurgeRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.PurgeFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.PurgeRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                ret = StartRoutine(_purgeRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartMfcRor(object[] param)
        {
            Result ret = StartRoutine(_mfcRorRoutine, param);

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartClean(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>("PM.IsCleanRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.CleanFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.CleanRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                ret = StartRoutine(_cleanRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartExchangeMO(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>($"PM.IsExchangeMO{param[0]}Routine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.ExchangeMO{param[0]}FileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.ExchangeMORoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                _changeMoRoutine.Init(param[0].ToString());
                ret = StartRoutine(_changeMoRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartToIsolation(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>("PM.IsIsolationRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.IsolationFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.IsolationRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                ret = StartRoutine(_toIsolationRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartLeakCheck(object[] param)
        {
            Result ret;
            if (SC.GetValue<bool>("PM.IsLeakCheckRoutine"))
            {
                string RoutineFileName = SC.GetStringValue($"PM.{Module}.LeakCheckFileName");

                _pMMacroRoutine.Init(RoutineFileName, RoutineType.LeakCheckRoutine);
                ret = StartRoutine(_pMMacroRoutine);
            }
            else
            {
                if (param != null && param.Length >= 2)
                {
                    _leakCheckRoutine.Init((int)param[0], (int)param[1]);
                }
                else
                {
                    _leakCheckRoutine.Init();
                }

                ret = StartRoutine(_leakCheckRoutine);
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmAbortTask(object[] param)
        {
            Result ret = Result.RUN;
            
            AbortRoutine();

            var workenable = SC.GetValue<bool>("System.MultiProcessMode");
            if (workenable)
            {
                //1.确认连接状态
                var r = (bool)DATA.Poll($"MultiProcessClient.IsConnected");
                if (!r)
                {
                    EV.PostWarningLog("MultiProcessClient", $"MultiProcessClient disconnect, can not do Operation");
                }
                else
                {
                    //2.通知服务器自己进入空闲状态，取消加热基数
                    OP.DoOperation($"MultiProcessClient.UpdateChamberState", Module, "QuitHeating");
                    r = (bool)DATA.Poll($"MultiProcessClient.IsConnected");
                    if (!r)
                    {
                        EV.PostWarningLog("MultiProcessClient", $"MultiProcessClient disconnect, can not do Operation");
                    }
                }
            }

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmToService(object[] param)
        {
            if (IsOnline)
                return false;

            if (IsServiceIdle)
            {
                // 如果退出Service模式，需要检查Interlock是否启用，如果未启用，不能退出Service模式
                DoIfInterlockNotBypassed(() =>
                {
                    IsServiceIdle = false;

                    // 如果退出Service模式，Interlock信息以Warning等级输出
                    Singleton<InterlockManager>.Instance.SetEventLevel(Module, false);
                });
            }
            else
            {
                IsServiceIdle = true;

                // 如果退出Service模式，Interlock信息以Info等级输出
                Singleton<InterlockManager>.Instance.SetEventLevel(Module, true);
            }
            return true;
        }

        private bool FsmStartStopHeat(object[] param)
        {
            Result ret = StartRoutine(_stopHeatEnableRoutine);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartMoveBody(object[] param)
        {
            _chamberMoveBodyRoutine.Init(param);
            Result ret = StartRoutine(_chamberMoveBodyRoutine);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartPcCalibration(object[] param)
        {
            Result ret = StartRoutine(_pmPcCalibrationRoutine);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartCleanRecipe(object[] param)
        {
            _cleanRecipe.Init(param[0].ToString());

            Result ret = StartRoutine(_cleanRecipe);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool ShowMessage(object[] param)
        {
            EV.PostWarningLog(Module, $"{param[0]}");
            return true;
        }

        private bool FsmStartOpenSlitValve(object[] param)
        {
            return true;
        }

        private bool FsmStartCloseSlitValve(object[] param)
        {
            return true;
        }

        private bool FsmSelectRecipe(object[] param)
        {
            _recipeRunningInfo.RecipeName = (string)param[0];
            return true;
        }

        private bool FsmStartPreProcess(object[] param)
        {
            //if (IsServiceIdle)
            //{
            //    EV.PostWarningLog(Module, $"can not set {Module} process while in service mode");
            //    return false;
            //}

            if (IsBypassInterlock || IsBypassEnableTable)
            {
                EV.PostWarningLog(Module, $"Interlock bypassed, unable to start process");
                return false;
            }

            var workenable = SC.GetValue<bool>("System.MultiProcessMode");
            if (workenable)
            {
                bool r = (bool)DATA.Poll($"MultiProcessClient.{Module}.CanEnterProcessNow");
                if (!r)
                {
                    EV.PostWarningLog("MultiProcessClient", $"MultiProcessClient reject, can not do Process");
                    return false;
                }
            }

            _preprocessRoutine.Init((string)param[0], (bool)param[1], (bool)param[2]);
            Result ret = StartRoutine(_preprocessRoutine);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmStartProcess(object[] param)
        {
            Result ret = StartRoutine(_processRoutine);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmEnterProcess(object[] param)
        {
            if (IsService)
            {
                EV.PostWarningLog(Module, $"{Module} is Service State, can not enter Process");
                return false;
            }

            WaferManager.Instance.UpdateWaferProcessStatus(ModuleHelper.Converter(Module), 0, WaferProcessStatus.InProcess);
            _procDataStatManager.Begin(_recipeRunningInfo.RecipeName);
            return true;
        }

        private bool FsmExitProcess(object[] param)
        {
            if (!_processRoutine.IsPaused)
            {
                WaferManager.Instance.UpdateWaferProcessStatus(ModuleHelper.Converter(Module), 0, WaferProcessStatus.Completed);
                _processRoutine.ExitProcess();
                _procDataStatManager.End();
                if (!RecipeRunningInfo.IsRoutineAbort)
                {
                    EV.PostInfoLog(Module, $"Exit Process: Recipe Name {_recipeRunningInfo.RecipeName},Recipe Step:{_recipeRunningInfo.StepNumber},Step Time:{string.Format("{0:F2}", _recipeRunningInfo.StepTime)}");
                    //StopProcess();
                }
            }

            var workenable = SC.GetValue<bool>("System.MultiProcessMode");
            if (workenable)
            {
                //1.确认连接状态
                var r = (bool)DATA.Poll($"MultiProcessClient.IsConnected");
                if (!r)
                {
                    EV.PostWarningLog("MultiProcessClient", $"MultiProcessClient disconnect, can not do Operation");
                }
                else
                {
                    //2.通知服务器自己进入空闲状态，取消加热基数
                    OP.DoOperation($"MultiProcessClient.UpdateChamberState", Module, "QuitProcess");
                    r = (bool)DATA.Poll($"MultiProcessClient.IsConnected");
                    if (!r)
                    {
                        EV.PostWarningLog("MultiProcessClient", $"MultiProcessClient disconnect, can not do Operation");
                    }
                }
            }
            return true;
        }

        private bool FsmRecipePause(object[] param)
        {
            _processRoutine.PauseRecipe();
            return true;
        }

        private bool FsmStartContinue(object[] param)
        {
            _processRoutine.SetContinue((string)param[0]);
            return true;
        }

        private bool FsmSkipStep(object[] param)
        {
            _processRoutine.SkipCurrentRecipeStep();
            return true;
        }

        private bool FsmStartPostProcess(object[] param)
        {
            Result ret = StartRoutine(_postprocessRoutine);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool ExitPostProcess(object[] param)
        {
            _pmInterLock.SetPMProcessRunning(false, out string reason);
            _pmInterLock.SetPMPreProcessRunning(false, out reason);
            _pmInterLock.SetPMPostProcessRunning(false, out reason);
            return true;
        }

        private bool FsmStartMFCCalibration(object[] param)
        {
            return true;
        }

        private bool FsmStartPMMacro(object[] param)
        {
            _pMMacroRoutine.Init((string)param[0]);
            Result ret = StartRoutine(_pMMacroRoutine);
            if (ret == Result.FAIL || ret == Result.DONE)
                return false;
            return ret == Result.RUN;
        }

        private bool FsmPMMacroPause(object[] param)
        {
            _pMMacroRoutine.PauseRecipe();
            return true;
        }

        private bool FsmPMMacroContinue(object[] param)
        {
            _pMMacroRoutine.SetContinue((string)param[0]);
            return true;
        }

        private bool FsmExitPMMacro(object[] param)
        {
            _pMMacroRoutine.ExitProcess();

            return true;
        }

        private bool FsmMonitorProcessAbortingTask(object[] param)
        {
            Result ret = MonitorRoutine();
            if (ret == Result.FAIL)
            {
                return false;
            }

            if (ret == Result.DONE)
            {
                return true;
            }

            return false;
        }

        private bool FsmStartProcessAbort(object[] param)
        {
            AbortRoutine();

            Result ret = StartRoutine(_pmProcessAbort);

            if (ret == Result.FAIL || ret == Result.DONE)
                return false;

            return ret == Result.RUN;
        }

        private bool FsmOnError(object[] param)
        {
            if (IsServiceIdle)
            {
                return false;
            }
            
            if (FsmState.Equals((int)STATE.ProcessAborting))
            {
                return false;
            }

            IsOnline = false;

            StopRamp();
            _pmInterLock.SetPMProcessRunning(false, out string reason);
            _pmInterLock.SetPMPreProcessRunning(false, out reason);
            _pmInterLock.SetPMPostProcessRunning(false, out reason);

            if (FsmState.Equals((int)STATE.Process) || FsmState.Equals((int)STATE.PreProcess) || FsmState.Equals((int)STATE.PostProcess) )
            {
                PostMsg(MSG.ProcessAbort);
                return false;
            }


            return true;
        }

        private bool FsmOnError1(object[] param)
        {
            IsOnline = false;

            if (FsmState.Equals((int)STATE.ProcessAborting))
            {
                return false;
            }

            if (FsmState.Equals((int)STATE.Error))
            {
                return false;
            }
            else
            {
                StopRamp();
                _pmInterLock.SetPMProcessRunning(false, out string reason);
                _pmInterLock.SetPMPreProcessRunning(false, out reason);
                _pmInterLock.SetPMPostProcessRunning(false, out reason);
            }

            return true;
        }

        private bool FsmReset(object[] param)
        {
            var alarms = EV.GetAlarmEvent();
            int alarmCount = alarms != null ? alarms.FindAll(a => a.Level == EventLevel.Alarm && a.Source == Module).Count : 0;
            if (alarmCount > 0)
            {
                EV.ClearAlarmEvent();
            }

            if (!_isInitFlag)
            {
                PostMsg(MSG.ToInit);
                return false;
            }
            return true;
        }

        private bool FsmStartHome(object[] param)
        {
            _isInitFlag = false;
            return true;
        }

        private bool FsmExitHome(object[] param)
        {
            return true;
        }

        private bool FsmEnterHome(object[] param)
        {
            return true;
        }

        private bool FsmMonitorHomeTask(object[] param)
        {
            Result ret = MonitorRoutine();
            if (ret == Result.FAIL)
            {
                PostMsg(MSG.Error1);
                return false;
            }

            if (ret == Result.DONE)
            {
                _isInitFlag = true;
                return true;
            }

            return false;
        }

        private bool FsmMonitorSafetyTask(object[] param)
        {
            Result ret = MonitorRoutine();
            if (ret == Result.FAIL)
            {
                PostMsg(MSG.Error1);
                return false;
            }

            if (ret == Result.DONE)
            {
                return true;
            }

            return false;
        }

        private bool FsmMonitorTask(object[] param)
        {
            Result ret = MonitorRoutine();
            if (ret == Result.FAIL)
            {
                PostMsg(MSG.Error1);
                return false;
            }

            if (ret == Result.RUN && FsmState == (int)STATE.PreProcess)
            {
                if (!_pmInterLock.DoPreprocessRunning)
                {
                    PostMsg(MSG.Abort);
                    EV.PostWarningLog(Module, "For abnormal PreProcess exit, please check the interlocking conditions.工艺异常退出，请检查互锁条件");
                    return false;
                }
            }

            if (ret == Result.RUN && FsmState == (int)STATE.Process)
            {
                if (!_pmInterLock.DoProcessRunning)
                {
                    PostMsg(MSG.Abort);
                    EV.PostWarningLog(Module, "For abnormal Process exit, please check the interlocking conditions.工艺异常退出，请检查互锁条件");
                    return false;
                }
            }

            if (ret == Result.RUN && FsmState == (int)STATE.PostProcess)
            {
                if (!_pmInterLock.DoPostProcessRunning)
                {
                    PostMsg(MSG.Abort);
                    EV.PostWarningLog(Module, "For abnormal PostProcess exit, please check the interlocking conditions.工艺异常退出，请检查互锁条件");
                    return false;
                }
            }

            if (ret == Result.DONE && FsmState == (int)STATE.PreProcess)
            {
                PostMsg(MSG.Process);
                return true;
            }

            if (ret == Result.DONE && FsmState == (int)STATE.Process)
            {
                PostMsg(MSG.PostProcess);
                return true;
            }

            return ret == Result.DONE;
        }

        public override bool Home(out string reason)
        {
            CheckToPostMessage((int)MSG.Home);
            reason = string.Empty;
            return true;
        }

        public override bool TransferHandoff(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType, out string reason)
        {
            reason = string.Empty;
            return true;
        }

        public override bool PostTransfer(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType, out string reason)
        {
            reason = string.Empty;
            return true;
        }

        public override bool CheckReadyForTransfer(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType,
            out string reason)
        {

            reason = string.Empty;
            return true;
        }

        public override void NoteTransferStart(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType)
        {

        }

        public override void NoteTransferStop(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType)
        {

        }

        private bool ClearMfcRorData()
        {
            _mfcRorRoutine.ClearMfcRorData();
            return true;
        }

        public override bool CheckLidClosed()
        {
            throw new System.NotImplementedException();
        }

        public void InvokeOffline()
        {
            PutOffline();
        }

        public void InvokeOnline()
        {
            PutOnline();
        }

        private CancellationTokenSource NotifyModuleOfflineCancellation = new CancellationTokenSource();
        private Task NotifyModuleOfflineTask(int delayTime)
        {
            var t1 = Task.Run(async () =>
            {
                await Task.Delay(delayTime, NotifyModuleOfflineCancellation.Token).ContinueWith(x => EV.PostWarningLog(Module, $"{Module} is still in offline"), NotifyModuleOfflineCancellation.Token);
            });
            return t1;
        }
    }
}
