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

using glue.Collections.XSpinLock;
using glue.Collections.ReadOnly;
using glue.Extensions.Enumerable;
using glue.Tokenization;

namespace agree.Parse
{
	abstract public partial class ChartBase<T> : ISysObj where T : ChartBase<T>.IMotherDaughter, IEquatable<T>
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// </summary>
		/// <remarks>
		/// Lexical edges are now directly (polymorphically) introduced into the chart as AnalysisStack objects the initial 
		/// lexical edges via their implementation IParseChartEdge interface
		/// </remarks>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public class DerivedPassiveEdge : AtomicSequenceObject, IParseChartEdge
		{
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			readonly Span span;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
#if !DEBUG
			readonly
#endif
			T contents;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			readonly IList<IParseChartEdge> daughters;

			public DerivedPassiveEdge(ChartBase<T> chart, Span span, T contents, IList<IParseChartEdge> d)
				:base(chart.ast)
			{
				this.span = span;
				this.contents = contents;
				this.daughters = d;
			}

			public IList<IParseChartEdge> Daughters { get { return daughters; } }

			public IEnumerable<IParseChartEdge> Descendants
			{
				get
				{
					return Daughters.Concat(Daughters.OfType<DerivedPassiveEdge>().SelectMany(d => d.Descendants));
				}
			}

			public IEnumerable<IParseChartEdge> DescendantsAndSelf
			{
				get { return Descendants.Append(this); }
			}

			public T Self { get { return contents; } }

			public bool SpinCompare(T other)
			{
				return false;
			}

			public void Dispose()
			{
#if DEBUG
				if (contents.Equals(default(T)))
					throw new Exception("already released");
#endif
				contents.Dispose();
#if DEBUG
				contents = default(T);
#endif
			}

			public Span ChartSpan { get { return span; } }

			public override string ToString()
			{
				return contents.ToString();
				//return String.Format("↻{0,-3} {{{1} {2}}}", SequenceIdString, span, contents);
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public class CompletedParse : DerivedPassiveEdge, ISysObj
		{
			readonly ChartBase<T> chart;
			internal int ix = 0;
			readonly ISelf start_symbol;

			public CompletedParse(ChartBase<T> chart, Span span, T contents, IList<IParseChartEdge> d, ISelf start_symbol)
				: base(chart, span, contents, d)
			{
				this.chart = chart;
				this.start_symbol = start_symbol;
			}

			public ISelf MatchedStartSymbol { get { return start_symbol; } }

			public string SysObjName
			{
				get { return String.Format("parse{0}", ix); }
			}

			public IReadOnlyDictionary<string, ISysObj> SysObjChildren
			{
				get { return SysObjHelper<ISysObj>.Empty; }
			}

			public ISysObj SysObjParent
			{
				get { return chart; }
			}

			public string SysObjDescription
			{
				get { return "a parse"; }
			}
		}
	};
}