using Aitex.Core.RT.Device;
using Aitex.Core.RT.Device.Unit;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadLocks;
using SicModules.EFEMs.Routines;
using SicModules.TMs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace SicModules.LLs.Routines
{
    public class LoadLockSlitValveRoutine : LoadLockBaseRoutine
    {
        enum RoutineStep
        {
            ServoRoutine,
            LiftRoutine,
            CheckPressureCondition,
            CheckPressure,
            SetSlitValve,
            CheckPressureCondition2,
            TimeDlay1
        }

        private int _motionTimeout = 30;
        private bool _paramIsOpen;          //是否开门
        private SicTM _tm;
        private IoSlitValve _slitvalveLoadLockLeft;
        private LoadLockServoToRoutine _llServoToRoutine;
        private LoadLockLiftRoutine _llLiftRoutine;

        public void Init(bool isOpen)
        {
            _paramIsOpen = isOpen;
            Name = isOpen ? "Open Slit Valve" : "Close Slit Valve";
        }

        public LoadLockSlitValveRoutine()
        {
            Module = ModuleName.LoadLock.ToString();
            Name = "LoadLockSlitValue";
            _tm = DEVICE.GetDevice<SicTM>($"{ModuleName.System.ToString()}.{ModuleName.TM.ToString()}");
            _llServoToRoutine = new LoadLockServoToRoutine(ModuleName.LoadLock);

            _llLiftRoutine = new LoadLockLiftRoutine();
            _slitvalveLoadLockLeft = DEVICE.GetDevice<IoSlitValve>("LoadLock.LoadLockLSideDoor");

        }

        public override Result Start(params object[] objs)
        {
            Reset();
            if (_paramIsOpen)
            {
                //判断TM到LoadLock或者UnLoad的门是否关上
                if (!_tm.CheckSlitValveClose(ModuleName.LoadLock))
                {
                    EV.PostWarningLog(Module, $"can not open left slit valve,TM slit valve not closed, can not open at same time");
                    return Result.FAIL;
                }

                _motionTimeout = SC.GetValue<int>("System.SlitValveMotionTimeout");

                _llServoToRoutine.Init(SC.GetValue<double>("LoadLock.AtmPressureBase"));
                _llLiftRoutine.Init(false);
            }
            Notify("Start");
            return Result.RUN;
        }

        public override Result Monitor()
        {
            try
            {
                //开门之前需要对两边腔体进行气压调节,降Lift
                if (_paramIsOpen)
                {
                    ExecuteRoutine((int)RoutineStep.ServoRoutine, _llServoToRoutine);
                    ExecuteRoutine((int)RoutineStep.LiftRoutine, _llLiftRoutine);
                }

                SetSlitValve((int)RoutineStep.SetSlitValve, _paramIsOpen, _motionTimeout);

                TimeDelay((int)RoutineStep.TimeDlay1, 1);

            }
            catch (RoutineBreakException)
            {
                return Result.RUN;
            }
            catch (RoutineFaildException)
            {
                return Result.FAIL;
            }

            Notify("Finished");
            return Result.DONE;

        }

        public void SetSlitValve(int id, bool isOpen, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify($"set left slit valve  " + (isOpen ? "Open" : "Close"));

                if (!_slitvalveLoadLockLeft.SetSlitValve(isOpen, out string reason))
                {
                    Stop(reason);
                    return false;
                }

                return true;
            }, () =>
            {
                return isOpen ? _slitvalveLoadLockLeft.IsOpen : _slitvalveLoadLockLeft.IsClose;

            }, timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    Stop($"can not complete in {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                    throw (new RoutineBreakException());
            }
        }

    }
}
