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

using miew.ReadOnly;
using miew.Enumerable;
using miew.Debugging;
using miew.BitArray;

namespace agree
{
	public abstract partial class PassiveEdge : ArrayTfs, IParseObj
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// </summary>
		/// <remarks>
		/// initial lexical edges are now directly (polymorphically) introduced into the chart as AnalysisStack objects via 
		/// their implementation of the IParseObj interface
		/// </remarks>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerDisplay("{ToString(),nq}")]
		public partial class Derived : PassiveEdge
		{
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			ParseObjs rgo;

			public Derived(ParseControl ctrl, GrammarRule rule, Tfs tfs, ref ParseObjs rgo)
				: base(ctrl, rgo.Span, rule, tfs)
			{
				this.rgo = rgo;
		//		this.m_dseq = -1;

				ctrl.stats.Parsing.Chart.PassiveEdge();
			}

//			public int m_dseq;

	//		public static int qc = 0;

#if false
			public void DirectCancel()
			{
				int _tmp = ctrl.chart.g_dseq;
				if (Interlocked.Exchange(ref m_dseq, _tmp) == _tmp)
					return;

				for (int j = 0; j < rgo.Count; j++)
				{
					Derived dtr = rgo[j] as Derived;
					if (dtr != null)
					{
						if (dtr.IsHold())
							dtr.DirectCancel();
						else if (!dtr.IsRemove())
							continue;
						this.s_state = SequenceControl.REMOVE;
						Interlocked.Increment(ref qc);
						break;
					}
				}
			}
#endif

			public ParseObjs ChartDaughters { get { return rgo; } }

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public IEnumerable<IParseObj> Descendants
			{
				get
				{
					Derived dpe;
					foreach (IParseObj ipce in rgo)
					{
						yield return ipce;
						if ((dpe = ipce as Derived) != null)
							foreach (IParseObj ipce_d in dpe.Descendants)
								yield return ipce_d;
					}
				}
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public IEnumerable<IParseObj> DescendantsAndSelf
			{
				get
				{
					yield return this;
					foreach (IParseObj ipce in Descendants)
						yield return ipce;
				}
			}

			/// <summary>
			/// when initiated with 'i_arg==0', enumerates the fixed-arity cross product of the packed trees 
			/// across each of this edge's chart daughters
			/// </summary>
			IEnumerable<IEnumerable<IDerivation>> _rightwards(int i_arg)
			{
				Debug.Assert(!this.IsRemove());
				IParseObj unary = rgo[i_arg];
				Debug.Assert(unary.IsActive());

				foreach (var d in unary.Derivations)
				{
					if (i_arg == rgo.Count - 1)
						yield return new IDerivation[] { d };
					else
					{
						IParseObj po = rgo[i_arg + 1];
						if (po.IsActive())
							foreach (var tree_xp in _rightwards(i_arg + 1))
								yield return tree_xp.Prepend(d);
					}
				}
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			IEnumerable<IDerivation> _packed_trees
			{
				get
				{
					Debug.Assert(!this.IsRemove());

					/// trees postulated by the cross product of this item's daughters...
					if (rgo[0].IsActive())
					{
						if (rgo.Count == 1)
							foreach (var e in rgo[0].Derivations)
								yield return new ParseTree(this.ctrl, this, new IDerivation[] { e });
						else
							foreach (var e in _rightwards(0))
								yield return new ParseTree(this.ctrl, this, e);
					}

					/// ...plus subsumed structures packed into this item itself (and their subsumptions...)
					if (this.IsActive())
						foreach (var e in _peer_packed())
							yield return e;
				}
			}

			static public readonly IDerivation[] NoDerivations = new IDerivation[0];

			/// <summary>
			/// exhaustive unpacking of trees which are packed into this item with thread-safe cache
			/// </summary>
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			IDerivation[] _parse_trees = null;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public override IList<IDerivation> Derivations
			{
				get
				{
					Debug.Assert(!this.IsRemove());
					Debug.Assert(ctrl.f_parse_phase_complete);

					IDerivation[] _tmp;
					return _parse_trees ??
							Interlocked.CompareExchange(ref _parse_trees, _tmp = _packed_trees.ToArray(), null) ??
							_tmp;
				}
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override string ToString()
			{
				return String.Format("{0} {1}", TokenSpan, base.ToString());
			}
		};

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// a derived passive chart edge which has been matched against one or more start symbols
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public class Completed : Derived
		{
			static bool[][] singleton_maps;

			static bool[] GetSingletonMap(ParseControl ctrl, int i_ss)
			{
				if (singleton_maps == null)
					Interlocked.CompareExchange(ref singleton_maps, new bool[ctrl.g.StartSymbols.Length][], null);

				bool[] _tmp = singleton_maps[i_ss];
				if (_tmp == null)
				{
					_tmp = new bool[i_ss + 1];
					_tmp[i_ss] = true;
					singleton_maps[i_ss] = _tmp;
				}
				return _tmp;
			}

			readonly bool[] start_symbol_map;

			public Completed(ParseControl ctrl,
									GrammarRule rule,
									Tfs tfs,
									bool[] rgss_map,
									ref ParseObjs rgo)
				: base(ctrl, rule, tfs, ref rgo)
			{
				this.start_symbol_map = rgss_map;
				ctrl.chart._completed_edges.Add(this);
				ctrl.stats.Parsing.Chart.RootEdge();
			}

			public Completed(ParseControl ctrl,
									GrammarRule rule,
									Tfs tfs,
									int i_ss,
									ref ParseObjs rgo)
				: this(ctrl, rule, tfs, GetSingletonMap(ctrl, i_ss), ref rgo)
			{
			}

			public bool[] MatchedStartSymbolsMap { get { return start_symbol_map; } }

			public IEnumerable<StartSymbol> MatchedStartSymbols
			{
				get
				{
					for (int i = 0; i < start_symbol_map.Length; i++)
						if (start_symbol_map[i])
							yield return ctrl.g.StartSymbols[i];
				}
			}

			public new String SysObjName
			{
				get { return String.Format("parse{0}", i_seq >> 1); }
			}

			public new ISysObj SysObjParent
			{
				get { return ctrl; }
			}

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

			//public string SysObjDescription
			//{
			//    get { return String.Format("{0} ({1})", License != null ? License.SysObjName : "null license", start_symbol.SysObjName); }
			//}
		}
	};
}