using System;
using System.Collections.Generic;
using System.Diagnostics;
using Aitex.Core.RT.Event;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.SubstrateTrackings;

namespace Aitex.Core.RT.Routine
{
	public class ModuleRoutine : SeqenecRoutine
	{
        #region Variables

        public delegate RoutineState RoutineFunc<T>(T arg);

        /// <summary>
		/// 用于统计Routine耗时的计时器。
		/// </summary>
        protected readonly Stopwatch SwStatisticElapse;

        protected string _stepName;

		protected TimeSpan _stepSpan = new TimeSpan(0, 0, 0, 0);

		protected DateTime _stepStartTime;

		private static object locker = new object();

        #endregion

        #region Constuctors
        
        public ModuleRoutine(string module)
        {
	        Module = module;
            SwStatisticElapse = new Stopwatch();
        }

        #endregion

        #region Properties

        /// <summary>
		/// 返回当前Routine所述的模组
		/// </summary>
        public string Module { get; protected set; }
        
        /// <summary>
		/// 返回当前Routine的名称
		/// </summary>
        public string Name { get; protected set; }

        public string StepName => _stepName;

        public TimeSpan StepLeftTime
        {
            get
            {
                if (_stepSpan.TotalMilliseconds < 1.0)
                {
                    return _stepSpan;
                }
                return _stepSpan - (DateTime.Now - _stepStartTime);
            }
        }

        #endregion
        
        #region Methods

       
        public virtual Result Monitor()
        {
            try
            {
                MonitorBody();
            }
            catch (RoutineBreakException)
            {
                return Result.RUN;
            }
            catch (RoutineFaildException)
            {
                return Result.FAIL;
            }

            SwStatisticElapse.Stop();
            Notify($"Finished ! Elapsed time: {(int)(SwStatisticElapse.ElapsedMilliseconds / 1000)} s");
            return Result.DONE;
        }
        
        public virtual Result Start(params object[] args)
        {
            Reset();
            SwStatisticElapse.Restart();
            return StartBody(args);
        }

        public virtual void Abort()
        {
        }

        protected virtual Result StartBody(params object[] args)
        {
            return Result.RUN;
        }
        
        protected virtual void MonitorBody()
        {

        }

        protected void Notify(string message)
		{
			EV.PostInfoLog(Module, Name + ", " + message);
		}

		protected void Stop(string failReason)
		{
			EV.PostAlarmLog(Module, Name + " failed, " + failReason);
		}

		public void Abort(string failReason)
		{
			EV.PostAlarmLog(Module, Name + "  " + failReason);
		}

		public void TimeDelay(int id, string stepName, double time)
		{
			Tuple<bool, Result> tuple = Delay(id, delegate
			{
				Notify($"Delay {time} seconds");
				_stepSpan = new TimeSpan(0, 0, 0, (int)time);
				_stepStartTime = DateTime.Now;
				_stepName = stepName;
				return true;
			}, time * 1000.0);
			if (tuple.Item1 && tuple.Item2 == Result.RUN)
			{
				throw new RoutineBreakException();
			}
		}

		public void TimeDelay(int id, double time)
		{
			Tuple<bool, Result> tuple = Delay(id, delegate
			{
				Notify($"Delay {time} seconds");
				_stepSpan = new TimeSpan(0, 0, 0, (int)time);
				_stepStartTime = DateTime.Now;
				return true;
			}, time * 1000.0);
			if (tuple.Item1 && tuple.Item2 == Result.RUN)
			{
				throw new RoutineBreakException();
			}
		}

		protected void ExecuteRoutine(int id, List<(IRoutine routine, object[] args)> routines)
		{
			Tuple<bool, Result> tuple = ExecuteAndWait(id, routines);
			if (tuple.Item1)
			{
				if (tuple.Item2 == Result.FAIL)
				{
					throw new RoutineFaildException();
				}
				if (tuple.Item2 == Result.RUN)
				{
					throw new RoutineBreakException();
				}
			}
		}
		
		protected void ExecuteRoutine(int id, List<IRoutine> routines)
		{
			Tuple<bool, Result> tuple = ExecuteAndWait(id, routines);
			if (tuple.Item1)
			{
				if (tuple.Item2 == Result.FAIL)
				{
					throw new RoutineFaildException();
				}
				if (tuple.Item2 == Result.RUN)
				{
					throw new RoutineBreakException();
				}
			}
		}
		
		protected void ExecuteRoutine(int id, IRoutine routine, params object[] args)
		{
			Tuple<bool, Result> tuple = ExecuteAndWait(id, routine, args);
			if (tuple.Item1)
			{
				if (tuple.Item2 == Result.FAIL)
				{
					throw new RoutineFaildException();
				}
				if (tuple.Item2 == Result.RUN)
				{
					throw new RoutineBreakException();
				}
			}
		}

		protected void PerformStep<T, T1>(T step, RoutineFunc<T1> func, T1 param1)
		{
			int num = Convert.ToInt32(step);
			RoutineState routineState = func(param1);
		}

		public void Loop(int id, int count)
		{
			Tuple<bool, Result> tuple = Loop(id, delegate
			{
				Notify($"Start loop {base.LoopCounter + 1}/{count}");
				return true;
			}, count);
			if (tuple.Item1 && tuple.Item2 == Result.FAIL)
			{
				throw new RoutineFaildException();
			}
		}

		public void EndLoop(int id)
		{
			Tuple<bool, Result> tuple = EndLoop(id, delegate
			{
				Notify("Loop finished");
				return true;
			});
			if (tuple.Item1)
			{
				throw new RoutineBreakException();
			}
		}

		/// <summary>
		/// 转移产品。
		/// </summary>
		/// <param name="id"></param>
		/// <param name="moduleFrom"></param>
		/// <param name="slotFrom"></param>
		/// <param name="moduleTo"></param>
		/// <param name="slotTo"></param>
		/// <exception cref="RoutineFaildException"></exception>
		protected virtual void Transfer(int id, ModuleName moduleFrom, int slotFrom, ModuleName moduleTo, int slotTo)
		{
			var ret = Execute(id, () =>
			{
				Notify($"Transfer {moduleFrom}.{slotFrom} -> {moduleTo}.{slotTo}");
                // 产品到达抓取位置后，Slot0 转移到 Slot1
                WaferManager.Instance.WaferMoved(moduleFrom, slotFrom, 
					moduleTo, slotTo);
				return true;
			});
            
			if (ret.Item1)
			{
				if (ret.Item2 == Result.FAIL)
				{
					throw new RoutineFaildException();
				}
			}
		}

		
        #endregion
    }
}
