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

using miew.ReadOnly;
using miew.Enumerable;
using miew.String;
using miew.Tokenization;
using miew.Debugging;

namespace agree
{
	public abstract partial class PassiveEdge : ArrayTfs, IParseObj
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public struct ParseObjs : IReadOnlyCollection<IParseObj>
		{
			readonly int c_args;
			readonly IParseObj ce0, ce1, ce2, ce3;

			public ParseObjs(IParseObj ce0)
			{
				this.c_args = 1;
				this.ce0 = ce0;
				ce1 = ce2 = ce3 = null;
			}
			public ParseObjs(IParseObj prepend, ParseObjs po)
			{
				this.c_args = po.Count + 1;
				this.ce0 = prepend;
				this.ce1 = po.ce0;
				this.ce2 = po.ce1;
				this.ce3 = po.ce2;
			}
			public ParseObjs(ParseObjs po, IParseObj append)
			{
				this = po;
				if (c_args == 0) ce0 = append;
				else if (c_args == 1) ce1 = append;
				else if (c_args == 2) ce2 = append;
				else if (c_args == 3) ce3 = append;
				this.c_args++;
			}

			public IParseObj this[int ix]
			{
				get
				{
					if (ix >= c_args)
						throw new IndexOutOfRangeException();
					return ix == 0 ? ce0 : ix == 1 ? ce1 : ix == 2 ? ce2 : ce3;
				}
			}

			/// <summary>
			/// 'true' if any (one or more) of the objects in this array are pending, on packing hold, or defunct
			/// </summary>
			public bool AnyInactive
			{
				get
				{
					if (ce0 == null) return false; if (ce0.IsHoldOrRemove()) return true;
					if (ce1 == null) return false; if (ce1.IsHoldOrRemove()) return true;
					if (ce2 == null) return false; if (ce2.IsHoldOrRemove()) return true;
					return ce3 != null && ce3.IsHoldOrRemove();
				}
			}
			public bool AnyDefunct
			{
				get
				{
					if (ce0 == null) return false; if (ce0.IsRemove()) return true;
					if (ce1 == null) return false; if (ce1.IsRemove()) return true;
					if (ce2 == null) return false; if (ce2.IsRemove()) return true;
					return ce3 != null && ce3.IsRemove();
				}
			}

			public int Count { get { return c_args; } }

			public bool Contains(IParseObj item) { return IndexOf(item) != -1; }

			public int IndexOf(IParseObj po) { return po == ce0 ? 0 : po == ce1 ? 1 : po == ce2 ? 2 : po == ce3 ? 3 : -1; }

			IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

			public IEnumerator<IParseObj> GetEnumerator()
			{
				if (ce0 == null) yield break; yield return ce0;
				if (ce1 == null) yield break; yield return ce1;
				if (ce2 == null) yield break; yield return ce2;
				if (ce3 == null) yield break; yield return ce3;
			}

			public void CopyTo(IParseObj[] array, int arrayIndex)
			{
				for (int i = 0; i < c_args; i++)
					array[arrayIndex++] = this[i];
			}

			public IParseObj First { get { return ce0; } }

			public IParseObj Last { get { return ce3 ?? ce2 ?? ce1 ?? ce0; } }

			public Span Span
			{
				get { return new Span(ce0.TokenSpan.StartIndex, (ce3 ?? ce2 ?? ce1 ?? ce0).TokenSpan.EndIndex); }
			}
		};
	};
}