using Aitex.Core.Common;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using CyberX8_Core;
using CyberX8_RT.Devices.EFEM;
using CyberX8_RT.Modules.LPs;
using MECF.Framework.Common.Beckhoff.Station;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.Common.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CyberX8_RT.Modules.EFEM
{
    public class RobotCycleRoutine : ModuleRoutineBase, IRoutine
    {
        private enum RobotCycleStep
        {

            LPCycleStrat,
            
            PickFromLP,
            PickFromLPCheck,

            PlaceToAligner,
            PlaceToAlignerCheck,

            AlignAction,
            AlignCompleteCheck,

            PickFromAligner,
            PickFromAlignerCheck,

            PlaceToDummy,
            PlaceToDummyCheck,

            PickFromDummy,
            PickFromDummyCheck,

            PlaceToSrd,
            PlaceToSrdCheck,

            PickFromSrd,
            PickFromSrdCheck,

            PlaceToLP,
            PlaceToLPCheck,

            LPCycleEnd,

            End
        }

        EfemBase _efem;
        /// <summary>
        /// 当前Cycle选中的LP里面的Wafer数量
        /// </summary>
        private int _waferCount;

        private EfemPickRoutine _efemPickRoutine;
        private EfemPlaceRoutine _efemPlaceRoutine;
        private EFEMAlignRoutine _efemAlignRoutine;

        private ModuleName _targetLP;
        private ModuleName _targetAligner;
        private ModuleName _targetDummy;
        private ModuleName _targetSrd;
        
        private Queue<MoveItem> _lpToAlignerMoveItem = new Queue<MoveItem>();
        private Queue<MoveItem> _alignerToDummyMoveItem = new Queue<MoveItem>();
        private Queue<MoveItem> _alignerToSrdMoveItem = new Queue<MoveItem>();
        private Queue<MoveItem> _dummyToLpMoveItem = new Queue<MoveItem>();
        private Queue<MoveItem> _dummyToSrdMoveItem = new Queue<MoveItem>();
        private Queue<MoveItem> _srdToLpMoveItem = new Queue<MoveItem>();
        
        private Queue<int> _lpWaferIndex = new Queue<int>(); //记录有LP有Wafer的slot号
     
        private int _moveTimeout = 20 * 1000;
        private int _dummySlotNumber = 0;
        private object[] alignerParamater;

        public RobotCycleRoutine(EfemBase efem) : base(ModuleName.EfemRobot)
        {
            _efem = efem;
            _efemPickRoutine = new EfemPickRoutine(efem);
            _efemPlaceRoutine = new EfemPlaceRoutine(efem);
            _efemAlignRoutine = new EFEMAlignRoutine(efem);

        }

        public RState Start(params object[] objs)
        {
            _lpWaferIndex.Clear();//初始化LP 有wafer的slot号
            _waferCount = 0; //初始化wafercount的数量
            
            alignerParamater = new object[3];//初始化Align参数
            alignerParamater[0] = ModuleName.Aligner1;
            alignerParamater[1] = 0;
            
            if (objs.Length >= 6)
            {
                _targetLP = (ModuleName)objs[0];
                _targetAligner = (ModuleName)objs[1];
                _targetDummy = (ModuleName)objs[2];
                _targetSrd = (ModuleName)objs[3];
                alignerParamater[2] = (int)objs[5];
            }
            else
            {
                return RState.Failed;
            }
            if (!CheckPreCondition()) //检验前提条件
            {
                return RState.Failed;
            }
            _moveTimeout = SC.GetValue<int>($"EFEM.MotionTimeout") * 1000;
            
            MoveItem lpToAlignerMoveItem = new MoveItem   //LP To Aligner
            {
                SourceModule = _targetLP,
                SourceSlot = _lpWaferIndex.Dequeue(),
                DestinationModule = ModuleName.Aligner1,
                DestinationSlot = 0,
                RobotHand = 0 //表示blade1
            };
            _lpToAlignerMoveItem.Enqueue(lpToAlignerMoveItem);


           MoveItem alignerToDummyMoveItem = new MoveItem //Aligner To Dummy
            {
                SourceModule = ModuleName.Aligner1,
                SourceSlot = 0,
                DestinationModule = _targetDummy,
                DestinationSlot = 0,
                RobotHand = 0
            };
            _alignerToDummyMoveItem.Enqueue(alignerToDummyMoveItem);
            
            MoveItem alignerToSrdMoveItem = new MoveItem //Aligner To Srd
            {
                SourceModule = ModuleName.Aligner1,
                SourceSlot = 0,
                DestinationModule = _targetSrd,
                DestinationSlot = 0,
                RobotHand = 0
            };
            _alignerToSrdMoveItem.Enqueue(alignerToSrdMoveItem);
            
            MoveItem dummyToLpMoveItem = new MoveItem //Dummy To LP
            {
                SourceModule = _targetDummy,
                SourceSlot = 0,
                DestinationModule = _targetLP,
                DestinationSlot = _lpToAlignerMoveItem.Peek().SourceSlot, //放回原来LP的slot位置
                RobotHand = 0
            };
            _dummyToLpMoveItem.Enqueue(dummyToLpMoveItem);
            
            MoveItem dummyToSrdMoveItem = new MoveItem //Dummy To Srd
            {
                SourceModule = _targetDummy,
                SourceSlot = 0, 
                DestinationModule = _targetSrd,
                DestinationSlot = 0,
                RobotHand = 0
            };
            _dummyToSrdMoveItem.Enqueue(dummyToSrdMoveItem);
            
            MoveItem srdToLpMoveItem = new MoveItem //SRD To LP
            {
                DestinationModule = _targetLP,
                DestinationSlot = _lpToAlignerMoveItem.Peek().SourceSlot, //放回原来LP的slot位置
                RobotHand = 0
            };
            _srdToLpMoveItem.Enqueue(srdToLpMoveItem);

            return Runner.Start(Module, "Robot Cycle start");
        }
       
        public RState Monitor()
        {
            Runner.LoopStart(RobotCycleStep.LPCycleStrat, "LP Cycle Start", _waferCount, NullFun, _delay_1ms)
   
                .LoopRun(RobotCycleStep.PickFromLP, () => { return _efemPickRoutine.Start(_lpToAlignerMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunWithStopStatus(RobotCycleStep.PickFromLPCheck, () => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
                 () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from LP failed"))

                .LoopRun(RobotCycleStep.PlaceToAligner, () => { return _efemPlaceRoutine.Start(_lpToAlignerMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunWithStopStatus(RobotCycleStep.PlaceToAlignerCheck, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
                 () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to aligner failed"))

                .LoopRun(RobotCycleStep.AlignAction, () => { return _efemAlignRoutine.Start(alignerParamater) == RState.Running; }, _delay_1ms)
                .LoopRunWithStopStatus(RobotCycleStep.AlignCompleteCheck, () => { return CommonFunction.CheckRoutineEndState(_efemAlignRoutine); },
                 () => CheckRoutineStopStatus(_efemAlignRoutine, "Efem aligner Action failed"))

                .LoopRun(RobotCycleStep.PickFromAligner, () => { return _efemPickRoutine.Start(_alignerToDummyMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunWithStopStatus(RobotCycleStep.PickFromAlignerCheck, () => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
                 () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from aligner failed"))

                //从Aligner到dummy
                .LoopRunIf(RobotCycleStep.PlaceToDummy, _targetDummy != ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_alignerToDummyMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToDummyCheck, _targetDummy != ModuleName.Unknown,() => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
                 () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to dummy failed"))

                .LoopRunIf(RobotCycleStep.PickFromDummy, _targetDummy != ModuleName.Unknown, () => { return _efemPickRoutine.Start(_dummyToLpMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunIfWithStopStatus(RobotCycleStep.PickFromDummyCheck, _targetDummy != ModuleName.Unknown,() => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
                 () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from dummy failed"))

                //从Aligner到SRD的
                .LoopRunIf(RobotCycleStep.PlaceToSrd, _targetSrd != ModuleName.Unknown && _targetDummy==ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_alignerToSrdMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToSrdCheck, _targetSrd != ModuleName.Unknown && _targetDummy == ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
                 () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to srd failed"))
                .LoopRunIf(RobotCycleStep.PickFromSrd, _targetSrd != ModuleName.Unknown && _targetDummy == ModuleName.Unknown, () => { return _efemPickRoutine.Start(_alignerToSrdMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunIfWithStopStatus(RobotCycleStep.PickFromSrdCheck, _targetSrd != ModuleName.Unknown && _targetDummy == ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
                 () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from srd failed"))

                //从dummy到SRD的
                .LoopRunIf(RobotCycleStep.PlaceToSrd, _targetSrd != ModuleName.Unknown && _targetDummy != ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_dummyToSrdMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToSrdCheck, _targetSrd != ModuleName.Unknown && _targetDummy != ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
                 () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to srd failed"))
                .LoopRunIf(RobotCycleStep.PickFromSrd, _targetSrd != ModuleName.Unknown && _targetDummy != ModuleName.Unknown, () => { return _efemPickRoutine.Start(_dummyToSrdMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunIfWithStopStatus(RobotCycleStep.PickFromSrdCheck, _targetSrd != ModuleName.Unknown && _targetDummy != ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPickRoutine); },
                 () => CheckRoutineStopStatus(_efemPickRoutine, "Efem pick from srd failed"))

                //从Dummy回LP
                .LoopRunIf(RobotCycleStep.PlaceToLP, _targetDummy != ModuleName.Unknown && _targetSrd == ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_dummyToLpMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToLPCheck, _targetDummy != ModuleName.Unknown && _targetSrd == ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
                 () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to LP failed"))

                //从SRD回LP
                .LoopRunIf(RobotCycleStep.PlaceToLP, _targetSrd != ModuleName.Unknown, () => { return _efemPlaceRoutine.Start(_srdToLpMoveItem) == RState.Running; }, _delay_1ms)
                .LoopRunIfWithStopStatus(RobotCycleStep.PlaceToLPCheck, _targetSrd != ModuleName.Unknown, () => { return CommonFunction.CheckRoutineEndState(_efemPlaceRoutine); },
                 () => CheckRoutineStopStatus(_efemPlaceRoutine, "Efem place to LP failed"))

                .LoopEnd(RobotCycleStep.LPCycleEnd, UpdateMoveItem, _delay_1ms)
                .End(RobotCycleStep.End, ClearMoveItem, _delay_1ms);


            return Runner.Status;
        }

        public void Abort()
        {
            _efem.Halt();
        }

        #region 功能方法
        private bool CheckPreCondition()
        {
            if (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0))
            {
                Stop($"Efem robot arm already has a wafer, cannot do the RobotCycle action");
                return false;
            }
            //LoadPort状态判断
            if (ModuleHelper.IsLoadPort(_targetLP) && ModuleHelper.IsInstalled(_targetLP))
            {
                Loadport loadPort = GetLoadPort(_targetLP);
                if (loadPort == null)
                {
                    Stop($"{_targetLP} is null");
                    return false;
                }
                WaferInfo[] waferInfos = WaferManager.Instance.GetWafers(_targetLP);
                for (int i = 0; i < waferInfos.Length; i++)
                {
                    if (waferInfos[i] != null && !waferInfos[i].IsEmpty)
                    {
                        _waferCount++;
                        _lpWaferIndex.Enqueue(i);
                    }
                }
                if (_waferCount < 1)
                {
                    Stop($"there is no wafer in {_targetLP}");
                    return false;
                }

            }
            else if(ModuleHelper.IsLoadPort(_targetLP) && !ModuleHelper.IsInstalled(_targetLP))
            {
                Stop($"{_targetLP} is not installed");
                return false;
            }
            //Aligner状态判断
            //if (!ModuleHelper.IsInstalled(_targetAligner))
            //{
            //    Stop($"{_targetAligner} is not installed");
            //    return false;
            //}
            //Dummy状态判断
            if (!ModuleHelper.IsInstalled(_targetDummy))
            {
                Stop($"{_targetDummy} is not installed");
                return false;
            }
            //若dummy存在wafer,需要人工处理
            DummyDevice dummyDevice = Singleton<RouteManager>.Instance.EFEM.GetDummyDevice(_targetDummy - ModuleName.Dummy1);
            if(dummyDevice != null)
            {
                if (!dummyDevice.HasCassette)
                {
                    Stop($"{_targetDummy} dose not have cassette");
                    return false;
                }
                WaferInfo[] waferInfos = WaferManager.Instance.GetWafers(_targetDummy);
                if(waferInfos.Length > 0)
                {
                    _dummySlotNumber = waferInfos.Length;
                    foreach (var item in waferInfos)
                    {
                        if (item != null && !item.IsEmpty)
                        {
                            Stop($"There are wafers inside the {_targetDummy},cannot do the RobotCycle action");
                            return false;
                        }
                    }
                }
                
            }
            return true;
        }

        private Loadport GetLoadPort(ModuleName station)
        {
            LoadPortModule loadPortModule = Singleton<RouteManager>.Instance.EFEM.GetLoadportModule(station - ModuleName.LP1);
            return loadPortModule.LPDevice;
        }

        private bool CheckRoutineStopStatus(IRoutine routine, string error)
        {
            bool result = CommonFunction.CheckRoutineStopState(routine);
            if (result)
            {
                Stop( $"{error}");
            }
            return result;
        }
        //更新取放dummy的位置
        private bool UpdateMoveItem()
        {
            if (_lpWaferIndex.Count > 0)
            {
                _lpToAlignerMoveItem.Peek().SourceSlot = _lpWaferIndex.Dequeue(); //更新从LP取片的位置
                if (_targetDummy != ModuleName.Unknown)
                {
                    _alignerToDummyMoveItem.Peek().DestinationSlot = (_alignerToDummyMoveItem.Peek().DestinationSlot + 1) % _dummySlotNumber; //更新放到Dummy的位置
                    _dummyToLpMoveItem.Peek().SourceSlot = (_dummyToLpMoveItem.Peek().SourceSlot + 1) % _dummySlotNumber; //更新从dummy取片的位置,送回LP
                    _dummyToSrdMoveItem.Peek().SourceSlot = (_dummyToSrdMoveItem.Peek().SourceSlot + 1) % _dummySlotNumber;//更新从dummy取片的位置,送到Srd
                }
                _dummyToLpMoveItem.Peek().DestinationSlot = _lpToAlignerMoveItem.Peek().SourceSlot;//更新从dummy放回LP的位置。 
                _srdToLpMoveItem.Peek().DestinationSlot = _lpToAlignerMoveItem.Peek().SourceSlot;//更新从srd放回LP的位置。 
            }
            return true;
        }
        //清除MoveItem
        private bool ClearMoveItem()
        {
            _lpToAlignerMoveItem.Clear();
            _alignerToDummyMoveItem.Clear();
            _alignerToSrdMoveItem.Clear();
            _dummyToLpMoveItem.Clear();
            _dummyToSrdMoveItem.Clear();
            _srdToLpMoveItem.Clear();
            return true;
        }


        #endregion
    }
}