using Aitex.Core.Common;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Key;
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.Sorter.Common;
using Kxware.Common;
using MECF.Framework.Common.DBCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Gem;
using MECF.Framework.Common.Jobs;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using OpenSEMI.Ctrlib.Controls;
using SicRT.Equipments.Schedulers;
using SicRT.Modules.Schedulers;
using SicRT.Scheduler;
using System;
using System.Collections.Generic;
using System.Linq;


namespace SicRT.Modules
{
    public partial class AutoTransfer : SchedulerModuleFactory
    {
        private List<ControlJobInfo> _controlJobList = new();
        private List<ProcessJobInfo> _processJobList = new();

        private int _maxTrayCount = 4;                      //可以同时运行的石墨盘总数

        private const string LogSource = "Scheduler";
        private SchedulerDBCallback _dbCallback = new();

        private bool _isCycleMode;
        private bool _isATMMode;
        private int _cycleSetPoint = 0;
        private int _cycledCount = 0;
        private int _cycledWafer = 0;
        private string _curRecipeName = "";
        private string _curSequenceName = "";

        private bool _isModuleErrorPrevious;
        private bool[] _isPMErrorPrevious = new bool[2];

        private double _timeBuffer1 { get; set; }
        private double _timeBuffer2 { get; set; }
        private double _timeBuffer3 { get; set; }
        private double _timeLoad { get; set; }

        private const int _bufferFloors = 1;

        private Dictionary<string, DateTime> _loadWaferInfo = new();

        private Dictionary<string, DateTime> _bufferWaferInfo = new();

        private Queue<Action> tmRobotActions = new() { };

        private R_TRIG _updateAutoJobLocation = new(); //需要向数据库更新Wafer位置

        public AutoTransfer()
        {
            DATA.Subscribe("Scheduler.IsCycleMode", () => _isCycleMode);
            DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount);
            DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint);
            DATA.Subscribe("Scheduler.RecipeName", () => _curRecipeName);
            DATA.Subscribe("Scheduler.SequenceName", () => _curSequenceName);

            DATA.Subscribe("Scheduler.TimeBuffer1", () => _timeBuffer1);
            DATA.Subscribe("Scheduler.TimeBuffer2", () => _timeBuffer2);
            DATA.Subscribe("Scheduler.TimeBuffer3", () => _timeBuffer3);

            DATA.Subscribe("Scheduler.TimeLoad", () => _timeLoad);

            DATA.Subscribe("LoadLock.LocalJobName", () =>
            {
                var jb = _controlJobList.Find(x => x.Module == "LoadLock");
                if (jb != null)
                    return jb.Name;
                return "";
            });

            DATA.Subscribe("LoadLock.LocalJobStatus", () =>
            {
                var jb = _controlJobList.Find(x => x.Module == "LoadLock");
                if (jb != null)
                    return jb.State.ToString();
                return "";
            });

            OP.Subscribe($"{ModuleName.TM}.ResetTask", (string cmd, object[] args) =>
            {
                _tmRobot.ResetTask();
                return true;
            });

            OP.Subscribe($"{ModuleName.EFEM}.ResetTask", (string cmd, object[] args) =>
            {
                _waferRobot.ResetTask();
                _trayRobot.ResetTask();
                return true;
            });

            OP.Subscribe($"{ModuleName.WaferRobot}.ResetTask", (string cmd, object[] args) =>
            {
                _waferRobot.ResetTask();
                return true;
            });

            OP.Subscribe($"{ModuleName.TrayRobot}.ResetTask", (string cmd, object[] args) =>
            {
                _tmRobot.ResetTask();
                return true;
            });

            tmRobotActions.Enqueue(MonitorTmRobotLoadPlaceTask);
            tmRobotActions.Enqueue(MonitorTmRobotLoadPickTask);
            tmRobotActions.Enqueue(MonitorTmRobotPMPlaceTask);
            tmRobotActions.Enqueue(MonitorTmRobotPMPickTask);
            tmRobotActions.Enqueue(MonitorTmRobotBufferPlaceTask);
            tmRobotActions.Enqueue(MonitorTmRobotBufferPickTask);
        }

        public bool HasJobRunning
        {
            get { return _controlJobList.Count > 0; }
        }


        public void Clear()
        {
            _tmRobot.ResetTask();

            foreach (var pm in _lstPms)
            {
                pm.ResetTask();
            }

            _load.ResetTask();
            _buffer.ResetTask();

            _controlJobList.Clear();
            _processJobList.Clear();
            _loadWaferInfo.Clear();
        }

        public void ResetTask()
        {
            if (!_load.IsOnline)
            {
                _load.ResetTask();
            }

            if (!_buffer.IsOnline)
            {
                _buffer.ResetTask();
            }

            if (!_tmRobot.IsOnline)
            {
                _tmRobot.ResetTask();
            }

            foreach (var pm in _lstPms)
            {
                if (!pm.IsOnline)
                {
                    pm.ResetTask();
                }
            }
        }

        #region Job Management

        public bool CreateJob(Dictionary<string, object> param)
        {
            var reason = "";
            var slotSequence = (string[])param["SlotSequence"];
            var jobId = (string)param["JobId"];
            var module = (string)param["Module"];
            var lotId = (string)param["LotId"];

            ////检查Load腔Lock是否锁定
            //if(!_load.CheckLocked())
            //{
            //    EV.PostWarningLog(LogSource, $"The Load is Unlocked,do not start");
            //    return false;
            //}

            //检查所有Module里Tray的数量
            if(GetCurrentTrayCount() >= _maxTrayCount)
            {
                EV.PostWarningLog(LogSource, $"The machine has more than {_maxTrayCount} Tray");
                return false;
            }

            if (slotSequence.Length != 1)
            {
                reason = $"slot sequence parameter not valid, length is {slotSequence.Length}, should be 1";
                EV.PostWarningLog(LogSource, reason);
                return false;
            }

            //拿到Recipe和ModuleName
            var recipeName = "";
            var pmModule = ModuleName.System;
            var seq = SequenceInfoHelper.GetInfo(slotSequence[0]);
            for (var i = 0; i < seq.Steps.Count; i++)
            {
                var stepInfo = seq.Steps[i];
                foreach (var m in stepInfo.StepModules)
                {
                    if (ModuleHelper.IsPm(m))
                    {
                        recipeName = seq.Steps[i].RecipeName;
                        pmModule = m;
                    }
                }
            }

            //每个PM腔不能超过2个对应Wafer
            if(pmModule != ModuleName.System)
            {
                if (GetRunWaferCount(pmModule) >= _maxTrayCount/2)
                {
                    EV.PostWarningLog(LogSource, $"Creating the job failed . There are already {_maxTrayCount / 2} job of the same pm in the system.");
                    return false;
                }
            }

            if (CheckModuleHaveWaferWithNoJob(out reason))
            {
                EV.PostWarningLog(LogSource, $"{reason}");
                return false;
            }

            if (!ValidateSequence(slotSequence, out reason))
            {
                EV.PostWarningLog(LogSource, $"{reason}");
                return false;
            }

            if (string.IsNullOrEmpty(jobId))
            {
                jobId = "CJ_Local_Load_" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            }

            if (!string.IsNullOrEmpty(lotId))
            {
                if (_controlJobList.Exists(x => x.LotName == lotId))
                {
                    reason = $"LotID : {lotId} already created";
                    EV.PostWarningLog(LogSource, reason);
                    return false;
                }
            }

            var cj = new ControlJobInfo();
            cj.Name = jobId;
            cj.Module = module;
            cj.LotName = lotId;
            cj.LotInnerId = Guid.NewGuid();
            cj.LotWafers = new List<WaferInfoRt>();
            cj.SetState(EnumControlJobState.WaitingForStart);

            List<string> sequenceNameList = new List<string>();

            string WaferAssociationInfo = $"WaferAssociationInfo({module}):";
            for (int i = 0; i < 1; i++)
            {
                //检查是否设置Sequence
                string sequenceName = slotSequence[i];
                if (string.IsNullOrEmpty(sequenceName))
                {
                    reason = $"sequence name is empty";
                    EV.PostWarningLog(LogSource, reason);
                    return false;
                }

                //检查是否有Normal Wafer
                if (!WaferManager.Instance.CheckWafer(ModuleHelper.Converter(module), i, WaferStatus.Normal))
                {
                    reason = $"{module} has no normal wafer";
                    EV.PostWarningLog(LogSource, reason);
                    return false;
                }

                WaferInfoRt wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(module), i);

                if (wafer.ProcessState != WaferProcessStatus.Idle)
                {
                    reason = $"specifies wafer: {module} slot {i + 1} process state is not idle";
                    EV.PostWarningLog(LogSource, reason);
                    return false;
                }

                if (wafer.ProcessJob != null)
                {
                    reason = $"{module} wafer has processJob";
                    EV.PostWarningLog(LogSource, reason);
                    return false;
                }

                WaferAssociationInfo = WaferAssociationInfo + string.Format(" slot{0} -- {1};", i + 1, slotSequence[i]);

                wafer.NextSequenceStep = 0;
                wafer.PPID = sequenceName;
                wafer.LotId = lotId;
                cj.LotWafers.Add(wafer);

                _isATMMode = SC.GetValue<bool>("System.IsATMMode");
                _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");

                //没有包含sequenceName,需新建
                if (!sequenceNameList.Exists(s => s == sequenceName))
                {
                    sequenceNameList.Add(sequenceName);

                    ProcessJobInfo pj = new ProcessJobInfo();
                    pj.Name = jobId + "_" + (i + 1);
                    pj.ControlJobName = cj.Name;
                    pj.Sequence = SequenceInfoHelper.GetInfo(sequenceName);
                    pj.SetState(EnumProcessJobState.Queued);
                    pj.SlotWafers = [Tuple.Create(ModuleHelper.Converter(module), i)];

                    //不是CycleMode模式，则CycleCount设为1
                    pj.CycleCount = _isATMMode && _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 1;
                    pj.CycleTime = 0;

                    //检查Sequence对应的PM腔状态
                    if (!CheckPMState(sequenceName))
                    {
                        return false;
                    }

                    wafer.ProcessJob = pj;
                    _processJobList.Add(pj);
                    cj.ProcessJobNameList.Add(pj.Name);
                }
                //已包含sequenceName
                else
                {
                    ProcessJobInfo pj = _processJobList.Find(p => p.Sequence.Name == sequenceName);
                    wafer.ProcessJob = pj;

                    pj.SlotWafers.Add(Tuple.Create(ModuleHelper.Converter(module), i));
                }
            }

            _controlJobList.Add(cj);

            int totalWafer = 0;
            foreach (string pjName in cj.ProcessJobNameList)
            {
                ProcessJobInfo tempPJ = _processJobList.First(p => p.Name == pjName);
                foreach (var pjSlotWafer in tempPJ.SlotWafers)
                {
                    var wafer = WaferManager.Instance.GetWafer(pjSlotWafer.Item1, pjSlotWafer.Item2);
                    WaferDataRecorder.SetCjInfo(wafer.WaferInnerID.ToString(), cj.InnerId.ToString());
                    WaferDataRecorder.SetWaferSequence(wafer.WaferInnerID.ToString(), tempPJ.Sequence.Name);
                    WaferDataRecorder.SetWaferLotId(wafer.WaferInnerID.ToString(), jobId);
                    WaferManager.Instance.UpdateWaferLotId(pjSlotWafer.Item1, pjSlotWafer.Item2, jobId);

                    totalWafer++;
                }
            }

            CarrierManager.Instance.DeleteCarrier(cj.Module);
            CarrierManager.Instance.CreateCarrier(cj.Module);
            CarrierManager.Instance.UpdateCarrierId(cj.Module, $"{cj.Module} {DateTime.Now}");
            //此carrier为null
            CarrierInfo carrier = CarrierManager.Instance.GetCarrier(cj.Module);
            JobDataRecorder.StartCJ(cj.InnerId.ToString(), "", cj.Name, cj.Module, cj.Module, totalWafer);

            EV.PostInfoLog(LogSource, WaferAssociationInfo);


            //保存信息
            var waferInfo = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0);
            if (waferInfo != null)
            {
                waferInfo.LotId = cj.LotName;
                if (recipeName.IndexOf(@"\") > 0)
                {
                    recipeName = recipeName.Substring(recipeName.LastIndexOf(@"\") + 1);
                }
               
                AutoJobRecorder.Add(waferInfo.WaferID.ToString(), recipeName, cj.LotName, ModuleName.LoadLock.ToString(), GetWaferStatue(waferInfo), cj.Name);
            }
            return true;
        }

        public void StartJob(string jobName)
        {
            _maxTrayCount = _lstPms.Count * 2;

            var cj = _controlJobList.Find(x => x.Name == jobName);
            if (cj == null)
            {
                EV.PostWarningLog(LogSource, $"start job rejected, not found job with id {jobName}");
                return;
            }

            if (cj.State == EnumControlJobState.WaitingForStart)
            {
                cj.BeginTime = DateTime.Now;
                cj.LotInnerId = Guid.NewGuid();
                //_dbCallback.LotCreated(cj);

                foreach (var pjName in cj.ProcessJobNameList)
                {
                    var pj = _processJobList.Find(x => x.Name == pjName);
                    if (pj == null)
                    {
                        LOG.Error($"Not find pj named {pjName} in {cj.Name}");
                        continue;
                    }

                    if (pj.State == EnumProcessJobState.Queued)
                    {
                        ActiveProcessJob(pj);
                    }
                }

                cj.SetState(EnumControlJobState.Executing);

                string squenceID = cj.LotWafers != null ? cj.LotWafers[0].PPID : string.Empty;
                //补全路径
                squenceID = $"Sequence\\{squenceID}.seq";
                GemManager.Instance.Equipment?.TriggerEvent("JobStart", new string[] { "LotID", "SequenceID" }, new object[] { cj.LotName, squenceID });
            }
        }

        private string GetWaferStatue(WaferInfoRt wafer)
        {
            if (wafer.ProcessState == WaferProcessStatus.InProcess)
            {
                return "InProcess";
            }
            else if (wafer.ProcessState == WaferProcessStatus.Completed)
            {
                return "Completed";
            }
            else if (wafer.ProcessState == WaferProcessStatus.Abort)
            {
                return "Aborted";
            }
            else
            {
                return "Idle";
            }
        }

        private bool ValidateSequence(string[] seqs, out string reason)
        {
            reason = string.Empty;
            //bool isAllSequenceNull = true;
            //for (int i = 0; i < seqs.Length; i++)
            //{
            //    if (string.IsNullOrEmpty(seqs[i]))
            //        continue;
            //    var sequence = SequenceInfoHelper.GetInfo(seqs[i]);
            //    if ((sequence == null || sequence.Steps == null || sequence.Steps.Count == 0) && !string.IsNullOrEmpty(sequence.Name))
            //    {
            //        reason = $"Invalid sequence {seqs[i]}";
            //        return false;
            //    }

            //    isAllSequenceNull = false;

            //    if (sequence.Steps != null)
            //    {
            //        int currentIndex = 0;
            //        if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Aligner)
            //        {
            //            reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Aligner";
            //            return false;
            //        }
            //        else
            //        {
            //            if (sequence.Steps[currentIndex].AlignAngle < 0 || sequence.Steps[currentIndex].AlignAngle > 360)
            //            {
            //                reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Aligner angle parameter is not valid";
            //                return false;
            //            }
            //        }

            //        currentIndex++;
            //        if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Load)
            //        {
            //            reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Load";
            //            return false;
            //        }

            //        currentIndex++;
            //        if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Buffer)
            //        {
            //            reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Buffer";
            //            return false;
            //        }
            //        else
            //        {
            //            //if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("SlotSelection")
            //            //    || string.IsNullOrEmpty(sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString())
            //            //    || sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString().Contains("3"))
            //            //{
            //            //    reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer SlotSelection parameter is not valid";
            //            //    return false;
            //            //}

            //            if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("BufferType") || !sequence.Steps[currentIndex].StepParameter["BufferType"].ToString().Contains("Heat"))
            //            {
            //                reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer BufferType parameter is not valid";
            //                return false;
            //            }
            //        }


            //        currentIndex++;
            //        if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules.Any(pm => !ModuleHelper.IsPm(pm)))
            //        {
            //            reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be PM";
            //            return false;
            //        }

            //        //if (sequence.Steps.Count == 7)
            //        //{
            //        //    currentIndex++;
            //        //    if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Buffer)
            //        //    {
            //        //        reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Buffer";
            //        //        return false;
            //        //    }
            //        //    else
            //        //    {
            //        //        if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("SlotSelection")
            //        //            || sequence.Steps[currentIndex].StepParameter["SlotSelection"].ToString() != "3")
            //        //        {
            //        //            reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer SlotSelection parameter is not valid";
            //        //            return false;
            //        //        }

            //        //        if (!sequence.Steps[currentIndex].StepParameter.ContainsKey("BufferType") || !sequence.Steps[currentIndex].StepParameter["BufferType"].ToString().Contains("Cooling"))
            //        //        {
            //        //            reason = $"Invalid sequence {seqs[i]},{currentIndex + 1}st step Buffer BufferType parameter is not valid";
            //        //            return false;
            //        //        }
            //        //    }

            //        //}

            //        currentIndex++;
            //        if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.UnLoad)
            //        {
            //            reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Unload";
            //            return false;
            //        }

            //        currentIndex++;
            //        if (sequence.Steps[currentIndex] == null || sequence.Steps[currentIndex].StepModules.Count <= 0 || sequence.Steps[currentIndex].StepModules[0] != ModuleName.Aligner)
            //        {
            //            reason = $"Invalid sequence {seqs[i]}, {currentIndex + 1}st step should be Aligner";
            //            return false;
            //        }
            //        else
            //        {
            //            if (sequence.Steps[0].AlignAngle < 0 || sequence.Steps[0].AlignAngle > 360)
            //            {
            //                reason = $"Invalid sequence {seqs[i]}, Aligner angle parameter is not valid";
            //                return false;
            //            }
            //        }
            //    }
            //}

            //if (isAllSequenceNull)
            //{
            //    reason = $"Invalid sequence, sequence are all null ";
            //    return false;
            //}
            return true;
        }

        internal void StopJob(string jobName)
        {
            //ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
            //if (cj == null)
            //{
            //    EV.PostWarningLog(LogSource, $"stop job rejected, not found job with id {jobName}");
            //    return;
            //}
            foreach (var cj in _controlJobList)
            {
                foreach (var pj in _processJobList)
                {
                    if (pj.ControlJobName == cj.Name)
                    {
                        pj.SetState(EnumProcessJobState.Stopping);
                    }
                }

                if (_cycleSetPoint > 0)
                {
                    _cycleSetPoint = _cycledCount;
                }
            }
        }

        public void Abort()
        {
            try
            {
                var wafer = WaferManager.Instance.GetWafer(ModuleName.PM1, 0);
                if (wafer != null && !string.IsNullOrEmpty(wafer.WaferID))
                {
                    AutoJobRecorder.UpdatePosition(wafer.WaferID.ToString(), ModuleName.PM1.ToString(), "Aborted");
                }

                var wafer1 = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0);
                if (wafer1 != null && !string.IsNullOrEmpty(wafer1.WaferID))
                {
                    AutoJobRecorder.UpdatePosition(wafer1.WaferID.ToString(), ModuleName.TM.ToString(), "Aborted");
                }

                var wafer2 = WaferManager.Instance.GetWafer(ModuleName.Buffer, 0);
                if (wafer2 != null && !string.IsNullOrEmpty(wafer2.WaferID))
                {
                    AutoJobRecorder.UpdatePosition(wafer2.WaferID.ToString(), ModuleName.Buffer.ToString(), "Aborted");
                }

                var wafer3 = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0);
                if (wafer3 != null && !string.IsNullOrEmpty(wafer3.WaferID))
                {
                    AutoJobRecorder.UpdatePosition(wafer3.WaferID.ToString(), ModuleName.LoadLock.ToString(), "Aborted");
                }

                var cjList = _controlJobList.FindAll(c => c.State == EnumControlJobState.Executing);
                if (cjList != null)
                {
                    foreach (var cj in cjList)
                    {
                        string squenceID = cj.LotWafers != null ? cj.LotWafers[0].PPID : string.Empty;
                        //补全路径
                        squenceID = $"Sequence\\{squenceID}.seq";
                        GemManager.Instance.Equipment?.TriggerEvent("JobAbort", new string[] { "LotID", "SequenceID" }, new object[] { cj.LotName, squenceID });
                    }
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message, ex);
            }
        }

        internal void AbortJob(string jobName)
        {
            var cj = _controlJobList.Find(x => x.Name == jobName);
            if (cj == null)
            {
                EV.PostWarningLog(LogSource, $"abort job rejected, not found job with id {jobName}");
                return;
            }

            var unprocessed_cj = 0;
            var aborted_cj = 0;

            var pjAbortList = new List<ProcessJobInfo>();
            foreach (var pj in _processJobList)
            {
                if (pj.ControlJobName == cj.Name)
                {
                    pj.SetState(EnumProcessJobState.Aborting);
                    pjAbortList.Add(pj);

                    var unprocessed = 0;
                    var aborted = 0;
                    var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
                    foreach (var waferInfo in wafers)
                    {
                        waferInfo.ProcessJob = null;
                        waferInfo.NextSequenceStep = 0;
                        if (waferInfo.ProcessState != WaferProcessStatus.Completed)
                        {
                            unprocessed++;
                            unprocessed_cj++;
                        }
                    }
                    JobDataRecorder.EndPJ(pj.InnerId.ToString(), aborted, unprocessed);
                }
            }

            foreach (var pj in pjAbortList)
            {
                _processJobList.Remove(pj);
            }

            _controlJobList.Remove(cj);

            _dbCallback.LotFinished(cj);
            JobDataRecorder.EndCJ(cj.InnerId.ToString(), aborted_cj, unprocessed_cj);
        }

        public void AbortSingleJob(string jobName, string waferID)
        {
            var cj = _controlJobList.Find(x => x.Name.ToString() == jobName);
            if (cj == null)
            {
                EV.PostWarningLog(LogSource, $"abort job rejected, not found job with id {jobName}");
                return;
            }

            var pjAbortList = new List<ProcessJobInfo>();
            foreach (var pj in _processJobList)
            {
                if (pj.ControlJobName == cj.Name)
                {
                    var wafers = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
                    foreach (var waferInfo in wafers)
                    {
                        SkipWaferProcessStep(waferInfo);
                        waferInfo.WaferStatus = WaferStatus.Aborted;
                        waferInfo.ProcessState = WaferProcessStatus.Abort;

                        AutoJobRecorder.UpdateStatus(waferInfo.WaferID.ToString(),"Aborted");
                    }
                }
            }
        }

        public void ResumeJob(string jobName)
        {
            //ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
            //if (cj == null)
            //{
            //    EV.PostWarningLog(LogSource, $"resume job rejected, not found job with id {jobName}");
            //    return;
            //}

            foreach (var cj in _controlJobList)
            {
                if (cj.State == EnumControlJobState.Paused)
                {
                    cj.SetState(EnumControlJobState.Executing);
                }
            }
        }

        internal void PauseJob(string jobName)
        {
            //ControlJobInfo cj = _lstControlJobs.Find(x => x.Name == jobName);
            //if (cj == null)
            //{
            //    EV.PostWarningLog(LogSource, $"pause job rejected, not found job with id {jobName}");
            //    return;
            //}

            foreach (var cj in _controlJobList)
            {
                if (cj.State == EnumControlJobState.Executing)
                {
                    cj.SetState(EnumControlJobState.Paused);
                }
            }
        }

        internal bool CheckPMState(string sequence)
        {
            var seqInfo = SequenceInfoHelper.GetInfo(sequence);

            if (seqInfo.Name != "")
            {
                foreach (var step in seqInfo.Steps)
                {
                    foreach (var moduleName in step.StepModules)
                    {
                        if (ModuleHelper.IsPm(moduleName))
                        {
                            var module = _lstPms.Find(x => x.Module == moduleName);

                            if (module != null)
                            {
                                if (module.IsError)
                                {
                                    EV.PostWarningLog("Scheduler", $"{moduleName} is not be error");
                                    return false;
                                }

                                if (!module.IsOnline)
                                {
                                    EV.PostWarningLog("Scheduler", $"{moduleName} is not be  Online");
                                    return false;
                                }

                                if (!module.IsLineHeaterEnable)
                                {
                                    EV.PostWarningLog("Scheduler", $"{moduleName} LineHeater is not be  Open");
                                    return false;
                                }
                                //if (module.IsService)
                                //{
                                //    EV.PostWarningLog("Scheduler", $"can not start job, {moduleName} is Service Mode");
                                //    return false;
                                //}
                            }
                            else
                            {
                                EV.PostWarningLog("Scheduler", "Sequence PM can not be null!");
                                return false;
                            }
                        }
                    }
                }
            }
            else
            {
                EV.PostWarningLog("Scheduler", "Sequence can not be null!");
                return false;
            }

            return true;
        }
        #endregion

        /// <summary>
        /// Start Auto Transfer
        /// </summary>
        /// <param name="objs"></param>
        /// <returns></returns>
        public Result CheckAutoMode(params object[] objs)
        {
            if (!_tmRobot.IsOnline || _tmRobot.IsError)
            {
                EV.PostWarningLog("Scheduler", "can not change to auto mode, TM robot should be online and no error");
                return Result.FAIL;
            }

            return Result.RUN;
        }

        public Result Monitor()
        {
            MonitorModuleTasks();

            MonitorAutoJobStatus();

            MonitorModuleError();

            MonitorJobTasks();

            return Result.RUN;
        }

        #region Job task
        public Result MonitorJobTasks()
        {
            UpdateProcessJobStatus();

            UpdateControlJobStatus();

            return Result.RUN;
        }

        /// <summary>
        /// 检查PJ中的Wafer信息是否被清空。
        /// <para>如果被清空，则说明中间过程中Wafer被人工删除，此时返回true，通知相关Monitor可以改PJ。</para>
        /// </summary>
        /// <param name="pj"></param>
        /// <returns></returns>
        protected bool CheckAllWaferDeleted(ProcessJobInfo pj)
        {
            var wi = WaferManager.Instance.GetWaferByProcessJob(pj.Name);
            return wi == null || wi.Length <= 0;
        }

        protected bool CheckAllWaferReturned(ProcessJobInfo pj, bool checkAllProcessed)
        {
            for (var i = 0; i < pj.SlotWafers.Count; ++i)
            {
                WaferInfoRt wafer = WaferManager.Instance.GetWafer(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2);
                if (wafer.IsWaferEmpty)
                    return false;
                if (checkAllProcessed && CheckWaferNeedProcess(pj.SlotWafers[i].Item1, pj.SlotWafers[i].Item2))
                    return false;
                if (wafer.ProcessJob == null || wafer.ProcessJob.InnerId != pj.InnerId)
                {
                    return false;
                }
            }

            return true;
        }

        protected bool CheckAllDummyWaferReturned()
        {
            foreach (var schedulerPm in _lstPms)
            {
                if (WaferManager.Instance.CheckWaferIsDummy(schedulerPm.Module, 0))
                    return false;
            }

            if (WaferManager.Instance.CheckWaferIsDummy(_tmRobot.Module, 0))
                return false;

            if (WaferManager.Instance.CheckWaferIsDummy(_tmRobot.Module, 1))
                return false;

            return true;
        }

        protected bool CheckAllPmCleaned(ProcessJobInfo pj)
        {
            foreach (var schedulerPm in _lstPms)
            {
                if (GetModule(schedulerPm.Module).CheckNeedRunClean(out _, out _))
                {
                    foreach (var sequenceStepInfo in pj.Sequence.Steps)
                    {
                        if (sequenceStepInfo.StepModules.Contains(schedulerPm.Module))
                            return false;
                    }
                }
            }


            return true;
        }
        
        private void UpdateProcessJobStatus()
        {
            foreach (var pj in _processJobList)
            {
                if (pj.State == EnumProcessJobState.Processing)
                {
                    if (CheckAllWaferReturned(pj, true))
                    {
                        if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0))
                        {
                            pj.CycleTime++;

                            if (pj.CycleTime < pj.CycleCount)
                            {
                                //重新设置wafer
                                for (int i = 0; i < pj.SlotWafers.Count; ++i)
                                {
                                    var wafer = GetModule(pj.SlotWafers[i].Item1).GetWaferInfo(pj.SlotWafers[i].Item2);

                                    wafer.NextSequenceStep = 0;
                                    wafer.WaferStatus = WaferStatus.Normal;
                                    wafer.ProcessState = WaferProcessStatus.Idle;
                                }
                            }
                            else
                            {
                                _load.SetJobStatue();
                                pj.SetState(EnumProcessJobState.ProcessingComplete);
                                JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
                                AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString());
                            }
                        }
                    }

                    if (CheckAllWaferDeleted(pj))
                    {
                        _load.SetJobStatue();
                        pj.SetState(EnumProcessJobState.Complete);
                        JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
                        AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString());
                    }
                }
                else if (pj.State == EnumProcessJobState.Stopping)
                {
                    if (CheckAllWaferReturned(pj, false))
                    {
                        if (CheckWaferSequenceStepDone(ModuleName.LoadLock, 0))
                        {
                            _load.SetJobStatue();
                            pj.SetState(EnumProcessJobState.Complete);
                            JobDataRecorder.EndPJ(pj.InnerId.ToString(), 0, 0);
                            AutoJobRecorder.EndJob(WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0).WaferID.ToString());
                        }
                    }
                }
            }
        }

        private void UpdateControlJobStatus()
        {
            try
            {
                if (_controlJobList.Count == 0)
                {
                    return;
                }

                foreach (var cj in _controlJobList)
                {
                    if (cj.State == EnumControlJobState.Executing)
                    {
                        bool allPjCompleted = true;
                        foreach (var pjName in cj.ProcessJobNameList)
                        {
                            var pj = _processJobList.Find(x => x.Name == pjName);
                            if (pj != null)
                            {
                                if (pj.State != EnumProcessJobState.ProcessingComplete && pj.State != EnumProcessJobState.Complete)
                                {
                                    allPjCompleted = false;
                                    break;
                                }
                            }
                        }

                        if (allPjCompleted)
                        {
                            foreach (var pjName in cj.ProcessJobNameList)
                            {
                                var pj = _processJobList.Find(x => x.Name == pjName);
                                if (pj != null)
                                {
                                    _processJobList.Remove(pj);
                                }
                            }

                            var wafer = cj.LotWafers[0];
                            if(wafer != null)
                            {
                                if(wafer.WaferStatus == WaferStatus.Aborted)
                                {
                                    cj.SetState(EnumControlJobState.Aborted);
                                }
                                else
                                {
                                    cj.SetState(EnumControlJobState.Completed);
                                }

                                AutoJobRecorder.UpdatePosition(wafer.WaferID.ToString(), ModuleName.LoadLock.ToString(), cj.State.ToString());

                                JobDataRecorder.EndCJ(cj.InnerId.ToString(), 0, 0);
                                _dbCallback.LotFinished(cj);
                            }
                        }
                    }
                }

                for (int i = 0; i < _controlJobList.Count; i++)
                {
                    if (_controlJobList[i].State == EnumControlJobState.Completed || _controlJobList[i].State == EnumControlJobState.Aborted)
                    {
                        _controlJobList.RemoveAt(i);
                    }
                }

            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message,ex);
            }
        }

        public void MonitorAutoJobStatus()
        {
            try
            {
                _updateAutoJobLocation.CLK = _tmRobot.IsAvailable;
                if (_updateAutoJobLocation.Q)
                {
                    WaferInfoRt wafer = WaferManager.Instance.GetWafer(ModuleName.PM1, 0);
                    if (wafer != null && !string.IsNullOrEmpty(wafer.WaferID))
                    {
                        AutoJobRecorder.UpdateWaferPosition(wafer.WaferID.ToString(), ModuleName.PM1.ToString());
                    }

                    WaferInfoRt wafer1 = WaferManager.Instance.GetWafer(ModuleName.TMRobot, 0);
                    if (wafer1 != null && !string.IsNullOrEmpty(wafer1.WaferID))
                    {
                        AutoJobRecorder.UpdateWaferPosition(wafer1.WaferID.ToString(), ModuleName.TM.ToString());
                    }

                    WaferInfoRt wafer2 = WaferManager.Instance.GetWafer(ModuleName.Buffer, 0);
                    if (wafer2 != null && !string.IsNullOrEmpty(wafer2.WaferID))
                    {
                        AutoJobRecorder.UpdateWaferPosition(wafer2.WaferID.ToString(), ModuleName.Buffer.ToString());
                    }

                    WaferInfoRt wafer3 = WaferManager.Instance.GetWafer(ModuleName.LoadLock, 0);
                    if (wafer3 != null && !string.IsNullOrEmpty(wafer3.WaferID))
                    {
                        AutoJobRecorder.UpdateWaferPosition(wafer3.WaferID.ToString(), ModuleName.LoadLock.ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message, ex);
            }
        }

        public bool CheckAllJobDone()
        {
            //条件满足状态由AutoRunning切换到AutoIdle状态
            if (_load.IsAvailable && _tmRobot.IsAvailable && _tmRobot.NoWafer(0) && _tmRobot.NoTray(0) &&
                _buffer.NoWafer(0) && _buffer.NoTray(0) && 
                _pm1.NoWafer(0) && _pm1.NoTray(0) && _pm2.NoWafer(0) && _pm2.NoTray(0) && !_controlJobList.Exists(c => c.State == EnumControlJobState.Executing))
            {
                return true;
            }

            return false;
        }

        private bool ActiveProcessJob(ProcessJobInfo pj)
        {
            foreach (var pjSlotWafer in pj.SlotWafers)
            {
                WaferInfoRt wafer = GetModule(pjSlotWafer.Item1).GetWaferInfo(pjSlotWafer.Item2);
                wafer.ProcessJob = pj;
                wafer.NextSequenceStep = 0;

                WaferDataRecorder.SetPjInfo(wafer.WaferInnerID.ToString(), pj.InnerId.ToString());
            }

            var cj = _controlJobList.Find(x => x.Name == pj.ControlJobName);

            var carrier = CarrierManager.Instance.GetCarrier(cj.Module);
            JobDataRecorder.StartPJ(pj.InnerId.ToString(), null, cj.InnerId.ToString(), pj.Name, cj.Module, cj.Module, pj.SlotWafers.Count);
            pj.SetState(EnumProcessJobState.Processing);

            return true;
        }
        #endregion

        #region Module task

        public Result MonitorModuleTasks()
        {
            MonitorPMTask();
            MonitorBufferTask();

            MonitorTmRobotTask();
            MonitorLoadTask();

            return Result.RUN;
        }

        private void MonitorBufferTask()
        {
            if (!_buffer.IsAvailable)
            {
                return;
            }

            for (var i = 0; i < _bufferFloors; i++)
            {
                var canExcute = _buffer.HasWafer(i) && _buffer.CheckWaferNextStepIsThis(_buffer.Module, i);
                if (canExcute)
                {
                    WaferInfoRt bufferWafer = _buffer.GetWaferInfo(i);

                    if(i == 2 || i ==1)
                    {
                        bufferWafer.NextSequenceStep++;
                        continue;
                    }

                    var bufferSetValue = 0;
                    if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "Type", out var strBufferType))
                    {
                        continue;
                    }
                    if (!GetWaferSequenceNextValue(ModuleName.Buffer, i, "SetValue", out var strBufferSetValue))
                    {
                        continue;
                    }
                    if (!Int32.TryParse(strBufferSetValue, out bufferSetValue))
                    {
                        continue;
                    }

                    //分别判断冷却和加热方式温度是否达到
                    if (strBufferType == "HeatByTemp")
                    {
                        if (_bufferWaferInfo.ContainsKey(bufferWafer.WaferInnerID.ToString()))
                        {
                            var dtStartTime = _bufferWaferInfo[bufferWafer.WaferInnerID.ToString()];
                            var pastTime = (DateTime.Now - dtStartTime).TotalSeconds;

                            //选择By温度5秒后再判断温度
                            if (pastTime > 5)
                            {
                                if (_buffer.GetTemperature() >= bufferSetValue)
                                    bufferWafer.NextSequenceStep++;
                                _bufferWaferInfo.Remove(bufferWafer.WaferInnerID.ToString());
                            }
                        }
                        else
                        {
                            _bufferWaferInfo.Add(bufferWafer.WaferInnerID.ToString(), DateTime.Now);
                        }
                    }
                    else if (strBufferType == "HeatByTime")
                    {
                        if (_bufferWaferInfo.ContainsKey(bufferWafer.WaferInnerID.ToString()))
                        {
                            var dtStartTime = _bufferWaferInfo[bufferWafer.WaferInnerID.ToString()];
                            var pastTime = (DateTime.Now - dtStartTime).TotalSeconds;

                            if (i == 0)
                            {
                                _timeBuffer1 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
                            }
                            else if (i == 1)
                            {
                                _timeBuffer2 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
                            }
                           else if (i == 2)
                            {
                                _timeBuffer3 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
                            }

                            if (pastTime > bufferSetValue)
                            {
                                bufferWafer.NextSequenceStep++;
                                _bufferWaferInfo.Remove(bufferWafer.WaferInnerID.ToString());
                            }
                        }
                        else
                        {
                            _bufferWaferInfo.Add(bufferWafer.WaferInnerID.ToString(), DateTime.Now);
                        }
                    }
                    else if (strBufferType == "CoolingByTime")
                    {
                        if (_bufferWaferInfo.ContainsKey(bufferWafer.WaferInnerID.ToString()))
                        {
                            var dtStartTime = _bufferWaferInfo[bufferWafer.WaferInnerID.ToString()];
                            var pastTime = (DateTime.Now - dtStartTime).TotalSeconds;

                            if (i == 0)
                            {
                                _timeBuffer1 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
                            }
                            else if (i == 1)
                            {
                                _timeBuffer2 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
                            }
                            else if (i == 2)
                            {
                                _timeBuffer3 = pastTime > bufferSetValue ? 0 : (bufferSetValue - pastTime);
                            }

                            if (pastTime > bufferSetValue)
                            {
                                bufferWafer.NextSequenceStep++;
                                _bufferWaferInfo.Remove(bufferWafer.WaferInnerID.ToString());
                            }
                        }
                        else
                        {
                            _bufferWaferInfo.Add(bufferWafer.WaferInnerID.ToString(), DateTime.Now);
                        }
                    }

                    //return;
                }
            }

            //Place和Pick条件都一样
            if (!_buffer.IsReadyForPlace(ModuleName.TMRobot, 0))
            {
                _buffer.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
            }
        }

        /// <summary>
        /// 检测到LL中的Wafer已完成Job。
        /// </summary>
        //private readonly R_TRIG _trigLLPjDone = new();

        private void MonitorLoadTask()
        {
            if (!_load.IsAvailable)
            {
                return;
            }

            if (_load.FirstDetectWaferArrive(0) || _load.FirstDetectWaferLeave(0))
            {
                _load.ResetPurged();
                //_trigLLPjDone.RST = true;
            }

            var canExcute = _load.HasWafer(0);
            if (canExcute)
            {
                if (_load.GetWaferInfo(0).ProcessJob != null)
                {
                    if (_load.GetWaferInfo(0).ProcessJob.State != EnumProcessJobState.Processing)
                    {
                        return;
                    }
                }
                else
                {
                    return;
                }


                if (!_load.CheckWaferSequenceStepDone(0))
                {
                    if (_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0))
                    {
                        if (_load.CheckWaferNeedProcess(0))
                        {
                            _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0));

                            _load.GetWaferInfo(0).NextSequenceStep++;

                            return;
                        }
                        else
                        {
                            if (!GetWaferSequenceNextValue(ModuleName.Load, 0, "Type", out var strType))
                            {
                                return;
                            }

                            if (!GetWaferSequenceNextValue(ModuleName.Load, 0, "SetValue", out var strSetValue))
                            {
                                return;
                            }

                            if (!Int32.TryParse(strSetValue, out var setValue))
                            {
                                return;
                            }

                            //Load腔没有测温
                            //if (strType == "CoolingByTemp")
                            //{
                            //    if (_load.GetTemperature() <= setValue)
                            //    {
                            //        _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0));

                            //        _load.Vent();

                            //        _load.GetWaferInfo(0).NextSequenceStep++;
                            //    }
                            //}
                            if (strType == "CoolingByTime")
                            {
                                if (_loadWaferInfo.ContainsKey(_load.GetWaferInfo(0).WaferInnerID.ToString()))
                                {
                                    var dtStartTime = _loadWaferInfo[_load.GetWaferInfo(0).WaferInnerID.ToString()];
                                    var pastTime = (DateTime.Now - dtStartTime).TotalSeconds;

                                    _timeLoad = pastTime > setValue ? 0 : (setValue - pastTime);

                                    if (pastTime > setValue)
                                    {
                                        if (!_load.CheckPurged())
                                        {
                                            _load.Purge(_load.GetWaferPurgeCount(0), _load.GetWaferPumpDelayTime(0));

                                            return;
                                        }

                                        _load.ResetPurged();

                                        _load.Vent();

                                        _load.GetWaferInfo(0).NextSequenceStep++;

                                        _loadWaferInfo.Remove(_load.GetWaferInfo(0).WaferInnerID.ToString());

                                        //补全路径
                                        string squenceID = $"Sequence\\{_load.GetWaferInfo(0).PPID}.seq";
                                        GemManager.Instance.Equipment?.TriggerEvent("JobComplete", new string[] { "LotID", "SequenceID" },
                                            new object[] { _load.GetWaferInfo(0).LotId, squenceID });

                                        return;
                                    }
                                }
                                else
                                {
                                    _loadWaferInfo.Add(_load.GetWaferInfo(0).WaferInnerID.ToString(), DateTime.Now);

                                    return;
                                }
                            }
                        }
                    }
                    else if (!_load.IsReadyForPick(ModuleName.TMRobot, 0) && !_tmRobot.IsInPumping)
                    {
                        _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0);

                        return;
                    }
                }
                /*else
                {
                    // Job Done, 响蜂鸣器
                    _trigLLPjDone.CLK = true;
                    if (_trigLLPjDone.Q)
                    {
                        OP.DoOperation("System.AlertJobDone", ModuleName.LoadLock.ToString(), 0);
                    }
                }*/
            }
            else
            {
                if (_load.NoTray(0))
                {
                    if (!_load.IsReadyForPlace(ModuleName.TMRobot, 0) && !_tmRobot.IsInPumping)
                    {
                        _load.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
                        return;
                    }
                }
            }
        }


        private void MonitorPMTask()
        {
            //if (_pm1.FirstDetectTrayArrive(0))
            //{
            //    _pm1.GetWaferInfo(0).TrayUsedForWhichPM = (int)_pm1.Module;
            //}

            //if (_pm2.FirstDetectTrayArrive(1))
            //{
            //    _pm2.GetWaferInfo(0).TrayUsedForWhichPM = (int)_pm2.Module;
            //}

            foreach (var pm in _lstPms)
            {
                if (!pm.IsAvailable)
                    continue;

                if (pm.HasWafer(0))
                {
                    if (pm.CheckNeedRunClean(out var withWafer, out var recipe) && withWafer
                          && GetModule(pm.Module).GetWaferInfo(0).WaferStatus == WaferStatus.Dummy
                          && GetModule(pm.Module).GetWaferInfo(0).ProcessState == WaferProcessStatus.Wait)
                    {
                        pm.Process(recipe, true, withWafer);
                        continue;
                    }

                    if (GetModule(pm.Module).CheckWaferNeedProcess(0, pm.Module))
                    {
                        WaferInfoRt wafer = GetModule(pm.Module).GetWaferInfo(0);
                        if (pm.Process(wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].RecipeName, false, true))
                        {
                            GetModule(pm.Module).GetWaferInfo(0).NextSequenceStep++;
                            continue;
                        }
                    }
                    else
                    {
                        if (!pm.IsReadyForPick(ModuleName.TMRobot, 0))
                        {
                            pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Pick, 0);
                        }
                    }
                }
                else
                {
                    if (GetModule(pm.Module).CheckNeedRunClean(out var withWafer, out var recipe) && !withWafer)
                    {
                        pm.Process(recipe, true, withWafer);
                        continue;
                    }

                    if (!pm.IsReadyForPlace(ModuleName.TMRobot, 0))
                    {
                        pm.PrepareTransfer(ModuleName.TMRobot, EnumTransferType.Place, 0);
                    }
                }
            }
        }

        private void MonitorTmRobotTask()
        {
            // TMRobot Idle或者Error时，清除被传盘对象的等待状态
            if (_tmRobot.CheckTaskDone())
            {
                foreach (var pm in _lstPms.Where(
                             pm => pm.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone()))
                {
                    pm.StopWaitTransfer(ModuleName.TMRobot);
                }

                if (_buffer.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone())
                    _buffer.StopWaitTransfer(ModuleName.TMRobot);

                if (_load.IsWaitTransfer(ModuleName.TMRobot) && _tmRobot.CheckTaskDone())
                    _load.StopWaitTransfer(ModuleName.TMRobot);

                //if (_unload.IsWaitTransfer(ModuleName.TMRobot))
                //    _unload.StopWaitTransfer(ModuleName.TMRobot);
            }

            if (!_tmRobot.IsAvailable)
            {
                return;
            }

            if (!_tmRobot.IsAvailable)
                return;

            var act = tmRobotActions.Peek();
            act.Invoke();

            tmRobotActions.Enqueue(tmRobotActions.Dequeue());
        }


        #region TmRobotTask
        private void MonitorTmRobotLoadPlaceTask()
        {
            if (!_load.IsAvailable || !_tmRobot.IsAvailable)
            {
                return;
            }

            //place Robot有Tray有Wafer,Load无Tray,无Wafer
            var canPlace = _tmRobot.HasTray(0)  && _load.NoTray(0) && _load.NoWafer(0)
                           && !_load.CheckTrayPlaced();
            if (canPlace)
            {
                if(!_tmRobot.CheckWaferNeedProcess(0) || _tmRobot.CheckWaferSequenceStepDone(0) || _load.CheckWaferNextStepIsThis(ModuleName.TMRobot,0))
                {
                    if (_load.IsReadyForPlace(ModuleName.TMRobot, 0))
                    {
                        if (_tmRobot.Place(_load.Module, 0, Hand.Blade1))
                        {
                            _load.WaitTransfer(ModuleName.TMRobot, false, 0);
                            return;
                        }
                    }
                }
            }
        }

        private void MonitorTmRobotLoadPickTask()
        {
            if (!_load.IsAvailable || !_tmRobot.IsAvailable)
            {
                return;
            }
               
            //pick TM无Tray,需要Process
            var canPick = _tmRobot.NoTray(0) && _tmRobot.NoWafer(0)
                                             && _load.HasTray(0) && _load.HasWafer(0)
                                             && _load.CheckWaferNeedProcess(0) 
                                             && !_load.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0) 
                                             && _load.CheckWaferNextStepModuleNoTray(0);
            if (canPick)
            {
                //下一步如果去PM1，判断PM1是否准备好
                if (_pm1.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0))
                {
                    if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0))
                    {
                        return;
                    }
                        
                    if(!_pm1.CheckBufferToPMTemp())
                    {
                        return;
                    }
                }

                //下一步如果去PM2，判断PM2是否准备好
                if (_pm2.CheckWaferNextStepIsThis(ModuleName.LoadLock, 0))
                {
                    if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0))
                    {
                        return;
                    }

                    if (!_pm2.CheckBufferToPMTemp())
                    {
                        return;
                    }
                }

                if (_load.IsReadyForPick(ModuleName.TMRobot, 0))
                {
                    if (_tmRobot.Pick(_load.Module, 0, Hand.Blade1))
                    {
                        _load.WaitTransfer(ModuleName.TMRobot, true, 0);
                        return;
                    }
                }
            }

        }

        private void MonitorTmRobotBufferPlaceTask()
        {
            if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
            {
                return;
            }

            //place Buffer位置没有Tray,Robot有Wafer,下一步骤是Buffer
            var canPalce = _tmRobot.HasTray(0);
            if (canPalce)
            {
                SlotItem bufferEmptySlot = null;

                if (_tmRobot.CheckWaferNeedProcess(0, _pm1.Module)
                    && _buffer.NoTray(2)
                    && _buffer.NoWafer(2)
                    && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0))
                {
                    bufferEmptySlot = new SlotItem(ModuleName.Buffer, 2);
                }
                else if (_tmRobot.CheckWaferNeedProcess(0, _pm2.Module)
                         && _buffer.NoTray(1)
                         && _buffer.NoWafer(1)
                         && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0))
                {
                    bufferEmptySlot = new SlotItem(ModuleName.Buffer, 1);
                }
                //TMRobot的下一步是Buffer3
                else if (!_tmRobot.CheckWaferNeedProcess(0)
                        && _buffer.NoTray(0)
                        && _buffer.NoWafer(0)
                        && _buffer.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0))
                {
                    bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0);
                }
                //Load里有Tray
                else if (!_tmRobot.CheckWaferNeedProcess(0)
                       && _buffer.NoTray(0)
                       && _buffer.NoWafer(0)
                       && _load.HasTray(0))
                {
                    bufferEmptySlot = new SlotItem(ModuleName.Buffer, 0);
                }

                if (bufferEmptySlot == null)
                {
                    return;
                }

                if (_buffer.IsReadyForPlace(ModuleName.TMRobot, bufferEmptySlot.Slot))
                {
                    if (_tmRobot.Place(_buffer.Module, bufferEmptySlot.Slot, Hand.Blade1))
                    {
                        _buffer.WaitTransfer(ModuleName.TMRobot);
                        return;
                    }
                }
                return;
            }

        }

        private void MonitorTmRobotBufferPickTask()
        {
            if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
            {
                return;
            }

            //pick,Buffer有Tray,机械手没有Tray
            MonitorTmRobotBuffer1PickTask();
            MonitorTmRobotBuffer2PickTask();
            MonitorTmRobotBuffer3PickTask();
        }

        private void MonitorTmRobotBuffer3PickTask()
        {
            if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
            {
                return;
            }
               
            //pick,Buffer有Tray,机械手没有Tray
            var canPick = _tmRobot.NoTray(0);
            if (canPick)
            {
                if (_buffer.HasTray(2) && _buffer.HasWafer(2))
                {
                    if (_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 2))
                    {
                        return;
                    }

                    //下一步如果去PM1，判断PM1是否准备好
                    if (_pm1.CheckWaferNextStepIsThis(ModuleName.Buffer, 2))
                    {
                        if (!_pm1.IsAvailable || _pm1.HasTray(0) || _pm1.HasWafer(0) || !_pm1.IsReadyForPlace(ModuleName.TMRobot, 0))
                        {
                            return;
                        }

                        if(!_pm1.CheckBufferToPMTemp())
                        {
                            return;
                        }
                    }

                    if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
                    {
                        if (_tmRobot.Pick(_buffer.Module, 2, Hand.Blade1))
                        {
                            _buffer.WaitTransfer(ModuleName.TMRobot);
                            return;
                        }
                    }

                }
            }
        }

        private void MonitorTmRobotBuffer2PickTask()
        {
            if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
            {
                return;
            }

            //pick,Buffer有Tray,机械手没有Tray
            var canPick = _tmRobot.NoTray(0);
            if (canPick)
            {
                if (_buffer.HasTray(1) && _buffer.HasWafer(1))
                {
                    if (_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 1))
                    {
                        return;
                    }

                    //下一步如果去PM2，判断PM2是否准备好
                    if (_pm2.CheckWaferNextStepIsThis(ModuleName.Buffer, 1))
                    {
                        if (!_pm2.IsAvailable || _pm2.HasTray(0) || _pm2.HasWafer(0) || !_pm2.IsReadyForPlace(ModuleName.TMRobot, 0))
                        {
                            return;
                        }

                        if(!_pm2.CheckBufferToPMTemp())
                        {
                            return;
                        }
                    }

                    if (_buffer.CheckWaferNextStepModuleNoTray(1))
                    {
                        if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
                        {
                            if (_tmRobot.Pick(_buffer.Module, 1, Hand.Blade1))
                            {
                                _buffer.WaitTransfer(ModuleName.TMRobot);
                                return;
                            }
                        }
                    }

                }
            }
        }

        private void MonitorTmRobotBuffer1PickTask()
        {
            if (!_tmRobot.IsAvailable || !_buffer.IsAvailable)
            {
                return;
            }

            var canPick = _tmRobot.NoTray(0) && _tmRobot.NoWafer(0);
            if (canPick)
            {
                if (_buffer.HasTray(0)
                    && _load.NoTray(0) && _load.NoWafer(0)
                    && !_buffer.CheckWaferNextStepIsThis(ModuleName.Buffer, 0)
                    && _load.IsReadyForPlace(ModuleName.TMRobot,0)
                    && _load.IsAvailable
                    && _load.IsOnline)
                {
                    if (!_buffer.CheckWaferNeedProcess(0))
                    {
                        if (_buffer.IsReadyForPick(ModuleName.TMRobot, 0))
                        {
                            if (_tmRobot.Pick(_buffer.Module,0, Hand.Blade1))
                            {
                                _buffer.WaitTransfer(ModuleName.TMRobot);
                                return;
                            }
                        }
                    }
                }
            }

        }

        private void MonitorTmRobotPMPlaceTask()
        {
            if (!_tmRobot.IsAvailable)
                return;

            //place to pm
            var blade0HasWaferAndNeedProcess = _tmRobot.HasWafer(0) && _tmRobot.HasTray(0) && _tmRobot.CheckWaferNeedProcess(0);

            if (blade0HasWaferAndNeedProcess)
            {
                foreach (var pm in _lstPms)
                {
                    if (!pm.IsAvailable
                        || !GetModule(pm.Module).NoWafer(0)
                        || !GetModule(pm.Module).NoTray(0)
                        || !pm.IsReadyForPlace(ModuleName.TMRobot, 0))
                        continue;

                    var blade0Place = _tmRobot.HasWafer(0) && _tmRobot.CheckWaferNeedProcess(0, pm.Module) && 
                        pm.CheckWaferNextStepIsThis(ModuleName.TMRobot, 0);
                    if (blade0Place)
                    {
                        if (!pm.CheckBufferToPMTemp())
                        {
                            continue;
                        }

                        if (_tmRobot.Place(pm.Module, 0, Hand.Blade1))
                        {
                            pm.WaitTransfer(ModuleName.TMRobot);
                            return;
                        }
                    }
                }
            }

        }

        private void MonitorTmRobotPMPickTask()
        {
            if (!_tmRobot.IsAvailable)
                return;

            //TMRobot从PM取Wafer,Buffer1中不能有Tray,否则先去Buffer1中的Tray
            if (_tmRobot.NoWafer(0) && _tmRobot.NoTray(0))
            {
                var pickBlade = Hand.Blade1;

                var pickPm = ModuleName.System;
                foreach (var schedulerPm in _lstPms)
                {
                    //增加温度低于900才能Pick的限制
                    if (!schedulerPm.IsAvailable
                        || GetModule(schedulerPm.Module).NoTray(0)
                        || GetModule(schedulerPm.Module).CheckWaferNeedProcess(0, schedulerPm.Module)
                        || _tmRobot.HasWafer((int)pickBlade)
                        || _tmRobot.HasTray((int)pickBlade))
                        continue;

                    //如果下一步是Buffer,只能取出放Buffer1
                    if (_buffer.CheckWaferNextStepIsThis(schedulerPm.Module, 0))
                    {
                        if (_buffer.NoTray(0) && _buffer.NoWafer(0))
                        {
                            pickPm = schedulerPm.Module;
                            break;
                        }
                    }
                    else if ((_buffer.NoTray(0) && _buffer.NoWafer(0))
                            || (_load.NoTray(0) && _load.NoWafer(0)))
                    {
                        pickPm = schedulerPm.Module;
                        break;
                    }
                }

                if (pickPm != ModuleName.System)
                {
                    var pmScheduler = _lstPms.Find(scheduler => scheduler.Module == pickPm);
                    if (!pmScheduler.CheckPMToTMRobotTemp())
                    {
                        return;
                    }

                    var pm = GetModule(pickPm.ToString());
                    if (pm.IsReadyForPick(ModuleName.TMRobot, 0))
                    {
                        if (_tmRobot.Pick(pm.Module, 0, pickBlade))
                        {
                            pm.WaitTransfer(ModuleName.TMRobot);

                            return;
                        }
                    }
                }
            }
        }
        #endregion


        #endregion

        #region Logic Check

        /// <summary>
        /// 获得Buffer的方式和数值
        /// </summary>
        /// <param name="module"></param>
        /// <param name="slot"></param>
        /// <param name="coolingType"></param>
        /// <param name="setValue"></param>
        /// <returns></returns>
        private bool GetWaferSequenceNextValue(ModuleName module, int slot, string nodeName, out string nodeValue)
        {
            nodeValue = "";

            if (!GetModule(module).HasWafer(slot))
                return false;

            WaferInfoRt wafer = GetModule(module).GetWaferInfo(slot);

            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
                return false;

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
                return false;

            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(module))
                return false;

            nodeValue = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter[nodeName].ToString();
            if (String.IsNullOrEmpty(nodeValue))
            {
                return false;
            }
            return true;
        }

        private bool GetWaferSequenceCurrentValue(ModuleName module, int slot, string nodeName, out string nodeValue)
        {
            nodeValue = "";

            if (!GetModule(module).HasWafer(slot))
                return false;

            WaferInfoRt wafer = GetModule(module).GetWaferInfo(slot);

            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
                return false;

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
                return false;

            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep - 1].StepModules.Contains(module))
                return false;

            nodeValue = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep - 1].StepParameter[nodeName].ToString();
            if (String.IsNullOrEmpty(nodeValue))
            {
                return false;
            }
            return true;
        }

        public bool CheckBufferWaferHasJob()
        {
            WaferInfoRt wafer = _buffer.GetWaferInfo(0);

            if (wafer.IsWaferEmpty)
            {
                return false;
            }
            if (wafer.ProcessJob == null)
            {
                return false;
            }

            var pj = _processJobList.Find(x => x.InnerId == wafer.ProcessJob.InnerId);
            if (pj == null)
            {
                return false;
            }

            return true;

        }

        public bool CheckWaferProcessModuleIsAvailable(ModuleName waferModule, int waferSlot)
        {
            var wafer = GetModule(waferModule).GetWaferInfo(waferSlot);

            if (wafer.IsWaferEmpty)
                return false;

            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
                return false;

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
                return false;

            //foreach (var module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
            //{
            //if (GetModule(module).NoWafer(0)
            //        && _lstPms.Find(x => x.Module == module).IsAvailable
            //        && !CheckNeedRunClean(module, out bool _, out string _))
            //        return true;
            //}

            foreach (var step in wafer.ProcessJob.Sequence.Steps)
            {
                foreach (var module in step.StepModules)
                {
                    if (module.ToString().StartsWith("PM")
                        && GetModule(module).NoWafer(0)
                        && _lstPms.Find(x => x.Module == module).IsAvailable
                        && !GetModule(module).CheckNeedRunClean(out var _, out var _))
                        return true;
                }
            }

            return false;
        }

        public bool CheckWaferSequenceStepDone(ModuleName waferModule, int waferSlot)
        {
            var wafer = WaferManager.Instance.GetWafer(waferModule, waferSlot);

            if (wafer.IsWaferEmpty)
            {
                return false;
            }
            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
            {
                return false;
            }

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count && wafer.ProcessJob.Sequence.Steps.Count > 0)
            {
                return true;
            }

            return false;
        }

        private SlotItem SortBySerialMode(List<Tuple<ModuleName, int>> processingWafers)
        {
            foreach (var pjSlotWafer in processingWafers)
            {
                if (pjSlotWafer.Item1 == ModuleName.CassAL || pjSlotWafer.Item1 == ModuleName.CassAR)
                {
                    if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm1.Module))
                    {
                        if (GetRunWaferCount(_pm1.Module) < 2)
                        {
                            return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
                        }
                        else
                        {
                            return null;
                        }
                    }
                    else if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm2.Module))
                    {
                        if (GetRunWaferCount(_pm2.Module) < 2)
                        {
                            return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
                        }
                        else
                        {
                            return null;
                        }
                    }
                }
            }

            return null;
        }

        private SlotItem SortByParallelMode(List<Tuple<ModuleName, int>> processingWafers)
        {
            foreach (var pjSlotWafer in processingWafers)
            {
                if (pjSlotWafer.Item1 == ModuleName.CassAL || pjSlotWafer.Item1 == ModuleName.CassAR)
                {
                    if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm1.Module))
                    {
                        if (GetRunWaferCount(_pm1.Module) < 2 && GetRunWaferCount(_pm1.Module) <= GetRunWaferCount(_pm2.Module))
                        {
                            return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
                        }
                    }
                    else if (GetModule(pjSlotWafer.Item1).CheckWaferNeedProcess(pjSlotWafer.Item2, _pm2.Module))
                    {
                        if (GetRunWaferCount(_pm2.Module) < 2 && GetRunWaferCount(_pm2.Module) <= GetRunWaferCount(_pm1.Module))
                        {
                            return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
                        }
                    }
                }
            }

            return SortBySerialMode(processingWafers);
        }

        /// <summary>
        /// 获取各个模块的Wafer总数量
        /// </summary>
        /// <returns></returns>
        private int GetRunWaferCount()
        {
            var waferCount = 0;
            if (_load.HasWafer(0))
            {
                waferCount++;
            }
            if (_unload.HasWafer(0))
            {
                waferCount++;
            }
            if (_tmRobot.HasWafer(0))
            {
                waferCount++;
            }
            foreach (var pm in _lstPms)
            {
                if (GetModule(pm.Module).HasWafer(0))
                {
                    waferCount++;
                }
            }
            for (var i = 0; i < _bufferFloors; i++)
            {
                if (_buffer.HasWafer(i))
                {
                    waferCount++;
                }
            }
            return waferCount;
        }

        private int GetRunWaferCount(ModuleName processIn)
        {
            var waferCount = 0;

            if (_tmRobot.HasWafer(0) && (_tmRobot.CheckWaferNeedProcess(0, processIn) || _tmRobot.GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString())))
            {
                waferCount++;
            }

            if (GetModule(processIn).HasWafer(0) && (GetModule(processIn).CheckWaferNeedProcess(0, processIn) || GetModule(processIn).GetWaferInfo(0).SubstHists.Select(x => x.locationID).Contains(processIn.ToString())))
            {
                waferCount++;
            }

            for (var i = 0; i < _bufferFloors; i++)
            {
                if (_buffer.HasWafer(i) && (_buffer.CheckWaferNeedProcess(i, processIn) || _buffer.GetWaferInfo(i).SubstHists.Select(x => x.locationID).Contains(processIn.ToString())))
                {
                    waferCount++;
                }
            }
            return waferCount;
        }

        /// <summary>
        /// 获取各个模块的石墨盘总数量
        /// </summary>
        /// <returns></returns>
        private int GetCurrentTrayCount()
        {
            var trayCount = 0;

            if (_tmRobot.HasTray(0))
            {
                trayCount++;
            }

            foreach (var pm in _lstPms)
            {
                if (GetModule(pm.Module).HasTray(0))
                {
                    trayCount++;
                }
            }

            for (var i = 0; i < _bufferFloors; i++)
            {
                if (_buffer.HasTray(i))
                {
                    trayCount++;
                }
            }

            return trayCount;
        }

        /// <summary>
        /// 获取ProcessJob可以同时运行工艺的Wafer总数
        /// </summary>
        /// <returns></returns>
        private int GetCurrentWaferCount()
        {
            var waferCountDiv = 0;
            var cassWaferCount = 0;
            foreach (var cj in _controlJobList)
            {
                if (cj.State == EnumControlJobState.Executing)
                {
                    foreach (var pj in _processJobList)
                    {
                        if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing)
                        {
                            cassWaferCount += pj.SlotWafers.Count;
                            foreach (var pjSlotWafer in pj.SlotWafers)
                            {
                                var module = GetModule(pjSlotWafer.Item1);
                                if (module.HasWafer(pjSlotWafer.Item2) && !module.CheckWaferNeedProcess(pjSlotWafer.Item2))
                                {
                                    waferCountDiv++;
                                }
                            }
                        }
                    }
                }
            }

            return cassWaferCount - waferCountDiv;

            //int waferCount = 0;
            //if (_load.HasWafer(0))
            //{
            //    waferCount++;
            //}
            //for (int i = 0; i < 3; i++)
            //{
            //if (_buffer.HasWafer(i))
            //    {
            //        waferCount++;
            //    }
            //}

            //if (_waferRobot.CheckWaferNeedProcess(0) )
            //{
            //    waferCount++;
            //}
            //if (_aligner.CheckWaferNeedProcess(0) )
            //{
            //    waferCount++;
            //}

            //for (int i=0;i<25;i++)
            //{
            //    if (CheckWaferNeedProcess(ModuleName.CassAL, i))
            //    {
            //        waferCount++;
            //    }
            //    if (CheckWaferNeedProcess(ModuleName.CassAR, i))
            //    {
            //        waferCount++;
            //    }
            //}
            //return waferCount;
        }
        #endregion



        #region Module error

        public Result MonitorModuleError()
        {
            var isModuleError = false;
            var isPMError = new bool[2];

            for (var i = 0; i < isPMError.Length; i++)
            {
                isPMError[i] = false;
            }

            if (_tmRobot.IsError)
                isModuleError = true;

            for (var i = 0; i < _lstPms.Count; i++) // PM出错，不影响其他腔体的传片
            {
                if (_lstPms[i].IsError)
                    isPMError[i] = true;
            }

            if (isModuleError && !_isModuleErrorPrevious)
            {

            }
            else if (!isModuleError && _isModuleErrorPrevious)
            {
                Reset();
            }

            for (var i = 0; i < _lstPms.Count; i++)
            {
                if (!isPMError[i] && _isPMErrorPrevious[i])
                {
                    _lstPms[i].ResetTask();
                }

                _isPMErrorPrevious[i] = isPMError[i];
            }

            _isModuleErrorPrevious = isModuleError;

            return Result.RUN;
        }

        private bool CheckModuleHaveWaferWithNoJob(out string reason)
        {
            reason = "";
            if (_controlJobList.Count > 0)
            {
                reason = "lstControlJobs.Count > 0";
                return false;
            }
            else
            {
                if (_buffer.HasWafer(0) || _buffer.HasWafer(1) || _buffer.HasWafer(2))
                {
                    reason = $"Buffer have wafer!";
                    EV.PostWarningLog(LogSource, reason);
                    return true;
                }

                if (_tmRobot.HasWafer(0))
                {
                    reason = $"TmRobot have wafer!";
                    EV.PostWarningLog(LogSource, reason);
                    return true;

                }

                if (!_load.HasWafer(0))
                {
                    reason = $"Load have no wafer!";
                    EV.PostWarningLog(LogSource, reason);
                    return true;

                }

                if (!_load.HasTray(0))
                {
                    reason = $"Load have no Tray!";
                    EV.PostWarningLog(LogSource, reason);
                    return true;

                }

                return false;
            }
        }

        private bool CheckWaferNeedProcess(ModuleName module, int waferSlot, ModuleName processIn = ModuleName.System)
        {
            WaferInfoRt wafer = WaferManager.Instance.GetWafer(module, waferSlot);

            if (wafer.IsWaferEmpty)
                return false;

            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.ProcessJob.Sequence.Steps == null)
                return false;

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count || wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules == null)
                return false;

            //if (processIn != ModuleName.System && !wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(processIn))
            //    return false;

            var hasPm = false;
            for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)
            {
                foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules)
                {
                    if (ModuleHelper.IsPm(stepModule))
                    {
                        hasPm = true;
                        break;
                    }
                }

                if (hasPm)
                    break;
            }

            if (processIn == ModuleName.System && !hasPm)
                return false;

            return true;
        }

        private bool SkipWaferProcessStep(WaferInfoRt wafer)
        {
            if (wafer.IsWaferEmpty)
                return false;

            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null || wafer.ProcessJob.Sequence.Steps == null)
                return false;

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count || wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules == null)
                return false;

            for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)
            {
                foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules)
                {
                    if (ModuleHelper.IsPm(stepModule))
                    {
                        if(wafer.NextSequenceStep == 0)
                        {
                            wafer.NextSequenceStep = wafer.ProcessJob.Sequence.Steps.Count - 1;
                        }
                        else
                        {
                            wafer.NextSequenceStep = i + 1;
                        }
                            
                        break;
                    }
                }
            }

            return true;
        }

        #endregion

    }
}