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,
            SetM7Or10,
            SetM8Or11,
            SetM21,
            OpenV73,
            StartLoop,
            OpenGroup1,
            CloseGroup2,
            OpenGroup3,
            CloseGroup3,
            OpenGroup2,
            CloseGroup1,
            EndLoop,

            CloseGroup3_2,
            CloseGroup2_2,
            OpenGroup1_2,
            CloseV73,
            SetM7Or10_2,
            SetM8Or11_2,
            SetPC2Or3,

            TimeDelay1,
            TimeDelay2,
        }

        private bool _isTCS = false;        //标记是TMA换源还是TCS换源
        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 mfc7Or10 = 7;
        private int mfc8Or11 = 8;
        private int pc2Or3 = 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)
        {
            if (moName.ToUpper().Contains("TCS"))
            {
                _isTCS = true;
            }
            else
            {
                _isTCS = false;
            }
        }

        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");

            //设置TCS换源参数
            if (_isTCS)
            {
                mfc7Or10 = 10;
                mfc8Or11 = 11;
                pc2Or3 = 3;

                _lstGroup1 = new List<string>() { "V49" };
                _lstGroup2 = new List<string>() { "V48", "V48s" };
                _lstGroup3 = new List<string>() { "V50", "V50s" };
            }
            else
            {
                mfc7Or10 = 7;
                mfc8Or11 = 8;
                pc2Or3 = 2;

                _lstGroup1 = new List<string>() { "V45" };
                _lstGroup2 = new List<string>() { "V43", "V43s" };
                _lstGroup3 = new List<string>() { "V46", "V46s" };
            }

            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);

                //设定M7,M8 80%,PC2设定Max
                SetMfcValueByPercent((int)RoutineStep.SetM7Or10, mfc7Or10, 80);
                SetMfcValueByPercent((int)RoutineStep.SetM21, 21, 80);
                SetMfcValueByPercent((int)RoutineStep.SetM8Or11, mfc8Or11, 80);

                //打开V73
                SetIoValueByList((int)RoutineStep.OpenV73, _lstGroupV73, true, _IoValueTimeout);

                //循环开始
                Loop((int)RoutineStep.StartLoop, _loopCount);

                //打开Group1
                SetIoValueByList((int)RoutineStep.OpenGroup1, _lstGroup1, true, _IoValueTimeout);

                //关闭Group2
                SetIoValueByList((int)RoutineStep.CloseGroup2, _lstGroup2, false, _IoValueTimeout);

                //打开Group3
                SetIoValueByList((int)RoutineStep.OpenGroup3, _lstGroup3, true, _IoValueTimeout);

                TimeDelay((int)RoutineStep.TimeDelay1, _OpenTime);

                //关闭Group3
                SetIoValueByList((int)RoutineStep.CloseGroup3, _lstGroup3, false, _IoValueTimeout);

                //打开Group2
                SetIoValueByList((int)RoutineStep.OpenGroup2, _lstGroup2, true, _IoValueTimeout);

                //关闭Group1
                SetIoValueByList((int)RoutineStep.CloseGroup1, _lstGroup1, false, _IoValueTimeout);

                TimeDelay((int)RoutineStep.TimeDelay2, _CLoseTime);

                EndLoop((int)RoutineStep.EndLoop);

                //关闭Group3
                SetIoValueByList((int)RoutineStep.CloseGroup3_2, _lstGroup3, false, _IoValueTimeout);

                //关闭Group2
                SetIoValueByList((int)RoutineStep.CloseGroup2_2, _lstGroup2, false, _IoValueTimeout);

                //打开Group1
                SetIoValueByList((int)RoutineStep.OpenGroup1_2, _lstGroup1, true, _IoValueTimeout);

                //关闭V73
                SetIoValueByList((int)RoutineStep.CloseV73, _lstGroupV73, true, _IoValueTimeout);

                //设定M7,M8/M10,M11到默认值
                SetMfcValueToDefaultByID((int)RoutineStep.SetM7Or10_2, mfc7Or10);
                SetMfcValueToDefaultByID((int)RoutineStep.SetM8Or11_2, mfc8Or11);

                //设置PC2/PC3到默认值
                SetPcToDefault((int)RoutineStep.SetPC2Or3, new List<int> { pc2Or3 });
            }
            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> { mfc7Or10 });
            _pmModule.SetMfcValueToDefault(new List<int> { mfc8Or11 });
            _pmModule.SetPCValueToDefault(new List<int> { pc2Or3 });
            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());
            }
        }
    }
}
