using System.Collections.Generic;
using System.Diagnostics;
using Aitex.Core.Util;

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

/// <summary>
/// 互锁限制条件。
/// </summary>
public abstract class InterlockLimitBase<TAccessor, TValue> : IInterlockLimit
	where TAccessor : IInterlockLimitDataProvider
	where TValue : struct
{
	#region Variables

	private Dictionary<string, string> _cultureTip;
	private readonly R_TRIG _trigger;

    #endregion

    #region Constructor

    /// <summary>
    /// 互锁限制条件的构造函数。
    /// </summary>
    /// <param name="dataProvider">数据供应器对象实例</param>
    /// <param name="value">当前限制条件中的IO状态。</param>
    /// <param name="tip">默认语言提示信息。</param>
    /// <param name="cultureTip">多国语言提示信息。</param>
    /// <param name="ignoreReverse">是否触发Action反转</param>
    /// <exception cref="InvalidIoNameException">IO名称错误，前缀不是“DI_”、”DO_“、”AI_“或"AO_".</exception>
    protected InterlockLimitBase(IInterlockLimitDataProvider dataProvider, string value, string tip,
		Dictionary<string, string> cultureTip,bool ignoreReverse = false)
	{
		Debug.Assert(dataProvider != null, "The data provider can not be null.");
		_trigger = new R_TRIG();
		DataProvider = dataProvider;
		Tip = tip;
		_cultureTip = cultureTip;
		UniqueId = $"{dataProvider.Name}.{value}";
		IgnoreReverse = ignoreReverse;
	}

	#endregion

	#region Properties

	/// <summary>
	/// 放回当前Limit所对应的IO对象。
	/// </summary>
	protected IInterlockLimitDataProvider DataProvider { get; }

	/// <summary>
	/// 返回互锁限制条件的唯一识别码。
	/// <remarks>
	/// 该唯一识别码用于创建字典时，作为字典的Key值使用。
	/// <br/>
	/// 该值由Name+LimitValue组成。
	/// </remarks>
	/// </summary>
	public string UniqueId { get; }

    /// <summary>
    /// <inheritdoc cref="IInterlockLimit.Name"/>
    /// </summary>
    public string Name => DataProvider?.Name ?? "";

    /// <summary>
    /// <inheritdoc cref="IInterlockLimit.Description"/>
    /// </summary>
    public string Description => DataProvider?.Description ?? "";

    /// <summary>
    /// 返回当前Limit对应的数据值。
    /// </summary>
    public abstract TValue CurrentValue { get; }

	/// <summary>
	/// 返回当前互锁限制条件触发的原因。
	/// </summary>
	public abstract string LimitReason { get; }

	/// <summary>
	/// 返回守护条件满足时输出的信息。
	/// </summary>
	public abstract string DaemonReason { get; }

	/// <summary>
	/// 返回当前互锁条件的信号约束值。
	/// </summary>
	public TValue LimitValue { get; protected set; }

	/// <summary>
	/// 返回当前互锁条件提示信息。
	/// </summary>
	public string Tip { get; }

    /// <summary>
    /// 返回该Limit是否对Action进行反转
    /// </summary>
    public bool IgnoreReverse { get; }

    #endregion

    #region Methods

    /*
	/// <summary>
	/// 判断两个互锁限制条件是否相等。
	/// </summary>
	/// <param name="interlockLimit">待比较的互锁限制条件。</param>
	/// <returns>
	///	<para>True: 相同；False：不同。</para>
	/// </returns>
	public bool IsSame(object interlockLimit)
	{
		if (interlockLimit is not InterlockLimit<TAccessor, TValue> li)
			return false;
		return Name == li.Name && li.LimitValue == LimitValue;
	}*/

    /// <summary>
    /// 返回互锁限制监测的信号当前值和期望值不相等的条件是否触发。
    /// <remarks>
    /// 捕获当前值和期望值不相等信号的上升沿，当上升沿到达时触发输出Q。
    /// </remarks>
    /// </summary>
    /// <returns></returns>
    public bool IsTriggered()
	{
		_trigger.CLK = !CheckInRange();
		return _trigger.Q;
	}

	/// <summary>
	/// 根据互锁条件判断是否允许DO输出。
	/// </summary>
	/// <param name="reason">如果禁止DO输出，返回互锁原因。</param>
	/// <returns></returns>
	public bool CanDo(out string reason)
	{
		reason = string.Empty;
		if (CheckInRange())
			return true;

		reason = LimitReason;
		return false;
	}

	/// <summary>
	/// 获取指定互锁限制条件中限制条件的内容。
	/// </summary>
	/// <returns></returns>
	public virtual string GetLimitValue()
	{
		return LimitValue.ToString();
	}

	/// <summary>
	/// 获取指定互锁限制条件中当前IO状态。
	/// </summary>
	/// <returns></returns>
	public virtual string GetCurrentValue()
	{
		return CurrentValue.ToString();
	}

	/// <summary>
	/// 检查当前值是否在指定范围内。
	/// </summary>
	/// <returns>True: 在范围内； False：超出范围。</returns>
	protected abstract bool CheckInRange();

	/// <summary>
	/// <inheritdoc />
	/// </summary>
	/// <returns></returns>
	public override string ToString()
	{
		return $"{Name}, Limit={LimitValue}";
	}

	#endregion
}



