using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore.Interlock.Actions;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.RT.Core.IoProviders;

namespace Aitex.Core.RT.IOCore.Interlock
{
	/// <summary>
	/// 互锁管理器。
	/// <remarks>
	/// 互锁管理器作为独立工作的设备，被系统的后台循环调度。
	/// <br/>
	/// 当监测到某个InterlockLimit被触发时，和该Limit相关的所有Action中定义的DO均被
	/// 置为Action节点Value属性中定义电平的反向电平。
	/// </remarks>
	/// </summary>
	public class InterlockManager : InterlockManagerBase<InterlockAction>
	{
        #region Variables
        
        /// <summary>
        /// 以Module为单位，当设置该Module所属的DO并触发互锁时，是否输出Info而不是Warning。
        /// </summary>
        private Dictionary<ModuleName, bool> _dicModulePostInfo;
        
        #endregion

        #region Constructors

        /// <summary>
        /// 互锁管理器的构造函数。
        /// </summary>
        public InterlockManager()
        {
	        RootNodeName = "Interlock";
            _dicModulePostInfo = new();
        }

        #endregion

        #region Methods

        /// <summary>
        /// 初始化互锁管理器。
        /// </summary>
        /// <param name="configFie">互锁配置文件。</param>
        /// <param name="ioManager">点表。</param>ioManager
        /// <returns></returns>
        public override void Initialize(string configFie, IIoBuffer ioManager)
        {
	        base.Initialize(configFie, ioManager);

            _dicModulePostInfo = _dictINTLKActionsPerModule?.Keys.ToDictionary(x => x, x => false) ?? new();
        }

        /// <summary>
        /// 背景扫描线程执行的任务。
        /// </summary>
        public override void Monitor()
        {
	        // 按Module扫描Interlock Limit
	        foreach (var moduleName in _dictINTLKActionsPerModule.Keys.ToList())
	        {
		        Debug.Assert(moduleName != ModuleName.UnDefined,
			        $"Interlock Manager CanSetDo() undesired module name {ModuleName.UnDefined}");
		        
		        // 检查当前Module是否旁路Interlock
		        var isBypassInterlock = GetScBypassInterlockValue(moduleName);
		        if (isBypassInterlock)
			        continue;
                
		        foreach (var limit in  _dictLIMTPerModule[moduleName].ToList())
		        {

			        // 如果互锁没被触发
			        if (!limit.IsTriggered())
				        continue;

			        var reverseInfo = new StringBuilder();
			        var module = "System";

                    if (!_dictLIMT2INTLKActionMap.ContainsKey(limit))//新增判断集合中是否包含，防止异常报错
                        continue;

                    var actions = _dictLIMT2INTLKActionMap[limit].ToList();
			        foreach (var action in actions)
			        {
				        // 尝试根据Action定义复位该互锁限制条件对应的所有DO的电平
				        if (((InterlockAction)action).TryReverse(out var reason))
				        {
					        var ss = action.ActionName.Split('.');
					        if (ss.Length > 1 && ModuleHelper.IsPm(ss[0]))
						        module = ss[0];

					        reverseInfo.AppendLine(reason);
				        }
			        }

			        // 如果PM腔有被恢复的DO，则打印信息并报警。
			        if (reverseInfo.Length > 0)
			        {
				        reverseInfo.Insert(0,
					        $"Due to the {limit.Tip}, {limit.Description} is not [{limit.GetLimitValue()}]\r\n");

				        // Post事件的类型， Info还是Warning
				        _dicModulePostInfo.TryGetValue(moduleName, out var isPostInfo);

				        if (isPostInfo)
					        EV.PostInfoLog(module, reverseInfo.ToString().TrimEnd('\r', '\n'));
				        else
					        EV.PostWarningLog(module, reverseInfo.ToString().TrimEnd('\r', '\n'));
			        }
		        }

	        }
        }

        /// <summary>
        /// 设置指定Module的Interlock打印信息等级。
        /// </summary>
        /// <param name="module">模组名称</param>
        /// <param name="isPostInfo">是否以Info等级打印信息</param>
        public void SetEventLevel(string module, bool isPostInfo)
        {
	        var moduleName = ModuleHelper.Converter(module);
	        if (_dicModulePostInfo.ContainsKey(moduleName))
		        _dicModulePostInfo[moduleName] = isPostInfo;
        }

        /// <summary>
		/// 对指定的DO的操作是否满足互锁条件。
		/// </summary>
		/// <param name="doName">待操作的DO名称。</param>
		/// <param name="onOff">
		/// 指定的输出。
		/// <value>True：输出有效电平</value>
		/// <br/>
		/// <value>False：清除有效电平输出</value>
		/// </param>
		/// <param name="reason">
		/// 如果触发互锁限制，输出互锁限制的原因。
		/// </param>
		/// <returns></returns>
		public bool CanSetDo(string doName, bool onOff, out string reason)
		{
			reason = string.Empty;

			var moduleName = GetModuleFromIo(doName);
            
			Debug.Assert(moduleName != ModuleName.UnDefined,
				$"Interlock Manager CanSetDo() undesired module name {ModuleName.UnDefined}");

			var isBypassInterlock = GetScBypassInterlockValue(moduleName);
			if (isBypassInterlock)
				return true;

            if (_dictINTLKActionsFileLoader.TryGetValue((doName, onOff), out var ilAction))
			{
                if(!ilAction.CanDo(out reason))
				{
					return false;
				}
            }
            
			/*
			foreach (var action in _lstActions.Where(action => action.IsSame(doName, onOff)))
            {
                return action.CanDo(out reason);
            }
            */

			return true;
		}
        
        /// <summary>
        /// 获取系统配置中指定Module的ByPassInterlock参数设置值。
        /// </summary>
        /// <param name="module">
        /// 模组名称, <see cref="ModuleName"/>
        /// </param>
        /// <returns></returns>
        public static bool GetScBypassInterlockValue(ModuleName module)
        {
	        return GetScBypassInterlockValue(module.ToString());
        }
        
        
        /// <summary>
        /// 获取系统配置中指定Module的ByPassInterlock参数设置值。
        /// </summary>
        /// <param name="module">模组名称</param>
        /// <returns></returns>
        public static bool GetScBypassInterlockValue(string module)
        {
	        if (ModuleHelper.IsPm(module))
		        return SC.SafeGetValue($"PM.{module}.BypassInterlock", false);
	        else
		        return SC.SafeGetValue($"{module}.BypassInterlock", false);
        }
        
		#endregion
	}
}
