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 : ISysObj
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <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)]
#if !DEBUG
			readonly
#endif
			Span span;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
#if !DEBUG
			readonly
#endif
			TfsEdge contents;
			ISysObj license;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			readonly IList<IParseChartEdge> daughters;

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

			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 TfsEdge Contents { get { return contents; } }

			public ISysObj License { get { return license; } }

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

			public void Dispose()
			{
#if DEBUG
				if (contents.Equals(default(TfsEdge)))
					throw new Exception("already released");
#endif
				contents.Dispose();
#if DEBUG
				contents = default(TfsEdge);
#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 chart;
			internal int ix = 0;
			readonly ISysObj start_symbol;

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

			public ISysObj 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 String.Format("{0} ({1})", License != null ? License.SysObjName : "null license", start_symbol.SysObjName); }
			}
		}
	};
}