using System;
using System.Collections.Generic;
using System.Linq;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;

namespace MECF.Framework.Common.Fsm
{
	/// <summary>
	/// 应用于构建模组（Module）状态机的对象。
	/// </summary>
	/// <remarks>
	/// 模组（Module）在系统中为一类控制单元，对应硬件系统的控制单元。
	/// <br/>
	/// 通常一个模组包含一组设备（Device），并通过Routine提供具有原子性的各种操作。
	/// 设备整机有不同的模组构成，并通过调用模组下的Routine完成各个功能动作。
	/// 关于Routine的细节，请参考<see cref="ModuleRoutine"/>对象。
	/// <br/>
	/// 模组基于有限状态机（FSM）进行工作，模组实例化时构建了状态转换表；各个动作基于状态转化完成；
	/// 状态机模型有效的控制模组的工作状态，有助于构建健壮的、稳定的系统架构。
	/// </remarks>
	public class ModuleFsmDevice : FsmDevice
	{
        #region Variables

        /// <summary>
        /// 当模组发生异常时触发此事件。
        /// </summary>
        /// <remarks>
        /// 通常情况下，当该事件引发时，会向状态机发送Error或Alarm消息，以使状态机转换到Error或Alarm状态。
        /// </remarks>
        public event EventHandler<string> OnEnterError;

        private readonly Queue<IRoutine> _qRoutines;

		#endregion

        #region Constructors

		/// <summary>
		/// 创建模组的对象实例。
		/// </summary>
		public ModuleFsmDevice()
        {
            _qRoutines = new Queue<IRoutine>();
        }

		#endregion

        #region Properties

		/// <summary>
		/// 返回当前模组是否在系统配置中启用。
		/// </summary>
		public bool IsInstalled
		{
			get
			{
				if (!SC.ContainsItem("System.SetUp.Is" + base.Module + "Installed"))
				{
					return true;
				}
				return SC.GetValue<bool>("System.SetUp.Is" + base.Module + "Installed");
			}
		}

		/// <summary>
		/// 设置或返回当前模组是否上线。
		/// </summary>
		public bool IsOnline { get; set; }

		/// <summary>
		/// 返回当前设备正在执行的Routine的列队。
		/// </summary>
		protected Queue<IRoutine> QueueRoutine => _qRoutines;

		#endregion

        #region Methods

		/// <summary>
		/// 初始化模组。
		/// </summary>
		/// <returns></returns>
		public override bool Initialize()
		{
            return base.Initialize();
		}

		/// <summary>
		/// 使用指定的参数启动Routine。
		/// </summary>
		/// <param name="routine">Routine对象的实例。</param>
		/// <param name="args">
		/// Routine的启动参数。
		/// <remarks>
		/// 该参数表会传递给Routine的Start()方法。
		/// </remarks>
		/// </param>
		/// <returns>
		/// <see cref="Result"/>
		/// <br/>
		/// Routine的执行状态。</returns>
		public Result StartRoutine(IRoutine routine, params object[] args)
		{
			QueueRoutine.Clear();
			QueueRoutine.Enqueue(routine);
			return QueueRoutine.Peek().Start(args);
		}

        /// <summary>
        /// 启动指定的Routine。
        /// </summary>
        /// <param name="routine">Routine对象的实例。</param>
        /// <returns>
        /// <see cref="Result"/>
        /// <br/>
        /// Routine的执行状态。</returns>
        public Result StartRoutine(IRoutine routine)
		{
			QueueRoutine.Clear();
			QueueRoutine.Enqueue(routine);
			return QueueRoutine.Peek().Start();
		}

        /// <summary>
        /// 启动列队中的Routine。
        /// </summary>
        /// <remarks>
        /// 需要将待执行的Routine添加到<see cref="QueueRoutine"/>队列中。
        /// </remarks>
        /// <returns>
        /// <see cref="Result"/>
        /// <br/>
        /// Routine的执行状态。
        /// </returns>
        public Result StartRoutine()
		{
			if (_qRoutines.Count == 0)
			{
				return Result.DONE;
			}
			var result = Result.DONE;
			var list = _qRoutines.ToList();
			for (int i = 0; i < list.Count; _qRoutines.Dequeue(), i++)
			{
				switch (list[i].Start())
				{
				case Result.DONE:
					continue;
				case Result.FAIL:
					return Result.FAIL;
				}
				break;
			}
			return Result.RUN;
		}

        /// <summary>
        /// 周期性扫描正在执行的Routine。
        /// </summary>
        /// <returns>
        /// <see cref="Result"/>
        /// <br/>
        /// Routine的执行状态。
        /// </returns>
        public Result MonitorRoutine()
		{
			if (_qRoutines.Count == 0)
			{
				return Result.DONE;
			}
			var routine = _qRoutines.Peek();
			var result = routine.Monitor();
			if (result == Result.DONE)
			{
				_qRoutines.Dequeue();
				var list = _qRoutines.ToList();
				for (var i = 0; i < list.Count; _qRoutines.Dequeue(), i++)
				{
					result = list[i].Start();
					switch (result)
					{
					case Result.DONE:
						continue;
					case Result.FAIL:
						return Result.FAIL;
					}
					break;
				}
			}
			return result;
		}

		/// <summary>
		/// 终止当前模组的所有正在执行的Routine。
		/// </summary>
		public void AbortRoutine()
		{
			if (_qRoutines != null)
			{
				if( _qRoutines.Count > 0)
				    _qRoutines.Peek().Abort();

				_qRoutines.Clear();
			}
		}

		/// <summary>
		/// 产生模组异常事件。
		/// </summary>
		/// <param name="module"></param>
		protected virtual void InvokeOnEnterError(string module)
		{
			OnEnterError?.Invoke(this, module);
		}

        #endregion

    }
}
