using System;
using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
 
using VirgoRT.Devices;

namespace VirgoRT.Modules.PMs
{
    class GasFlowRoutine : PMRoutineBase, IRoutine
    {
        private enum RoutineStep
        {
            CheckPressure,
            StartFlow,
            StopFlow,
            CheckStable,
            End,
        };

        public bool _gasStatus = false;
        private double _pressureAlarmRange;
        private double _pressureAlarmTime;
        //private double _gasFlowAlarmRange;
        //private double _gasFlowAlarmTime;

        private double[] _mfcSetPoint = new double[5];

        public GasFlowRoutine(JetPM chamber) : base(chamber)
        {
            Name = "Flow gas";
            bUINotify = true;
        }

        public Result Start(params object[] objs)
        {
            if (!_chamber.IsFastPumpOpened)
            {
                StopFlow2();
                Stop("Pump 阀没有打开");
                return Result.FAIL;
            }

            Reset();

            _pressureAlarmRange = SC.GetValue<double>($"{Module}.GasFlowPressureAlarmRange");
            _pressureAlarmTime = SC.GetValue<double>($"{Module}.GasFlowPressureAlarmTime");

            // open process final valve and flow
            Notify("Open valve and flow mfc");
            _chamber.SetValveOnOff(ValveType.PROCESS, true);

            int i = 0;
            foreach (object o in objs)
            {
                _mfcSetPoint[i++] = (double)o;
            }

            FlowMfc2((int)RoutineStep.StartFlow, _mfcSetPoint);

            _gasStatus = true;

            return Result.RUN;
        }

        public Result Monitor()
        {
            try
            {
                //CheckPressure((int)RoutineStep.CheckPressure, "Wait for pressure normally",  (int)_pressureAlarmTime, Notify, Stop);

                if (_chamber.HasGasOutOfRange)
                {
                    Stop("流气率越界");
                    _gasStatus = false;
                    return Result.FAIL;
                }

                End((int)RoutineStep.End);
            }
            catch (RoutineBreakException)
            {
                return Result.RUN;
            }
            catch (RoutineFaildException)
            {
                _gasStatus = false;
                return Result.FAIL;
            }
            catch (Exception ex)
            {
                Stop(ex.Message);
                _gasStatus = false;
                return Result.FAIL;
            }

            return Result.DONE;
        }

        public void FlowMfc2(int id, double[] mfcValues)
        {
            string reason = string.Empty;

            for (int index = 0; index < mfcValues.Length; index++)
            {
                _chamber.FlowGas(index, mfcValues[index]);
            }
        }

        public void StopFlow2()
        {
            Notify("Close valve and stop to flow MFC");

            _chamber.SetValveOnOff(ValveType.PROCESS, false);
            _chamber.StopAllGases();
        }

        [Obsolete]
        public void FlowMfc(int id, double[] mfcValues, int time)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify("Open valve and flow mfc");
                string reason = string.Empty;

                _chamber.SetValveOnOff(ValveType.PROCESS, true);

                for (int index = 0; index < mfcValues.Length; index++)
                {
                    if (mfcValues[index] > 0)
                    {
                        _chamber.FlowGas(index, mfcValues[index]);
                    }
                }

                return true;
            }, () => { return _chamber.HasGasOutOfRange; }, time * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    _chamber.StopAllGases();

                    throw new RoutineFaildException();
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    _chamber.StopAllGases();

                    EV.PostAlarmLog(Module, $"MFC not flow normally in {time} seconds");

                    throw new RoutineFaildException();
                }
                else
                    throw new RoutineBreakException();
            }
        }

        [Obsolete]
        public void StopGasFlow(int id)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                Notify("Close valve and stop to flow MFC");
                string reason = string.Empty;

                _chamber.SetValveOnOff(ValveType.PROCESS, false);
                _chamber.StopAllGases();

                return true;
            });

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

        public void CheckStable(int id, string name, int alarmTime)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify(name);
                delayTimer.Start(0);
                return true;
            },
            () =>
            {
                if (_chamber.PressureMode == PressureCtrlMode.TVPressureCtrl)
                {
                    return _chamber.TargetPressure < _chamber.ChamberPressure;
                }

                return delayTimer.GetElapseTime() / 1000 > 10;
            }, alarmTime * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw new RoutineFaildException();
                }
                else if (ret.Item2 == Result.TIMEOUT)
                {
                    EV.PostAlarmLog(Module, $"Gas flow pressure not stable in {alarmTime} seconds");
                    throw new RoutineFaildException();
                }
                else
                    throw new RoutineBreakException();
            }
        }

        public override void Abort()
        {
            this.StopFlow2();
            _gasStatus = false;
        }
    }
}