using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Runtime.InteropServices;

using miew.Debugging;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public interface IMotherDaughter
	{
		TfsSection[] RuleDaughters { get; }
		int KeyDaughterIndex { get; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// Caches rule daughters and arity
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public partial class MotherDaughterTfs : ArrayTfs, IMotherDaughter
	{
		public MotherDaughterTfs(Allocator ctrl,
								TargetTfs tt,
								int[] rg_feat_delete)
			: base(ctrl, tt, rg_feat_delete)
		{
		}

		unsafe public MotherDaughterTfs(Allocator ctrl,
			Edge e_top,
			arr_tfs_entry* _p_ate,
			int c,
			int next_mark,
			int next_coref_mark,
			int min_coref_in_mark,
			bool f_restricted)
			: base(ctrl, e_top, _p_ate, c, next_mark, next_coref_mark, min_coref_in_mark, f_restricted)
		{
		}

		unsafe public MotherDaughterTfs(Allocator ctrl,
			Edge e_top,
			arr_tfs_entry[] rg_ate,
			ushort[] hidx,
			ushort[] rgn,
			int next_mark,
			int next_coref_mark,
			bool f_restricted)
			: base(ctrl, e_top, rg_ate, hidx, rgn, next_mark, next_coref_mark, f_restricted)
		{
		}
		TfsSection[] daughters = null;

		int i_key_daughter = 0;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int KeyDaughterIndex
		{
			get
			{
				if (daughters == null)
					_lazy_load_rule_daughters();
				return i_key_daughter;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TfsSection[] RuleDaughters
		{
			get { return daughters ?? _lazy_load_rule_daughters(); }
		}

		public TfsSection[] _lazy_load_rule_daughters()
		{
#if false
			/// locate the daughter entry points in the expanded contents
			TfsSection[] _tmp = GetSectionsFromPathToList(tm.config.RuleArgsPath).ToArray();
#else
			/// locate the daughter entry points in the expanded contents
			var rg_lp_edges = tm.config.parser.RuleArgsPath.GetListPathEdges(this).ToArray();
			if (rg_lp_edges.Length == 0)
				throw new Exception();

			TfsSection[] _tmp = new TfsSection[rg_lp_edges.Length];
			for (int i = 0; i < rg_lp_edges.Length; i++)
				_tmp[i] = GetSection(rg_lp_edges[i], i);
#endif

			/// find the first KEY daughter, i.e. the first daughter where the type at the KEY daughter path (if
			/// specified) matches the KEY daughter type (if specified). In the absence of such a match, the
			/// parser will default to active rightwards expansion starting at daughter index 0.
			/// As noted in a comment elsewhere, the KEY daughter index remains constant for active edges derived
			/// from this rule, so we don't need to redo this during parsing; instead we can just copy this value
			/// over.

			i_key_daughter = 0;
			Type t_key = tm.tt_key_daughter;
			if (!t_key.IsTop)
			{
				for (int i = 0; i < _tmp.Length; i++)
					if (tm.config.parser.KeyDaughterPath.GetType(_tmp[i]) == t_key)
					{
						i_key_daughter = i;
						/// If multiple daughters have KEY-ARG marked, it is not clear what to do. This
						/// implementation currently elects to take the leftmost acceptable KEY:
						break;
					}
			}
			return daughters = _tmp;
		}
	};
}