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

using miew.Debugging;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class TfsSection : Tfs
	{
		readonly public Tfs mother;
		int c_edges = -1;
		public int i_sect = -1;

		public TfsSection(Tfs mother, Edge daughter, int i_sect)
			: base(mother.tm, daughter)
		{
			this.mother = mother;
			this.i_sect = i_sect;
			this.next_mark = mother.next_mark;
			this.next_coref_mark = mother.next_coref_mark;
			//_load_coref_tally_map(false);
		}

		public TfsSection(Tfs mother, PathEdge pe, int i_sect)
			: this(mother, pe.e, i_sect)
		{
		}

		int ix_mother = -1;
		public int MotherSlotIndex
		{
			get
			{
				if (ix_mother == -1)
				{
					if (i_sect < 0 || i_sect > 1)
						throw new Exception();
					int m = mother.GetEdgeAtPath(i_sect == 0 ? "args" : "args.rest").Mark;
					ix_mother = ((MotherDaughterTfs)mother).GetEdgeIndex(tm.f_ix_list_head, ref m);
				}
				return ix_mother;
			}
		}

		public void _load_coref_tally_map()
		{
			byte[] _tmp = null;
			int c_corefs = 0;
			int max_c = mother.coref_tally_map.Length;
			if (max_c > 0 && (this.Edge.FlagsId & Edge.Flag.EtmNonBareType) != 0)
			{
				_tmp = new byte[max_c];
				EdgeCounter ec = new EdgeCounter(mother, this.Edge, _tmp);
				c_corefs = ec.ActualCount;
				c_edges = ec.EdgeCount;
			}

			if (c_corefs == 0 || _tmp == null)
			{
				_tmp = NoCorefsTallyMap;
			}
			coref_tally_map = _tmp;
		}

		public void _load_coref_tally_map_restricted()
		{
			byte[] _tmp = null;
			int c_corefs = 0;
			int max_c = mother.coref_tally_map.Length;
			if (max_c > 0 && (this.Edge.FlagsId & Edge.Flag.EtmNonBareType) != 0)
			{
				_tmp = new byte[max_c];
				EdgeCounterRestricted ec = new EdgeCounterRestricted(mother, this.Edge, _tmp);
				c_corefs = ec.ActualCount;
				c_edges = ec.EdgeCount;
			}

			if (c_corefs == 0 || _tmp == null)
			{
				_tmp = NoCorefsTallyMap;
			}
			coref_tally_map_restricted = _tmp;
		}

		public TfsEdge SectionTfsEdge { get { return new TfsEdge(mother, Edge); } }

		public bool IsSectionOf(Tfs putative) { return putative == mother; }

		public Tfs MotherTfs { get { return mother; } }

		public override void SetEdge(int i_feat, int mark, Edge e)
		{
			mother.SetEdge(i_feat, mark, e);
		}

		public override bool TryGetEdge(int i_feat, int mark, out Edge e)
		{
			return mother.TryGetEdge(i_feat, mark, out e);
		}

		public override Edge.Flag TryGetFlagsMark(int i_feat, int mark, out int m)
		{
			return mother.TryGetFlagsMark(i_feat, mark, out m);
		}

		public override ulong GetUlEdge(FeatMark fm)
		{
			return mother.GetUlEdge(fm);
		}

		public override bool RemoveEdge(int i_feat, int mark)
		{
			return mother.RemoveEdge(i_feat, mark);
		}

		public override void AddEdge(int i_feat, int mark, Edge e)
		{
			mother.AddEdge(i_feat, mark, e);
		}

		public override Edge GetEdge(int i_feat, int mark)
		{
			return mother.GetEdge(i_feat, mark);
		}

		public override IEnumerable<FeatMarkEdge> FeatMarkEdges
		{
			get { return new FeatMarkEdgeGatherer(mother).Gather(this.Edge); }
		}

		public override bool ContainsFeatMark(int i_feat, int mark)
		{
			/// not the correct result for the TFS section
			Nop.CodeCoverage();
			return mother.ContainsFeatMark(i_feat, mark);
		}

		public override bool _ContainsInMark(int mark)
		{
			/// not the correct result for the TFS section
			Nop.CodeCoverage();
			return mother._ContainsInMark(mark);
		}

		public override int EdgeCount
		{
			get
			{
				if (c_edges != -1)
					return c_edges;

				/// not the correct result for the TFS section
				Nop.CodeCoverage();
				return mother.EdgeCount;
			}
		}

		public override Tfs Clone()
		{
			throw new NotImplementedException();
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class TinyTfs : Tfs
	{
		readonly public FeatMarkEdge[] entries;

		unsafe public TinyTfs(TypeMgr tm, Edge root, IDictionary<ulong, Edge> d, TargetTfs tt)
			: base(tm, root)
		{
			int c = d.Count;
			Debug.Assert(c > 0);

			this.entries = new FeatMarkEdge[c];
			fixed (FeatMarkEdge* _base = &entries[0])
			{
				FeatMarkEdge* pfme = _base;
				foreach (var kvp in d)
				{
					pfme->i_feat = (int)(kvp.Key >> 32);
					pfme->mark = (int)kvp.Key;
					pfme->e = kvp.Value;

					if (tt != null && pfme->e.FlagsId < 0)
					{
						Unification.UnifCoref uc = tt.corefs[((long)tt.id << 32) | (uint)pfme->e.Mark];
						while (uc.f_redirect)
							uc = uc.next;
						pfme->e = uc.e_cur;
					}
					pfme++;
				}

				int c_corefs = 0;
				Debug.Assert(next_coref_mark == -1);
				for (int i = 0; i < c; i++)
				{
					int m_old = _base[i].e.Mark;
					if (_base[i].e.FlagsId < 0 && m_old > 0)
					{
						int m_new = next_coref_mark--;
						c_corefs++;
						pfme = _base;
						for (int j = 0; j < c; j++)
						{
							if (pfme->mark == m_old)
								pfme->mark = m_new;
							if (pfme->e.Mark == m_old)
								pfme->e = new Edge(pfme->e.FlagsId, m_new);
							pfme++;
						}
					}
				}

				if (c_corefs == 0)
					coref_tally_map = Tfs.NoCorefsTallyMap;
				else
				{
					coref_tally_map = new byte[c_corefs];
					pfme = _base;
					for (int i = 0; i < c; i++)
					{
						int m = pfme->e.Mark;
						if (pfme->e.Mark < 0)
							coref_tally_map[~m]++;
					}
				}
			}
			Array.Sort<FeatMarkEdge>(this.entries);
		}

		public TinyTfs(BootstrapTfs dtfs)
			: this(dtfs.tm, dtfs.Edge, dtfs.d, null)
		{
		}

		public TinyTfs(TargetTfs tt)
			: this(tt.tm, tt.Edge, tt.d, tt)
		{
		}

		public TinyTfs(TinyTfs to_clone)
			: base(to_clone.tm, to_clone.Edge)
		{
			this.entries = to_clone.entries;
			this.coref_tally_map = to_clone.coref_tally_map;
		}

		public unsafe override bool TryGetEdge(int i_feat, int mark, out Edge e)
		{
			fixed (FeatMarkEdge* _base = entries)
			{
				FeatMarkEdge* pe = _base;
				FeatMarkEdge* end = _base + entries.Length;
				int d;
				do
				{
					d = pe->mark - mark;
					if (d == 0)
						d = pe->i_feat - i_feat;
					if (d == 0)
					{
						e = pe->e;
						return true;
					}
				}
				while (d < 0 && ++pe < end);
			}
			e = default(Edge);
			return false;
		}

		public unsafe override Edge.Flag TryGetFlagsMark(int i_feat, int mark, out int m)
		{
			fixed (FeatMarkEdge* _base = entries)
			{
				FeatMarkEdge* pe = _base;
				FeatMarkEdge* end = _base + entries.Length;
				int d;
				do
				{
					d = pe->mark - mark;
					if (d == 0)
						d = pe->i_feat - i_feat;
					if (d == 0)
					{
						m = pe->e.Mark;
						return pe->e.FlagsId;
					}
				}
				while (d < 0 && ++pe < end);
			}
			m = 0;
			return 0;
		}


		public unsafe override ulong GetUlEdge(FeatMark fm)
		{
			fixed (FeatMarkEdge* _base = entries)
			{
				FeatMarkEdge* pe = _base;
				FeatMarkEdge* end = _base + entries.Length;
				int d;
				do
				{
					d = pe->mark - fm.m;
					if (d == 0)
						d = pe->i_feat - fm.i_feat;
					if (d == 0)
						return *(ulong*)&pe->e;
				}
				while (d < 0 && ++pe < end);
			}
			return 0;
		}

		public override Edge GetEdge(int i_feat, int mark)
		{
			int d, i = 0;
			do
			{
				d = entries[i].mark - mark;
				if (d == 0)
					d = entries[i].i_feat - i_feat;
				if (d == 0)
					return entries[i].e;
			}
			while (d < 0 && ++i < entries.Length);
			return default(Edge);
		}

		public override IEnumerable<FeatMarkEdge> FeatMarkEdges
		{
			get { return entries; }
		}

		public override bool ContainsFeatMark(int i_feat, int mark)
		{
			int d, i = 0;
			do
			{
				d = entries[i].mark - mark;
				if (d == 0)
					d = entries[i].i_feat - i_feat;
				if (d == 0)
					return true;
			}
			while (d < 0 && ++i < entries.Length);
			return false;
		}

		public override bool _ContainsInMark(int mark)
		{
			for (int i = 0; i < entries.Length; i++)
				if (entries[i].mark == mark)
					return true;
			return false;
		}

		public override int EdgeCount { get { return entries.Length; } }
		public override void SetEdge(int i_feat, int mark, Edge e) { throw new InvalidOperationException(); }
		public override bool RemoveEdge(int i_feat, int mark) { throw new InvalidOperationException(); }
		public override void AddEdge(int i_feat, int mark, Edge e) { throw new InvalidOperationException(); }

		public override Tfs Clone() { return coref_tally_map.Length == 0 ? this : new TinyTfs(this); }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class BareTfs : Tfs
	{
		public BareTfs(Type t)
			: base(t.tm, t.tm.CreateEdge(t, t.IsBare ? 0 : 1, false))
		{
			coref_tally_map = NoCorefsTallyMap;
		}

		public override bool TryGetEdge(int i_feat, int mark, out Edge e)
		{
			e = default(Edge);
			return false;
		}
		public override Edge.Flag TryGetFlagsMark(int i_feat, int mark, out int m)
		{
			m = 0;
			return 0;
		}
		public override ulong GetUlEdge(FeatMark fm)
		{
			return 0;
		}

		public override Edge GetEdge(int i_feat, int mark) { return default(Edge); }
		public override bool ContainsFeatMark(int i_feat, int mark) { return false; }
		public override void SetEdge(int i_feat, int mark, Edge e) { throw new InvalidOperationException(); }
		public override bool RemoveEdge(int i_feat, int mark) { throw new InvalidOperationException(); }
		public override void AddEdge(int i_feat, int mark, Edge e) { throw new InvalidOperationException(); }
		public override IEnumerable<FeatMarkEdge> FeatMarkEdges { get { yield break; } }
		public override bool _ContainsInMark(int mark) { return false; }
		public override int EdgeCount { get { return 0; } }
		public override int ScratchAlloc { get { return 0; } }

		public override Tfs Clone() { return this; }
	};

	[DebuggerDisplay("{fc.ToString(),nq}")]
	public class FeatureSlotTfs : Tfs
	{
		const int TopmostMark = 1;

		public FeatureSlotTfs(TypeMgr tm, Type for_example)
			: base(tm, tm.CreateEdge(for_example ?? tm.TopType, TopmostMark, false))
		{
			this.next_mark = 2;
		}
		public FeatureSlotTfs(FeatureConfig fc, Type for_example)
			: this(fc.TypeMgr, for_example)
		{
			this.fc = fc;
			this.Name = "max feat config for " + fc.ToString();
		}

		readonly FeatureConfig fc;

		//public override bool GetEdgeIndex(int i_feat, int mark, out int mix, out Edge e)
		//{
		//    Debug.Assert(mark == TopmostMark);
		//    mix = (i_feat % fc.modulus) + 1;
		//    e = default(Edge);
		//    return true;
		//}
		//public override FeatMark GetSlotFeatMark(int mix)
		//{
		//    Debug.Assert(mix > 0);
		//    mix--;
		//    Debug.Assert(mix < fc.modulus);
		//    foreach (int fix in fc)
		//        if (mix == fix % fc.modulus)
		//            return new FeatMark(fix, TopmostMark);
		//    return default(FeatMark);
		//}

		public override bool TryGetEdge(int i_feat, int mark, out Edge e)
		{
			Debug.Assert(mark == TopmostMark);
			e = default(Edge);
			return true;
		}

		public override Edge.Flag TryGetFlagsMark(int i_feat, int mark, out int m)
		{
			Debug.Assert(mark == TopmostMark);
			m = 0;
			return 0;
		}

		public override ulong GetUlEdge(FeatMark fm)
		{
			Debug.Assert(fm.m == TopmostMark);
			return 0;
		}

		public override Edge GetEdge(int i_feat, int mark)
		{
			Debug.Assert(mark == TopmostMark);
			return default(Edge);
		}

		public override int EdgeCount { get { return fc.Count; } }
		public override int ScratchAlloc { get { return fc.modulus; } }
		public override void SetEdge(int i_feat, int mark, Edge e) { throw new InvalidOperationException(); }
		public override bool RemoveEdge(int i_feat, int mark) { throw new InvalidOperationException(); }
		public override void AddEdge(int i_feat, int mark, Edge e) { throw new InvalidOperationException(); }

		public override IEnumerable<FeatMarkEdge> FeatMarkEdges
		{
			get
			{
				foreach (int fix in fc)
					yield return new FeatMarkEdge(fix, TopmostMark, default(Edge));
			}
		}

		public override bool ContainsFeatMark(int i_feat, int mark)
		{
			return mark == TopmostMark && fc.Contains(i_feat);
		}

		public override bool _ContainsInMark(int mark)
		{
			return mark == TopmostMark;
		}

		public override Tfs Clone()
		{
			throw new NotImplementedException();
		}
	};
}