using System.Collections.Generic;
using System.Linq;
using System.Text;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;

namespace Aitex.Core.RT.IOCore.Interlock.Actions;

public class InterlockDaemonAction : InterlockActionBase
{
	#region Variables

	private readonly R_TRIG _rTrigSetDoFailed = new();

	#endregion
	
	#region Constructors

	public InterlockDaemonAction(string module, DOAccessor doItem, bool value, string tip, Dictionary<string, string> cultureTip)
	: base(module, doItem, value, tip, cultureTip)
    {
	}

	#endregion
    
    #region Methods
    
	/// <summary>
	/// 扫描当前动作的条件，并设置相关DO的输出状态。
	/// </summary>
	public override void Monitor()
	{
		var info = new StringBuilder();

		// 检查所有的Limit是否满足要求
		foreach (var limit in Limits)
		{
			if (!limit.CanDo(out _))
				return;

			info.AppendLine($"{limit.DaemonReason}");
		}
			
		// 扫描OR定义的Limit组，每个组中只要有一个Limit命中，则继续测试下个OR组；否则直接退出。
		foreach (var group in LogicOrGroups)
		{
			var hitLimit = group.FirstOrDefault(limit => limit.CanDo(out _));
			if (hitLimit == null) // 当前OR组中没用命中的Limit，退出Monitor
				return;

			info.AppendLine($"{hitLimit.DaemonReason}");
		}

		// 如果DO输出已经满足要求，则直接退出
		if (_do.Value == _actionValue)
			return;

		// 所有的Limit和OR逻辑组均命中
		var succeeded = _do.SetValue(_actionValue, out var reason);
		_rTrigSetDoFailed.CLK = !succeeded;
		if (succeeded)
		{
			info.Insert(0,
				$"Interlock Daemon Force set DO-{_do.IoTableIndex}({_do.Name}) = [{((_actionValue) ? "ON" : "OFF")}] Due to\r\n");
			
			EV.PostInfoLog( _module, info.ToString().TrimEnd('\r', '\n'));

			_rTrigSetDoFailed.CLK = false;
		}
		else if(_rTrigSetDoFailed.Q)
		{
			// 第一次Set DO错误时打印日志
			LOG.Error($"Interlock Daemon set {_do.Name} failed, {reason}");
		}
	}
    
	#endregion
}

