using System;
using System.Collections.Generic;
using System.Xml;
using Aitex.Core.Equipment.SusceptorDefine;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.RecipeCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.Util;
using MECF.Framework.Common.DBCore;
using MECF.Framework.Common.Equipment;
using Virgo_DRT.Devices;
namespace Virgo_DRT.Modules.PMs
{
    class ProcessRoutine : PMRoutineBase
    {
        /// 
        /// 工艺程序运行引擎状态定义
        /// 
        private enum RecipeEngineState
        {
            Error,
            RecipeCompleted,
            ExecStep,
            TimeWait,
            ConditionWait,
            StepCompleted,
            Paused,
        }
        /// 
        /// 工艺程序数据
        /// 
        private object _lockerTotalCycle = new object();
        private Dictionary _recipeTotalCycle = new Dictionary();
        //public bool IsAtmRecipeRun { private set; get; }
        private DeviceTimer _beginPauseTimer = new DeviceTimer();
        /// 
        /// 防止工艺程序运行线程和外部更新工艺程序数据的线程并发进行
        /// 
        private object _recipeLocker = new object();
        /// 
        /// 当前工艺执行引擎的状态
        /// 
        private RecipeEngineState _state = RecipeEngineState.ExecStep;
        private RecipeEngineState _pausedState = RecipeEngineState.ExecStep;
        private DeviceTimer _estimatedTimeCalcTimer = new DeviceTimer();//用于定时计算工艺程序估计的结束时间
        public DateTime RecipeStartTime { get; private set; }
        public int RecipeChangeNo { get; private set; }
        public string CurrentRecipeBaseName { get; private set; }
        public string CurrentRecipeRunningName { get; private set; }
        public string CurrentRecipeContent { get; private set; }
        public string CurrentLotName { get; set; }
        private List _recipeStepList = new List();
        public List CurrentRecipeStepList
        {
            get
            {
                return _recipeStepList;
            }
            set
            {
                _recipeStepList = value;
            }
        }
        public RecipeHead CurrentRecipeHead { get; set; }
        public int CurStepNum { get; private set; }
        public int CurStepTotalLoopCount { get; private set; }
        public double CurStepTotalTime
        {
            get
            {
                if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
                    return 0;
                return _recipeStepList[CurStepNum].StepTime * 1000;
            }
        }
        public int CurrentLoopCount
        {
            get;
            private set;
        }
        private DeviceTimer StepTimer = new DeviceTimer();
        public bool IsPaused
        {
            private set;
            get;
        }
        public string CurStepComment
        {
            get
            {
                if (_recipeStepList == null || _recipeStepList.Count == 0)
                    return string.Empty;
                return _recipeStepList[CurStepNum].StepName;
            }
        }
        public double CurStepLeftTime
        {
            get
            {
                if (IsPaused)
                    return StepTimer.GetTotalTime() - StepTimer.GetElapseTime() + _beginPauseTimer.GetElapseTime();
                //return Math.Max(0,StepTimer.GetTotalTime() - StepTimer.GetElapseTime());
                return StepTimer.GetTotalTime() - StepTimer.GetElapseTime();
            }
        }
        public double CurStepElpasedTime
        {
            get
            {
                if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
                    return 0;
                return StepTimer.GetElapseTime();
            }
        }
        public double CurStepTotalRfTime
        {
            get
            {
                if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
                    return 0;
                if (_recipeStepList[CurStepNum].RecipeCommands.ContainsKey("Rf.SetPower") &&
                    !string.IsNullOrEmpty(_recipeStepList[CurStepNum].RecipeCommands["Rf.SetPower"]) &&
                    Convert.ToDouble(_recipeStepList[CurStepNum].RecipeCommands["Rf.SetPower"]) > 0.1)
                    return CurStepTotalTime;
                return 0;
            }
        }
        public int TotalCycle
        {
            get
            {
                if (string.IsNullOrEmpty(DateTimeRecipeBaseName))
                    return 0;
                lock (_lockerTotalCycle)
                {
                    if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))
                        return _recipeTotalCycle[DateTimeRecipeBaseName];
                }
                return 0;
            }
        }
        public string DateTimeRecipeBaseName
        {
            get
            {
                if (string.IsNullOrEmpty(CurrentRecipeBaseName))
                    return "";
                return DateTime.Now.ToString("yyyyMMdd") + CurrentRecipeBaseName;
            }
        }
        public double PausedTime
        {
            get
            {
                return IsPaused ? _beginPauseTimer.GetElapseTime() : 0;
            }
        }
        public double EstimatedTotalLeftTime
        {
            get;
            private set;
        }
        public int RecipeTotalStepNum
        {
            get
            {
                return _recipeStepList.Count;
            }
        }
        public ProcessRoutine(JetPM chamber) : base(chamber)
        {
            Name = "ProcessRoutine";
            RecipeStartTime = new DateTime(0);
            EstimatedTotalLeftTime = 0;
            CalcEstimatedRecipeEndTime();
        }
        public Result Start(params object[] param)
        {
            RecipeStartTime          = DateTime.Now;
            CurrentRecipeBaseName    = (string)param[0];
            CurrentRecipeRunningName = (string)param[1];
            RecipeChangeNo           = (int)param[2];
            CurrentLotName           = (string)param[3];
            CurrentRecipeContent     = (string)param[4];
            CurrentRecipeHead        = (RecipeHead)param[5];
            CurrentRecipeStepList    = (List)param[6];
            if (!_chamber.IsRFGInterlockOn)
            {
                EV.PostAlarmLog(Module, "射频电源 Interlock条件不满足");
                return Result.VERIFYFAIL;
            }
            lock (_lockerTotalCycle)
            {
                if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))
                    _recipeTotalCycle[DateTimeRecipeBaseName] += 1;
                else
                {
                    _recipeTotalCycle[DateTimeRecipeBaseName] = 1;
                }
                List keys = new List();
                foreach (KeyValuePair item in _recipeTotalCycle)
                {
                    if (!item.Key.StartsWith(DateTime.Now.ToString("yyyyMMdd")))
                        keys.Add(item.Key);
                }
                foreach (string key in keys)
                {
                    _recipeTotalCycle.Remove(key);
                }
            }
            _chamber.OpenValve(ValveType.PROCESS, true);
            CurStepNum = CurStepTotalLoopCount = 0;
            _estimatedTimeCalcTimer.Start(1000);
            //EV.PostSoundMessage($"Run Recipe {CurrentRecipeRunningName}");
            EV.PostInfoLog(Module, $"工艺程序 {CurrentRecipeRunningName} 开始运行");
            //更新当前的工艺状态到数据库中
            //Singleton.Instance.CurrentRunningJob.JobResult = JobStatus.InProcessing;
            //Singleton.Instance.UpdateProcessStatus(Singleton.Instance.CurrentRunningJob.RecipeRunId, JobStatus.InProcessing);
            ProcessDataRecorder.UpdateStatus(RecipeRunGuid.ToString(), SusceptorStatus.InProcessing.ToString());
            _state = RecipeEngineState.ExecStep;
            return Result.RUN;
        }
        /// 
        /// quiting current state
        /// 
        /// 
        public void Exit()
        {
            _chamber.IsPressureToleranceEnabled = false;
            var ts = DateTime.Now - RecipeStartTime;
            var totalTime = $"{Convert.ToInt32(ts.TotalHours)}:{ts.Minutes}:{ts.Seconds}";
            //JobInfo job = Singleton.Instance.CurrentRunningJob;
            bool isProcessCompleted = _state == RecipeEngineState.RecipeCompleted;
            if (isProcessCompleted)
            {
                //正常工艺运行结束
                //Singleton.Instance.AddRecord(job.RecipeRunId, CarrierDataType.ProcessNormalEnd, totalTime, "recipe finished");
                //string info = string.Format(Resources.Process_Exit_Recipe0RNStartTime1RNEndTime2RNTotalTime3,
                //    CurrentRecipeRunningName, RecipeStartTime.ToString("yyyy/MM/dd HH:mm:ss"),
                //    DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), totalTime);
                EV.PostInfoLog(Module, $"工艺程序 {CurrentRecipeRunningName} 正常运行完毕");
                //if (true)
                //{
                //    EV.PostPopDialogMessage(EventLevel.Information, string.Format(Resources.Process_Exit_0RecipeCompletelyRun, Module), info);
                //}
                //job.JobResult = JobStatus.Processed;
            }
            else
            {
                //人为终止工艺运行结束
                //Singleton.Instance.AddRecord(job.RecipeRunId, CarrierDataType.PostProcessErrorEnd, totalTime, "recipe aborted");
                string info = string.Format("Recipe:{0}\r\nStart time:{1:yyyy/MM/dd HH:mm:ss}\r\nEnd time:{2:yyyy/MM/dd HH:mm:ss}\r\nTotal time:{3}",
                    CurrentRecipeRunningName, RecipeStartTime, DateTime.Now, totalTime);
                EV.PostWarningLog(Module, info);
                EV.PostPopDialogMessage(EventLevel.Warning, $"{Module} recipe was aborted", info);
                //Update susceptor information
                //job.JobResult = JobStatus.Troubled;
            }
            //job.ProcessEndTime = DateTime.Now;
            //重置工艺程序名
            CurrentRecipeRunningName = string.Empty;
            CurrentLotName = string.Empty;
            //stop all ramping when quiting processing state
            //StopRamp();
        }
        //private void CheckPressureStability()
        //{
        //    //如果有ThrottleValve 就检查Throttle Valve的tolerance
        //    if (DeviceModel.PressureControl != null)
        //    {
        //        DeviceModel.PressureControl.EnableTolerance =
        //            DeviceModel.MfcGas1 != null && DeviceModel.MfcGas1.SetPoint > 0.001 ||
        //            DeviceModel.MfcGas2 != null && DeviceModel.MfcGas2.SetPoint > 0.001 ||
        //            DeviceModel.MfcGas3 != null && DeviceModel.MfcGas3.SetPoint > 0.001;
        //    }
        //}
        /// 
        /// 工艺程序运行引擎放于此处
        /// 
        public Result Monitor()
        {
            string reason = string.Empty;
            CalcEstimatedRecipeEndTime();
            //检查软件互锁是否强制停止运行工艺程序
            //if (!doRoutineRunning.Value)
            //{
            //    if (!doRoutineRunning.Check(true, out reason))
            //    {
            //        EV.PostMessage(Module.ToString(), EventEnum.RecipeAbortedByInterlock, Module, reason);
            //        return Result.FAIL; //    Reactor.PostEvent(new AlarmHandleCommand("软件互锁"));
            //    }
            //}
            //工艺程序运行监控,自动打开阀门如果对应的MFC设定设置大于0
            _chamber.Monitor();
            if (_chamber.IsError)
                return Result.FAIL;
            if (_chamber.CheckFactoryScrubberSysAlarm)
            {
                _chamber.OpenValve(ValveType.FAST_PUMP, false);
                _chamber.OpenValve(ValveType.SOFT_PUMP, false);
                EV.PostAlarmLog(Module, $"{Module} {Name} Factory Scrubber System is alarm ");
                return Result.FAIL;
            }
            //工艺程序运行引擎
            lock (_recipeLocker)
            {
                try
                {
                    switch (_state)
                    {
                    case RecipeEngineState.ExecStep:
                        {
                            //工艺程序循环设置
                            if (_recipeStepList[CurStepNum].IsLoopStartStep)
                            {
                                CurStepTotalLoopCount = _recipeStepList[CurStepNum].LoopCount;
                                if (CurStepTotalLoopCount == 0)
                                {
                                    CurrentLoopCount = 0;
                                }
                                else
                                {
                                    CurrentLoopCount++;
                                }
                            }
                            //当前工艺程序步的定时器设定
                            StepTimer.Start(_recipeStepList[CurStepNum].StepTime * 1000);
                            //Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId,
                            //  CarrierDataType.RecipeStepStart, (CurStepNum + 1).ToString(),
                            //  string.Format(Resources.Process_Monitor_RecipeRunningStartStep01, CurStepNum + 1, _recipeStepList[CurStepNum].StepName));
                            //发送信息到用户界面
                            EV.PostInfoLog(Module, $"工艺程序 {CurrentRecipeRunningName} 第{CurStepNum + 1} 步开始:{_recipeStepList[CurStepNum].StepName}");
                            //执行工艺程序命令
                            foreach (var cmdkey in _recipeStepList[CurStepNum].RecipeCommands.Keys)
                            {
                                string recipeCmd = cmdkey;
                                string param = _recipeStepList[CurStepNum].RecipeCommands[recipeCmd];
                                if (string.IsNullOrWhiteSpace(param)) continue;
                                if (!OP.CanDoOperation($"{Module}." + recipeCmd, out reason, param))
                                {
                                    EV.PostAlarmLog(Module, $"不能执行 {recipeCmd}, {reason}");
                                    return Result.FAIL;
                                }
                                else
                                {
                                    var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);
                                    if (_recipeStepList[CurStepNum].IsJumpStep)
                                        rampTime_ms = 0;
                                    OP.DoOperation($"{Module}." + recipeCmd, out string reason1, rampTime_ms, param);
                                }
                                //    if (!DEVICE.CanDo(recipeCmd))
                                //{
                                //    EV.PostMessage(Module.ToString(), EventEnum.DefaultWarning, Module, recipeCmd);
                                //}
                                //else
                                //{
                                //    var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);
                                //    if (_recipeStepList[CurStepNum].IsJumpStep)
                                //        rampTime_ms = 0;
                                //    string str = _recipeStepList[CurStepNum].RecipeCommands[cmdkey];
                                //    if (!string.IsNullOrEmpty(str))
                                //        DEVICE.Do(recipeCmd, rampTime_ms, false, str);
                                //}
                            }
                            string endby = _recipeStepList[CurStepNum].EndBy;
                            if (string.IsNullOrEmpty(endby) ||
                                string.Compare(endby, "EndByStepTime", StringComparison.OrdinalIgnoreCase) == 0 ||
                                string.Compare(endby, "EndByRfTime", StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                _state = RecipeEngineState.TimeWait;
                            }
                            else
                            {
                                _state = RecipeEngineState.ConditionWait;
                            }
                        }
                        break;
                    case RecipeEngineState.TimeWait:
                        _chamber.CheckPressureStability();
                        if (StepTimer.IsTimeout())
                        {
                            _state = RecipeEngineState.StepCompleted;
                        }
                        break;
                    case RecipeEngineState.ConditionWait:
                        {
                            //var endbyCondition = (EndByCondition)Enum.Parse(typeof(EndByCondition), _recipeStepList[CurStepNum].EndBy, true);
                            //var endbyValue = Convert.ToDouble(_recipeStepList[CurStepNum].EndByValue);
                            //if (isStepEndby(endbyCondition, endbyValue))
                            {
                                _state = RecipeEngineState.StepCompleted;
                            }
                        }
                        break;
                    case RecipeEngineState.Paused:
                        break;
                    case RecipeEngineState.StepCompleted:
                        {
                            //发送新的一步开始的信息到用户界面
                            EV.PostInfoLog(Module, $"工艺程序 {CurrentRecipeRunningName} 第{CurStepNum + 1}步结束");
                            //添加石墨盘信息
                            //Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepNormalEnd, (CurStepNum + 1).ToString(), string.Format("recipe running:end step {0}", CurStepNum + 1));
                            //判断是否当前步循环终止
                            if (_recipeStepList[CurStepNum].IsLoopEndStep)
                            {
                                //重新读取循环的设定次数
                                for (int nn = CurStepNum; nn >= 0; nn--)
                                {
                                    if (_recipeStepList[nn].IsLoopStartStep)
                                    {
                                        CurStepTotalLoopCount = _recipeStepList[nn].LoopCount;
                                        break;
                                    }
                                }
                                if (CurrentLoopCount >= CurStepTotalLoopCount)
                                {
                                    CurrentLoopCount = CurStepTotalLoopCount = 0;
                                    CurStepNum++;
                                }
                                else
                                {
                                    int n = CurStepNum - 1;
                                    int next = -1;
                                    while (n >= 0)
                                    {
                                        if (_recipeStepList[n].IsLoopStartStep)
                                        {
                                            next = n;
                                            break;
                                        }
                                        n--;
                                    }
                                    if (next == -1)
                                        throw new Exception("Loop End control error");
                                    CurStepNum = next;
                                }
                            }
                            else
                            {
                                if (CurStepNum < _recipeStepList.Count - 1)
                                {
                                    CurStepNum++;
                                    _state = RecipeEngineState.ExecStep;
                                }
                                else
                                {
                                    EV.PostInfoLog(Module, $"工艺 {CurrentRecipeRunningName} 完毕");
                                    CurStepNum = _recipeStepList.Count - 1;
                                    _state = RecipeEngineState.RecipeCompleted;
                                    return Result.DONE;
                                }
                            }
                        }
                        break;
                    case RecipeEngineState.RecipeCompleted:
                        return Result.DONE;
                    case RecipeEngineState.Error:
                        return Result.FAIL;
                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    EV.PostAlarmLog(Module, $"{CurStepNum + 1}, 语法错误, {ex.Message}");
                    return Result.FAIL;
                }
            }
            return Result.RUN;
        }
        /// 
        /// 暂停工艺程序运行
        /// 
        public void PauseRecipe()
        {
            if (_state != RecipeEngineState.TimeWait && _state != RecipeEngineState.ConditionWait)
                return;
            if (!IsPaused)
            {
                string reason = string.Empty;
                IsPaused = true;
                _pausedState = _state;
                _state = RecipeEngineState.Paused;
                _beginPauseTimer.Start(0);
                //Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepPaused, CurStepNum.ToString(), string.Format(Resources.Process_PauseRecipe_工艺运行中当前第0步暂停, CurStepNum + 1));
                EV.PostInfoLog(Module, $"工艺程序'{CurrentRecipeRunningName}'第{CurStepNum + 1}步暂停");
                //pause mfc
                //pause pc
                //StopRamp();
            }
        }
        /// 
        /// 恢复工艺程序运行
        /// 
        public void ResumeRecipe()
        {
            if (IsPaused)
            {
                //update current recipe step time
                string recipeXml = CurrentRecipeContent;
                int currentStepNo = CurStepNum;
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(recipeXml);
                var stepNodes = xmlDoc.SelectNodes("/TableRecipeData/Step");
                if (currentStepNo >= 0 && currentStepNo < stepNodes.Count)
                {
                    var curStepNode = stepNodes[currentStepNo] as XmlElement;
                    var curStepNewTime = CurStepTotalTime + PausedTime;
                    if (curStepNewTime < 0)
                        curStepNewTime = 0;
                    TimeSpan tspan = new TimeSpan(0, 0, 0, 0, (int)curStepNewTime);
                    var timeString =
                        $"{((int)tspan.TotalHours).ToString("00")}:{tspan.Minutes.ToString("00")}:{tspan.Seconds.ToString("00")}";
                    curStepNode.SetAttribute("Time", timeString);
                    LOG.Write($"执行Resume命令,将当前第{currentStepNo}步时间修改为{timeString}");
                    UpdateRecipe(xmlDoc.OuterXml);
                }
                //Resume recipe
                IsPaused = false;
                _state = _pausedState;
                //Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepResume, CurStepNum.ToString(), string.Format("工艺运行中:当前第{0}步,取消暂停", CurStepNum + 1));
                EV.PostInfoLog(Module, $"工艺程序'{CurrentRecipeRunningName}'第{CurStepNum + 1}步继续");
                //resume recipe
                double stepElapsedTime = StepTimer.GetElapseTime() - _beginPauseTimer.GetElapseTime();
                double stepLeftTime = StepTimer.GetTotalTime() - stepElapsedTime;
                if (stepLeftTime < 0)
                    stepLeftTime = 0;
                //更新当前步的定时器时间
                StepTimer.Restart(StepTimer.GetTotalTime() + _beginPauseTimer.GetElapseTime());
                //重新执行当前工艺程序步
                foreach (var recipeCmd in _recipeStepList[CurStepNum].RecipeCommands.Keys)
                {
                    if (!DEVICE.CanDo(recipeCmd))
                    {
                        EV.PostInfoLog(Module, $"不可识别的工艺程序控制命令{recipeCmd}");
                    }
                    else
                    {
                        var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);
                        if (_recipeStepList[CurStepNum].IsJumpStep)
                            rampTime_ms = 0;
                        DEVICE.Do(recipeCmd, rampTime_ms, false, _recipeStepList[CurStepNum].RecipeCommands[recipeCmd]);
                    }
                }
            }
        }
        /// 
        /// 终止工艺程序运行
        /// 
        public void AbortRecipe()
        {
            ResumeRecipe();
            _state = RecipeEngineState.RecipeCompleted;
            CalcEstimatedRecipeEndTime();
            //StopRamp();
            //send informational event
            //Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepResume, CurStepNum.ToString(), string.Format("recipe running:aborted in step {0}", CurStepNum + 1));
            EV.PostInfoLog(Module, "工艺程序被终止运行");
        }
        /// 
        /// 跳至工艺程序下一步
        /// 
        public void SkipCurrentRecipeStep()
        {
            if (_state == RecipeEngineState.Paused)
            {
                EV.PostInfoLog(Module, "在 Pause Recipe 状态下不能执行 Skip to next step 命令");
                return;
            }
            try
            {
                //update current recipe step time
                string recipeXml = CurrentRecipeContent;
                int currentStepNo = CurStepNum;
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.LoadXml(recipeXml);
                var stepNodes = xmlDoc.SelectNodes("/TableRecipeData/Step");
                if (currentStepNo >= 0 && currentStepNo < stepNodes.Count)
                {
                    var curStepNode = stepNodes[currentStepNo] as XmlElement;
                    var curStepElapsedTime = CurStepTotalTime - CurStepLeftTime;//ms
                    if (curStepElapsedTime < 0)
                        curStepElapsedTime = 0;
                    TimeSpan tspan = new TimeSpan(0, 0, 0, 0, (int)curStepElapsedTime);
                    var timeString =
                        $"{((int)tspan.TotalHours).ToString("00")}:{tspan.Minutes.ToString("00")}:{tspan.Seconds.ToString("00")}";
                    curStepNode.SetAttribute("Time", timeString);
                    LOG.Write($"step skipped,step {currentStepNo} time changed to {timeString}");
                    //recipe update command
                    UpdateRecipe(xmlDoc.OuterXml);
                }
            }
            catch (Exception ex)
            {
                LOG.Write(ex);
            }
            if (_state == RecipeEngineState.ConditionWait || _state == RecipeEngineState.TimeWait)
            {
                _state = RecipeEngineState.StepCompleted;
                //send informational event
                EV.PostMessage(Module, EventEnum.GeneralInfo, Module, CurrentRecipeRunningName, CurStepNum + 1);
                //Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepJump, CurStepNum.ToString(), string.Format("Recipe Running:current step {0},skip to next step", CurStepNum + 1));
            }
        }
        public bool UpdateRecipe(string newRecipeContent)
        {
            lock (_recipeLocker)
            {
                RecipeHead head = null;
                List newRecipeData = null;
                if (!Recipe.Parse(newRecipeContent, out head, out newRecipeData))
                {
                    EV.PostMessage(Module, EventEnum.DefaultAlarm, Module, CurrentRecipeRunningName);
                    return false;
                }
                else
                {
                    string oldRecipeName = CurrentRecipeRunningName;
                    CurrentRecipeRunningName =
                        $"{DateTime.Now:yyyyMMddHHmmss}-{CurrentRecipeBaseName}-({RecipeChangeNo++})";
                    //update local recipe data
                    _recipeStepList = newRecipeData;
                    CurrentRecipeContent = newRecipeContent;
                    //Singleton.Instance.UpdateProcessRecipeName(Singleton.Instance.CurrentRunningJob.RecipeRunId, CurrentRecipeRunningName);
                    //update susceptor recipe name
                    //Susceptor sus = SusceptorManager.Instance.GetSystemSusceptors()[ModuleName.System];
                    //if (sus != null)
                    //{
                    //    sus.RecipeName = RecipeName;
                    //    SusceptorManager.Instance.Persist();
                    //}
                    //send informational event
                    EV.PostInfoLog(Module, $"运行工艺程序'{oldRecipeName}'第{CurStepNum + 1}步时更新工艺程序为'{CurrentRecipeRunningName}");
                    //Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeUpdated, CurStepNum.ToString(), string.Format("工艺运行中:当前第{0}步,更新程序:{1}", CurStepNum + 1, CurrentRecipeRunningName));
                    //notify recipe change event to TM
                    RecipeFileManager.Instance.SaveRecipeHistory(ModuleName.System.ToString(), CurrentRecipeRunningName, CurrentRecipeContent);
                }
            }
            return true;
        }
        /// 
        /// Status name
        /// 
        /// 
        public override string ToString()
        {
            return "recipe running";
        }
        protected void sendRecipeStopToSmart()
        {
            ///工艺停止发送StreamOffCommand
            //           NotifierSmart.SendCommand("StreamOffCommand", Reactor.ChamId);
        }
        /// 
        /// 工艺程序估计结束时间计算
        /// 
        protected void CalcEstimatedRecipeEndTime()
        {
            try
            {
                //(*计算当前工艺程序预计所需的总时间,从当前步开始计算剩余步的估算时间+已经既成事实的时间 => 总的估计时间,采用该种方式进行总工艺时间理论上最为精确*)
                if (!_estimatedTimeCalcTimer.IsTimeout())
                    return;
                _estimatedTimeCalcTimer.Start(1000);
                EstimatedTotalLeftTime = 0;
                if (_state == RecipeEngineState.RecipeCompleted)
                    return;
                if (!(CurStepNum >= 0 && CurStepNum <= _recipeStepList.Count - 1))
                    return;
                if (CurStepLeftTime > 0)
                {
                    EstimatedTotalLeftTime = CurStepLeftTime;
                }
                int nextBegin = CurStepNum;
                //(*判断当前是否处于循环之中*)
                bool IsInLoop = false;
                int iNum1 = 0;
                int iNum2 = 0;
                //int j=i;
                for (int j = CurStepNum; j < _recipeStepList.Count; j++)
                {
                    if (_recipeStepList[j].IsLoopEndStep)
                    {
                        iNum2 = j;
                        IsInLoop = true;
                        break;
                    }
                    else if (j > CurStepNum && _recipeStepList[j].IsLoopStartStep)
                    {
                        IsInLoop = false;
                        break;
                    }
                }
                if (IsInLoop)
                {
                    //(*当前步处于循环中*)
                    iNum1 = CurStepNum;
                    for (int j = CurStepNum; j >= 0; j--)
                    {
                        if (_recipeStepList[j].IsLoopStartStep)
                        {
                            iNum1 = j;
                            break;
                        }
                    }
                    for (int j = CurStepNum + 1; j <= iNum2; j++)
                    {
                        EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000 * (_recipeStepList[iNum1].LoopCount - CurrentLoopCount + 1);
                    }
                    for (int j = iNum1; j <= CurStepNum; j++)
                    {
                        EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000 * (_recipeStepList[iNum1].LoopCount - CurrentLoopCount);
                    }
                    nextBegin = iNum2 + 1;
                }
                else
                {
                    nextBegin++;
                }
                //(*当前步处于循环外*)
                for (int j = nextBegin; j < _recipeStepList.Count; j++)
                {
                    if (_recipeStepList[j].IsLoopStartStep)
                    {
                        //j=i;
                        iNum1 = j;
                        iNum2 = j + 1;
                        double lr1 = 0;
                        for (int m = j; m < _recipeStepList.Count; m++)
                        {
                            lr1 += _recipeStepList[m].StepTime * 1000;
                            if (_recipeStepList[m].IsLoopEndStep)
                            {
                                iNum2 = m;
                                break;
                            }
                        }
                        EstimatedTotalLeftTime = EstimatedTotalLeftTime + lr1 * _recipeStepList[iNum1].LoopCount;
                        j = iNum2;
                    }
                    else
                    {
                        EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000;
                    }
                    //END_WHILE
                }
            }
            catch (Exception ex)
            {
                LOG.Write(ex);
            }
        }
    }
}