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

using miew.Tokenization;
using miew.Debugging;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// base class for (also nested) Derived and Completed passive chart edges. This associaties a TFS with the parsing
	/// activities coordinated by a ParseControl instance
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract partial class PassiveEdge : ArrayTfs, IParseObj
	{
		public PassiveEdge(ParseControl ctrl, Span sp, Entry license, Tfs tfs)
			: base(tfs)
		{
			this.ctrl = ctrl;
			this.span = sp;
			this.license = license;
		}

		public ParseControl ctrl;

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// ITokenSpan, ICharacterSpan
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		Span span;
		public Span TokenSpan { get { return span; } }
		public Span CharacterSpan { get { throw new NotImplementedException(); } }
		public String Text { get { return ctrl.ts_input.Source.MinimalSpanText(span); } }

		public bool IsEntireSpan { get { return TokenSpan.Equals(ctrl.chart.EntireSpan); } }

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// IParseObj
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		Entry license;
		List<IParseObj> packed_edges;

		public Entry License { get { return license; } }

		public Tfs Tfs { get { return this; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public abstract IList<IDerivation> Derivations { get; }

		public int deleted = 0;
		public
		IParseObj m_next;
		public IParseObj Next { get { return m_next; } }
		public bool TrySetTail(IParseObj po)
		{
			return Interlocked.CompareExchange(ref m_next, po, null) == null;
		}
		public bool TrySetNext(IParseObj po_to_set, IParseObj po_expected)
		{
			return Interlocked.CompareExchange(ref m_next, po_to_set, po_expected) == po_expected;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public void HoistPackingFrom(PassiveEdge pe_old)
		{
			var _old = pe_old.packed_edges;
			if (_old != null)
			{
				pe_old.packed_edges = null;
				if (packed_edges == null)
					packed_edges = _old;
				else
					packed_edges.AddRange(_old);
#if false
				PassiveEdge[] defer = null;
				int _tmp, c = 0;
				foreach (PassiveEdge hoist in _old)
				{
					if ((_tmp = hoist.TryTransact()) == SequenceControl.ACTIVE)
						hoist.s_state = SequenceControl.HOLD;
					else if ((_tmp & SequenceControl.stb_Blocked) > 0)
						(defer = defer ?? new PassiveEdge[_old.Count])[c++] = hoist;
				}

				if (defer != null)
				{
					Console.WriteLine("yabba");
					Environment.Exit(0);
					int i = -1, rem = c;
					do
					{
						do
							if (++i == c)
								i = 0;
						while (defer[i] == null);

						if ((_tmp = defer[i].TryTransact()) == SequenceControl.ACTIVE)
							defer[i].SetStateRaw(SequenceControl.HOLD);
						else if ((_tmp & SequenceControl.stb_Blocked) > 0)
							continue;
						defer[i] = null;
					}
					while (--rem > 0);
				}
#else
				foreach (PassiveEdge hoist in _old)
					if (hoist.BeginTransact())
						hoist.s_state = SequenceControl.HOLD;
#endif
			}
			else
			{
				if (packed_edges == null)
					packed_edges = new List<IParseObj>(12);
			}

			packed_edges.Add(pe_old);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		protected IEnumerable<IDerivation> _peer_packed()
		{
			Debug.Assert(ctrl.f_parse_phase_complete);
			Debug.Assert(this.IsActive());	/// ok because parse phase should be complete
#if false

			if (packed_edges != null)
				foreach (IParseObj parseobj in packed_edges)
				{
					if (parseobj.IsRemove())
						continue;
#if DEBUG
					var pt = parseobj as PassiveEdge;
					if (pt != null && pt.packed_edges != null)
						throw new Exception();
#endif

					foreach (IDerivation tree in parseobj.Derivations)
						yield return tree;
				}

#else
			return packed_edges == null ?
						Derived.NoDerivations :
						packed_edges.Where(ce => !ce.IsRemove()).SelectMany(ce => ce.Derivations);
#endif
		}


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// IAtomicallySequenceable
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		int i_seq;
		public int SequenceId { get { return i_seq; } }
		public void SetSequenceId(int id) { i_seq = id; }

		int s_state;
		public int State { get { return s_state; } }
		public void SetStateRaw(int s) { s_state = s; }

		public bool BeginTransact()
		{
			if ((s_state & (SequenceControl.stb_Hold | SequenceControl.stb_Remove)) > 0)
				return false;
			SpinWait sw = new SpinWait();
			while (true)
			{
				int q = Interlocked.CompareExchange(ref s_state, SequenceControl.TRANSACT, SequenceControl.ACTIVE);
				if (q == SequenceControl.ACTIVE)
					return true;
				if ((q & (SequenceControl.stb_Hold | SequenceControl.stb_Remove)) > 0)
					return false;
				sw.SpinOnce();
				//Thread.Yield();
			}
		}

		/// <summary>
		/// returns:
		/// 'SequenceControl.ACTIVE' if the transaction is started
		/// </summary>
		/// <returns></returns>
		public int TryTransact()
		{
			int _tmp = s_state;
			if ((_tmp & (SequenceControl.stb_Hold | SequenceControl.stb_Remove)) > 0)
				return _tmp;
			return Interlocked.CompareExchange(ref s_state, SequenceControl.TRANSACT, SequenceControl.ACTIVE);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// ISysObj
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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