using System;
using System.Collections.Generic;
using System.Diagnostics;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Device.Devices;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Fsm;
using SicModules.PMs.Routines.Base;

namespace SicModules.PMs.Routines
{
    public class PMExchangeMoRoutine : PMBaseRoutine
    {
        private enum RoutineStep
        {
            SetGroupK,
            SetMfc1,
            SetMfc2,
            SetM21,
            OpenV73,
            StartLoop,
            OpenGroup1,
            CloseGroup2,
            OpenGroup3,
            CloseGroup3,
            OpenGroup2,
            CloseGroup1,
            EndLoop,

            CloseGroup3_2,
            CloseGroup2_2,
            OpenGroup1_2,
            CloseV73,
            SetDefalutMfc1,
            SetDefalutMfc2,
            SetPC,
            SetPCMax,

            TimeDelay1,
            TimeDelay2,
            TimeDelay3,

            LoopCloseGroup2, 
            LoopOpenGroup3, 
            LoopOpenGroup1, 
            LoopCloseGroup3, 
            LoopOpenGroup2
        }

        private string _type = "";        //CS2 WCO6 MORE MOCO6
        private PMModule _pmModule;
        private ModuleName moduleName;
        private IoInterLock _pmIoInterLock;

        private int _IoValueTimeout = 2; //开关超时时间
        private int _loopCount;
        private int _routineTimeOut;

        private double _OpenTime = 10;
        private double _CLoseTime = 10;

        //默认为TMA换源参数
        private int mfc1 = 7;
        private int mfc2 = 8;
        private int pc = 2;

        private List<string> _lstGroupV73 = new List<string>() { "V73" };

        private List<string> _lstGroup1 = new List<string>() { "V49" };
        private List<string> _lstGroup2 = new List<string>() { "V48", "V48s" };
        private List<string> _lstGroup3 = new List<string>() { "V50", "V50s" };

        private Stopwatch _swTimer = new Stopwatch();
        public PMExchangeMoRoutine(ModuleName module, PMModule pm) : base(module, pm)
        {
            moduleName = module;
            _pmModule = pm;
            Name = "MoExchange";
            _pmIoInterLock = DEVICE.GetDevice<IoInterLock>($"{Module}.PMInterLock");
        }

        public void Init(string moName)
        {
            _type = moName;
        }

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

            if (_pmModule.V69.Status)
            {
                EV.PostAlarmLog(Module, $"can not Exchange Mo,V69 should be Closed");
                return Result.FAIL;
            }
            if (_pmModule.V72.Status)
            {
                EV.PostAlarmLog(Module, $"can not Exchange Mo,V72 should be Closed");
                return Result.FAIL;
            }
            if (_pmModule.V74.Status)
            {
                EV.PostAlarmLog(Module, $"can not Exchange Mo,V74 should be Closed");
                return Result.FAIL;
            }
            if (_pmModule.EPV2.Status)
            {
                EV.PostAlarmLog(Module, $"can not Exchange Mo,EPV2 should be Closed");
                return Result.FAIL;
            }

            _loopCount = SC.GetValue<int>($"PM.{Module}.MoExchange.CycleCount");
            _OpenTime = SC.GetValue<int>($"PM.{Module}.MoExchange.PumpTime");
            _CLoseTime = SC.GetValue<int>($"PM.{Module}.MoExchange.VentTime");
            _routineTimeOut = SC.GetValue<int>($"PM.{Module}.MoExchange.RoutineTimeOut");

            //设置换源参数
            switch (_type)
            {
                case "CS2":
                    mfc1 = 11;
                    mfc2 = 12;
                    pc = 3;

                    _lstGroup1 = new List<string>() { "V49" };
                    _lstGroup2 = new List<string>() { "V50", "V50s" };
                    _lstGroup3 = new List<string>() { "V48", "V48s" };
                    break;
                case "WCO6":
                    mfc1 = 7;
                    mfc2 = 8;
                    pc = 2;

                    _lstGroup1 = new List<string>() { "V45" };
                    _lstGroup2 = new List<string>() { "V46", "V46s" };
                    _lstGroup3 = new List<string>() { "V43", "V43s" };
                    break;
                case "MORE":
                    mfc1 = 16;
                    mfc2 = 17;
                    pc = 9;

                    _lstGroup1 = new List<string>() { "V22" };
                    _lstGroup2 = new List<string>() { "V23", "V23s" };
                    _lstGroup3 = new List<string>() { "V21", "V21s" };
                    break;
                case "MOCO6":
                    mfc1 = 9;
                    mfc2 = 10;
                    pc = 8;

                    _lstGroup1 = new List<string>() { "V19" };
                    _lstGroup2 = new List<string>() { "V20", "V20s" };
                    _lstGroup3 = new List<string>() { "V18", "V18s" };
                    break;
            }

            if (!_pmIoInterLock.SetPMExchangeMoRoutineRunning(true, out string reason))
            {
                EV.PostAlarmLog(Module, $"can not Exchange Mo,{reason}");
                return Result.FAIL;
            }

            _swTimer.Restart();
            Notify("Start");
            return Result.RUN;
        }


        public override Result Monitor()
        {
            try
            {
                CheckRoutineTimeOut();

                //关闭K阀组
                SetIoValueByGroup((int)RoutineStep.SetGroupK, IoGroupName.K, false, _IoValueTimeout);

                //设定 M16 M17 80%， PC9 设定 Max；
                SetMfcValueByPercent((int)RoutineStep.SetMfc1, mfc1, 80);
                SetMfcValueByPercent((int)RoutineStep.SetMfc2, mfc2, 80);
                SetPCValueByPercent((int)RoutineStep.SetPCMax, pc, 100);

                //4.先打开 V73 ,再打开 V23 和 V23S 持续 30s；
                SetIoValueByList((int)RoutineStep.OpenV73, _lstGroupV73, true, _IoValueTimeout);
                SetIoValueByList((int)RoutineStep.OpenGroup2, _lstGroup2, true, _IoValueTimeout);
                TimeDelay((int)RoutineStep.TimeDelay1, _OpenTime);

                Loop((int)RoutineStep.StartLoop, _loopCount);

                //5.先关闭 V23 和 V23S，再打开 V21 和 V21S，再打开 V22, 持续 10S；
                SetIoValueByList((int)RoutineStep.LoopCloseGroup2, _lstGroup2, false, _IoValueTimeout);
                SetIoValueByList((int)RoutineStep.LoopOpenGroup3, _lstGroup3, true, _IoValueTimeout);
                SetIoValueByList((int)RoutineStep.LoopOpenGroup1, _lstGroup1, true, _IoValueTimeout);
                TimeDelay((int)RoutineStep.TimeDelay2, _CLoseTime);

                //6.关闭 V21 和 V21S，打开 V23 和 V23S，持续 30S；
                SetIoValueByList((int)RoutineStep.LoopCloseGroup3, _lstGroup3, false, _IoValueTimeout);
                SetIoValueByList((int)RoutineStep.LoopOpenGroup2, _lstGroup2, true, _IoValueTimeout);
                TimeDelay((int)RoutineStep.TimeDelay3, _OpenTime);
                //循环开始

                EndLoop((int)RoutineStep.EndLoop);

                //7.循环结束，关闭 V23 和 V23S，关闭 V73；
                SetIoValueByList((int)RoutineStep.CloseGroup2_2, _lstGroup2, false, _IoValueTimeout);
                SetIoValueByList((int)RoutineStep.CloseV73, _lstGroupV73, false, _IoValueTimeout);

                //8.设定 M16 M17 default， PC9 default。
                SetMfcValueToDefaultByID((int)RoutineStep.SetDefalutMfc1, mfc1);
                SetMfcValueToDefaultByID((int)RoutineStep.SetDefalutMfc2, mfc2);
                SetPcToDefault((int)RoutineStep.SetPC, new List<int> { pc });
            }
            catch (RoutineBreakException)
            {
                return Result.RUN;
            }
            catch (RoutineFaildException)
            {
                return Result.FAIL;
            }

            Notify($"Finished ! Elapsed time: {(int)(_swTimer.ElapsedMilliseconds / 1000)} s");
            _swTimer.Stop();
            SetRoutineRuningDo();
            return Result.DONE;
        }

        private void SetRoutineRuningDo()
        {
            _pmIoInterLock.DoExchangeMoRoutineRunning = false;
        }

        public override void Abort()
        {
            SetRoutineRuningDo();

            _pmModule.SetIoValue(_lstGroup2, false);
            _pmModule.SetIoValue(_lstGroup3, false);
            _pmModule.SetMfcValueToDefault(new List<int> { mfc1 });
            _pmModule.SetMfcValueToDefault(new List<int> { mfc2 });
            _pmModule.SetPCValueToDefault(new List<int> { pc });
            base.Abort();
        }
        private void CheckRoutineTimeOut()
        {
            if (_routineTimeOut > 10)
            {
                if ((int)(_swTimer.ElapsedMilliseconds / 1000) > _routineTimeOut)
                {
                    Notify($"Routine TimeOut! over {_routineTimeOut} s");
                    throw (new RoutineFaildException());
                }
            }
        }

        private void SetIoValueByList(int id, List<string> lstIo, bool close, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                _pmModule.SetIoValue(lstIo, close);
                return true;
            }, () =>
            {
                return _pmModule.CheckIoValue(lstIo, close);
            },
            timeout * 1000);

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

        private void SetMfcValueToDefaultByID(int id, int mfcID)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                List<int> lst = new List<int> { mfcID };
                _pmModule.SetMfcModelToNormal(lst);
                _pmModule.SetMfcValueToDefault(lst);
                return true;
            });

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


        private void SetMfcValueByPercent(int id, int mfcID, double percent)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                _pmModule.SetMfcModelToNormal(new List<int> { mfcID });
                _pmModule.SetMfcValueByPercent(mfcID, percent);
                return true;
            });

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

        private void SetPCValueByPercent(int id, int pcID, double percent)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                _pmModule.SetPcModelToNormal(new List<int> { pcID });
                _pmModule.SetPCValueByPercent(pcID, percent);
                return true;
            });

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