using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using miew.Debugging;
using miew.Enumerable;
using miew.String;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract partial class Tfs : ISysObj
	{
		///this was DEBUG code... generally do not use
		public bool GetEdgeAtPath(Edge e_start, FsPath p, out Edge e)
		{
			e = e_start;
			foreach (String f in p)
			{
				int i_feat = tm.GetFeatureIndex(f);
				if (i_feat == -1 || !TryGetEdge(i_feat, e.Mark, out e))
					return false;
			}
			return true;
		}
		public Edge GetEdgeAtPath(String p)
		{
			Edge e;
			GetEdgeAtPath(Edge, new FsPath(p), out e);
			return e;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public bool GetEdgeAtPath(Edge e_start, FsPath p, out ConstraintRef cref)
		{
			if (p.Count == 0)
			{
				cref = default(ConstraintRef);
				return false;
			}
			Edge e = e_start;
			Edge e_prev;
			for (int i = 0; ; )
			{
				e_prev = e;
				int i_feat = tm.GetFeatureIndex(p[i]);
				if (i_feat == -1 || !TryGetEdge(i_feat, e.Mark, out e))
				{
					cref = default(ConstraintRef);
					return false;
				}
				i++;
				if (i == p.Count)
				{
					cref = new ConstraintRef(this, e_prev, i_feat);
					return true;
				}
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<Edge> GetListEdges(Edge e)
		{
			/// e.Type must unify down to tt_list_parent, but we don't need to check this separately because the ListHead pool 
			/// is only appropriate for types that are lists, so the Mark won't be found if e.Type is not a list.
			Edge lh_edge;
			while (TryGetEdge(tm.f_ix_list_head, e.Mark, out lh_edge))
			{
				yield return lh_edge;

				if (!TryGetEdge(tm.f_ix_list_tail, e.Mark, out e) || e.Mark == 0)
					yield break;
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<PathEdge> GetListPathEdges(Edge e)
		{
			/// e.Type must unify down to tt_list_parent, but we don't need to check this separately because the ListHead pool 
			/// is only appropriate for types that are lists, so the Mark won't be found if e.Type is not a list.
			Edge lh_edge;
			List<int> fix_path = new List<int>(4);
			while (TryGetEdge(tm.f_ix_list_head, e.Mark, out lh_edge))
			{
				fix_path.Add(tm.f_ix_list_head);
				yield return new PathEdge(fix_path, lh_edge);

				fix_path[fix_path.Count - 1] = tm.f_ix_list_tail;
				if (!TryGetEdge(tm.f_ix_list_tail, e.Mark, out e) || e.Mark == 0)
					yield break;
			}
		}

#if false
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<TfsSection> GetSectionsFromPathToList(TypeMgrCompiledFsPath p)
		{
			List<ConstraintRef> path_to_list = p.WalkPath(this).ToList();

			foreach (Edge e in GetListEdges(path_to_list[path_to_list.Count - 1].Constraint))
			{
				TfsSection ts = new TfsSection(this, e);

				yield return ts;
			}
		}
#endif

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<ConstraintRef> GetListConstraintRefs(Edge e)
		{
			Edge lh_edge;
			while (TryGetEdge(tm.f_ix_list_head, e.Mark, out lh_edge))
			{
				yield return new ConstraintRef(this, e, tm.f_ix_list_head);

				if (!TryGetEdge(tm.f_ix_list_tail, e.Mark, out e))
					yield break;
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<ConstraintRef> GetDiffListLists(Edge e)
		{
			Edge ll_edge;
			if (!TryGetEdge(tm.f_ix_dlist_list, e.Mark, out ll_edge))
				yield break;
			foreach (ConstraintRef cr in GetListConstraintRefs(ll_edge))
				yield return cr;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<FeatMark> AllFeatMarks(Edge e)
		{
			return e.Mark != 0 ?
						tm.rgrgfix_by_type[(int)(e.FlagsId & Edge.Flag.MultiIdMask)].Select(fix => new FeatMark(fix, e.Mark)) :
						Enumerable.Empty<FeatMark>();
		}


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IEnumerable<int> AllPools
		{
			get
			{
				Debug.Assert(Edge.Mark != 0);
				return tm.rgrgfix_by_type[(int)(Edge.FlagsId & Edge.Flag.MultiIdMask)];
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<int> ConstrainedPoolsOnly()
		{
			Debug.Assert(Edge.Mark != 0);
			int m = Edge.Mark;
			if (m != 0)
			{
				foreach (int i_feat in tm.rgrgfix_by_type[(int)(Edge.FlagsId & Edge.Flag.MultiIdMask)])
					if (ContainsFeatMark(i_feat, m))
						yield return i_feat;
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<int> ConstrainedPoolsOnly(Edge e)
		{
			if (e.Mark != 0)
				foreach (int i_feat in tm.rgrgfix_by_type[(int)(e.FlagsId & Edge.Flag.MultiIdMask)])
					if (ContainsFeatMark(i_feat, e.Mark))
						yield return i_feat;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<ConstraintRef> AllConstraintRefs(Edge e)
		{
			if (e.Mark != 0)
				foreach (int i_feat in tm.rgrgfix_by_type[(int)(e.FlagsId & Edge.Flag.MultiIdMask)])
					yield return new ConstraintRef(this, e, i_feat);
		}


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public IEnumerable<ConstraintRef> ConstrainedRefsOnly(Edge e)
		{
			if (e.Mark != 0)
				foreach (int i_feat in tm.rgrgfix_by_type[(int)(e.FlagsId & Edge.Flag.MultiIdMask)])
					if (ContainsFeatMark(i_feat, e.Mark))
						yield return new ConstraintRef(this, e, i_feat);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Includes coreferences, of course
		/// Constrained means it is has at least one non-top or coreferenced feature. We count on the fact that such edges are 
		/// always vacant from the constraint pool
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public int ConstrainedFeaturesCount(Edge e)
		{
			int c = 0;
			if (e.Mark != 0)
				foreach (int i_feat in tm.rgrgfix_by_type[(int)(e.FlagsId & Edge.Flag.MultiIdMask)])
					if (ContainsFeatMark(i_feat, e.Mark))
						c++;
			return c;
		}
	};
}