//#define PARTICIPANTS
#define EXHAUSTIVE_POOL_SEARCH
using System;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

using miew.Enumerable;
using miew.Debugging;
using miew.Tally;
using miew.ReadOnly;
using miew.Concurrency;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// To abort processing at any point and send up a TFS for examination
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class DebuggingTfsDisplayException : Exception
	{
		Tfs[] rgtfs;

		public DebuggingTfsDisplayException(Tfs tfs)
			: base(String.Format("Debugging exception for TFS {0}", tfs.ToString()))
		{
			this.rgtfs = new Tfs[] { tfs };
		}

		public DebuggingTfsDisplayException(params Tfs[] rgtfs)
		{
			this.rgtfs = rgtfs;
		}

		public Tfs[] Tfs { get { return rgtfs; } }
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// To abort processing at any point and send up a TFS for examination
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class DebuggingTfsDisplayExceptionWithHighlighting : DebuggingTfsDisplayException
	{
		Tfs tfsHighlight;

		public DebuggingTfsDisplayExceptionWithHighlighting(Tfs tfs, Tfs highlight)
			: base(tfs)
		{
			this.tfsHighlight = highlight;
		}

		public Tfs TfsHighlight { get { return tfsHighlight; } }
	}


#if DEBUG
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: E D G E 
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public partial struct Edge
	{
		public String ToString(TypeMgr tm)
		{
			String s = FormatMark(this) + " " + _FlagsReport(tm, FlagsId, false);
			if (!Debugger.IsAttached && !Nop.IsGuiApplication)
				s = s.Replace("⇌", "%").Replace("⊣", ".").Replace("☐", "_").Replace("☒", "X").Replace("⒮", "(s)");
			return s;
		}

		public override String ToString()
		{
			Grammar g = Grammar._singleton;
			return ToString(g == null ? null : g.tm);
		}

		public Type _Type { get { return Grammar._singleton.tm.GetEdgeType(FlagsId); } }

		static public String _FlagsReport(Flag f_in, bool f_coref)
		{
			if (f_in == Edge.Flag.Bottom)
				return "⊥";
			Grammar g = Grammar._singleton;
			return _FlagsReport(g == null ? null : g.tm, f_in, f_coref);
		}

		static public String _FlagsReport(TypeMgr tm, Flag f_in, bool f_coref)
		{
			if (f_in == Edge.Flag.Bottom)
				return "⊥";
			if (tm == null)
				return String.Format("{0} (no TypeMgr available)", f_in);

			String s = "";
			if (f_coref && (f_in & Flag.Coreference) == Flag.Coreference)
				s += "⇌ ";
			if ((f_in & Flag.PrunedDuringParsing) == Flag.PrunedDuringParsing)
				s += "✗ ";

			Flag etm = f_in & Flag.EtmMask;
			if (etm == Flag.EtmString)
			{
				int sid = (int)(f_in & Edge.Flag.MultiIdMask);
				if (sid == 0)
					s += "(" + tm.config.types.string_type + ") ⊣";
				else
				{
					String err = tm.strings.CheckId(sid);
					if (err != null)
						s += err;
					else
						s += String.Format("⒮ “{0}” ⊣", tm.strings.Get(sid));
				}
			}
			else
			{
				int id = (int)(f_in & Edge.Flag.MultiIdMask);
				if (id == 0)
					s += "(*top*) ";
				else
				{
					//s += "id " + id.ToString() + " ";
					s += "(" + tm.type_arr[id].Name + ") ";
				}

				if (etm == Flag.EtmNonBareType)
					s += "…";
				else if (etm == Flag.EtmConfigMapped)
					s += "✦";
				else
					s += "⊣";
			}
			return s;
		}

		public static String FormatMark(Edge e)
		{
			if (e.IsCoreferenced)
				return "⇌" + e.Mark.ToString();
			if (e.Mark != 0)
				return "@" + e.Mark.ToString();
			if ((e.FlagsId & Edge.Flag.EtmNonBareType) != 0)
				return "☒";
			return "☐";
		}
	};

	[DebuggerDisplay("{ToString(),nq}")]
	public partial struct FeatMark : IEquatable<FeatMark>, IComparable<FeatMark>
	{
		public override string ToString()
		{
			if (m == 0 && i_feat == 0)
				return "(null?)";
			//return String.Format("{0}/{1}={2}", m, ((FeatureInfo)i_feat).feature.ToUpper(), i_feat);
			return String.Format("{0}/{1}", m, ((FeatureInfo)i_feat).feature.ToUpper());
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: T F S
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public abstract partial class Tfs : ISysObj
	{
		//public bool GetEdgeAtPath(Edge e_start, FsPath p, out Edge e)
		//{
		//    e = e_start;
		//    foreach (String f in p)
		//    {
		//        int i_feat = tm.GetFeatureIndex(f);
		//        if (i_feat == -1 || !TryGetEdge(i_feat, e.Mark, out e))
		//            return false;
		//    }
		//    return true;
		//}
		//public Edge GetEdgeAtPath(String p)
		//{
		//    Edge e;
		//    GetEdgeAtPath(Edge, new FsPath(p), out e);
		//    return e;
		//}
		public bool GetTypeAtPath(Edge e_start, FsPath p, out Edge e)
		{
			e = e_start;
			foreach (String f in p)
			{
				int i_feat = tm.GetFeatureIndex(f);
				if (i_feat == -1 || !TryGetEdge(i_feat, e.Mark, out e))
					return false;
			}
			return true;
		}
		public Type GetTypeAtPath(String p)
		{
			Edge e = GetEdgeAtPath(p);
			return tm.GetEdgeType(e.FlagsId);
		}

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public ConstraintRef[] _BELOW
		{
			get
			{
				if ((Edge.FlagsId & Edge.Flag.EtmNonBareType) == 0)
					return ConstraintRef.NoneBelow;
				return AllConstraintRefs(Edge).ToArray();
			}
		}
	};


	//[DebuggerTypeProxy(typeof(_arraytfs_debug_display))]
	[DebuggerDisplay("{ToString(),nq}")]
	public partial class ArrayTfs : Tfs
	{
		//public _coref_tallies_debug corefs;

		_arraytfs_entries_debug_display._arr_tfs_entry_debug_display[] _entries_by_in_mark
		{
			get
			{
				return Enumerable.Range(0, entries.Length)
								.OrderBy(i => entries[i].mark)
								.ThenBy(i => entries[i].i_feat)
								.Select(i => new _arraytfs_entries_debug_display._arr_tfs_entry_debug_display { tfs = this, ix = i })
								.ToArray();
			}
		}

		_arraytfs_entries_debug_display._arr_tfs_entry_debug_display[] _entries_by_out_mark
		{
			get
			{
				return Enumerable.Range(0, entries.Length)
								.OrderBy(i =>
									{
										int om = entries[i].e_Mark;
										if (om == 0)
											om = 0x8000 + entries[i].mark;
										return om;
									})
								.Select(i => new _arraytfs_entries_debug_display._arr_tfs_entry_debug_display { tfs = this, ix = i })
								.ToArray();
			}
		}

		_arraytfs_entries_debug_display._arr_tfs_entry_debug_display[] _entries_natural_order
		{
			get
			{
				return Enumerable.Range(0, entries.Length)
								.Select(ix => new _arraytfs_entries_debug_display._arr_tfs_entry_debug_display { tfs = this, ix = ix })
								.ToArray();
			}
		}


		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public ConstraintRef[] _BELOW2
		{
			get
			{
				if ((Edge.FlagsId & Edge.Flag.EtmNonBareType) == 0)
					return ConstraintRef.NoneBelow;
				return AllConstraintRefs(Edge).ToArray();
			}
		}

		public class _arraytfs_entries_debug_display
		{
			ArrayTfs target;
			public _arraytfs_entries_debug_display(ArrayTfs target)
			{
				this.target = target;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			_arr_tfs_entry_debug_display[] _by_mark
			{
				get
				{
					return target.entries
									.Select((ate, ix) => new KeyValuePair<arr_tfs_entry, int>(ate, ix))
									.OrderBy(ate => ate.Key.mark)
									.ThenBy(ate => ate.Key.i_feat)
									.Select(kvp => new _arr_tfs_entry_debug_display { tfs = target, ix = kvp.Value })
									.ToArray();
				}
			}

			[DebuggerDisplay("{ToString(),nq}")]
			public struct _arr_tfs_entry_debug_display
			{
				[DebuggerBrowsable(DebuggerBrowsableState.Never)]
				public ArrayTfs tfs;
				[DebuggerBrowsable(DebuggerBrowsableState.Never)]
				public int ix;

				//[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
				//ConstraintRef[] _BELOW
				//{
				//    get
				//    {
				//        Edge e = tfs.entries[ix].e;
				//        if ((e.FlagsId & Edge.Flag.EtmNonBareType) == 0)
				//            return ConstraintRef.NoneBelow;
				//        return tfs.AllConstraintRefs(e).ToArray();
				//    }
				//}

				public override string ToString()
				{
					FeatureInfo[] rgfi;
					String f;
					arr_tfs_entry ate = tfs.entries[ix];
					int i_next = tfs.rg_next[ix];
					String nxt = i_next == -1 ? "" : i_next.ToString("0000");
					if (tfs.tm == null || (rgfi = tfs.tm.feat_arr) == null || ate.i_feat >= rgfi.Length || (f = rgfi[ate.i_feat].feature) == null)
						return String.Format("{0} {1} {2} {3}", ate.i_feat, ate.mark, ate.e.ToString(tfs.tm), nxt);
					String s = ate.mark + "/" + rgfi[ate.i_feat].feature.ToUpper();
					return String.Format("{0:0000} {1,20} {2,30} {3}", ix, s, ate.e, nxt);
				}
			};
		};
	}

	//[DebuggerTypeProxy(typeof(_arraytfs_debug_display))]
	[DebuggerDisplay("{ToString(),nq}")]
	public partial class MotherDaughterTfs :
		//MarkingArrayTfs, 
		ArrayTfs,
		IMotherDaughter
	{
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: T F S
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public sealed partial class TargetTfs : BootstrapTfs
	{
		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public String[] _target
		{
			get
			{
				var farr = tm.feat_arr;
				return FeatMarkEdges.OrderBy(fme => fme.mark)
							.Select(fme => String.Format("{0,10} {1,8} {2}", farr[fme.i_feat].feature.ToUpper(), fme.mark, fme.e))
							.ToArray();
			}
		}

		public String[] _by_edge_mark
		{
			get
			{
				var farr = tm.feat_arr;
				return FeatMarkEdges.OrderBy(fme => fme.e.Mark)
							.ThenBy(fme => fme.e.FlagsId)
							.Select(fme => String.Format("{0,30} {1,10} {2}", fme.e, farr[fme.i_feat].feature.ToUpper(), fme.mark))
							.ToArray();
			}
		}

		public override string ToString()
		{
			return base.ToString() + String.Format(" nodes: {0}  corefs: {1}", EdgeCount, corefs == null ? 0 : corefs.Count);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if false
	[DebuggerDisplay("{ToString(),nq}")]
	public partial class CachedCorefTfs : Tfs
	{
		public override string ToString()
		{
			return String.Format("{0}, {1} corefs", m_top_edge, corefs.Length);
		}


		//[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//[DebuggerHidden]
		//public CorefTarget[] _corefs
		//{
		//    get
		//    {
		//        TfsEdge _this_te = m_top_edge;
		//        return corefs.Select(c => new CorefTarget(_this_te, c.edge, c.count)).ToArray();
		//    }
		//}

		//[DebuggerDisplay("{ToString(),nq}")]
		//public struct CorefTarget
		//{
		//    public CorefTarget(TfsEdge tfs, Edge e, int count)
		//    {
		//        this.te = tfs;
		//        this.count = count;
		//        this.paths = te.Tray.Roots
		//                            .PathInfoStrings(e.Mark, true)
		//                            .Select(tfsp => new FsPathInstance(tfs, tfsp.fsp))
		//                            .ToArray();
		//    }
		//    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//    public FsPathInstance[] paths;

		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    public TfsEdge te;

		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    public int count;

		//    public override string ToString()
		//    {
		//        Edge e;
		//        paths[0].fsp.GetEdge(te, out e);
		//        return String.Format("   ↳ {0}: {1} in-edges, {2} paths", e, count, paths.Length);
		//    }
		//};


		//[DebuggerDisplay("{ToString(),nq}")]
		//public sealed class FsPathInstance
		//{
		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    public readonly TfsEdge te_tfs;

		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    public readonly TrayCompiledFsPath fsp;

		//    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//    public PoolEdge[] _debug_display
		//    {
		//        get
		//        {
		//            return fsp
		//                .EnumeratePoolEdges(te_tfs.Edge.Mark)
		//                .ToArray();
		//        }
		//    }

		//    public FsPathInstance(TfsEdge tfs, IEnumerable<String> rgs)
		//    {
		//        this.te_tfs = tfs;
		//        this.fsp = new TrayCompiledFsPath(tfs.Tray, rgs);
		//    }

		//    public override String ToString()
		//    {
		//        Edge e;
		//        fsp.GetEdge(te_tfs, out e);
		//        return "      ↳ " + fsp.ToString().ToUpper() + ": " + e.ToString();
		//    }
		//};

	};
#endif

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: C O N S T R A I N T   R E F
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public partial struct ConstraintRef
	{
		public override String ToString()
		{
			String s = Host.ToString();
			if (i_feat == -1)
				s += " (no feat.)";
			else
			{
				s += String.Format("{0} → {1}", Feature.ToUpper(), Constraint);
				if (ConstraintType.IsAtomic)
					s += "•";
			}
			return s;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public ConstraintRef[] _NextConstraint
		{
			get
			{
				Edge e = this.Constraint;
				if ((e.FlagsId & Edge.Flag.EtmNonBareType) == 0)
					return ConstraintRef.NoneBelow;
				return tfs.AllConstraintRefs(e).ToArray();
			}
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: G L B   D A G 
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//[DebuggerDisplay("{m_level} {m_name,nq} {_OnesPositions(),nq}")]
	public abstract partial class GlbDag : Instance
	{
		/// Return a string that lists the integers corresponding to the 'set' bit positions in m_code
		String _OnesPositions()
		{
			int[] rg = m_code.OnesPositions().ToArray();
			if (rg.Length == tm.code_dict.Count)
				return "[all]";
			return rg.StringJoin(" ");
		}

		Type GreatestLowerBound(Type other)
		{
			if (this.IsLeaf && other.IsLeaf)
				return null;
			HashSet<Type> cln = CommonLowerNodes(other);
			if (cln.Count == 0)
				return null;
			if (cln.Count == 1)
				return cln.First();
			if (cln.Contains(this))
				return this as Type;
			if (cln.Contains(other))
				return other;
			throw new Exception();
		}

		public HashSet<Type> CommonLowerNodes(Type other)
		{
			HashSet<Type> h = AllDescendantsInclusive;
			h.IntersectWith(other.AllDescendantsInclusive);
			return h;
		}

		/// only returns error cases
		public HashSet<Type> GlbCheck(Type other, Type root)
		{
			if (this as Type == other)
				return null;
			if (this.IsLeaf || other.IsLeaf)	// one might be GLB, but there surely won't be a problem
				return null;
			if (this as Type == root || other == root)
				return null;

			HashSet<Type> cln = CommonLowerNodes(other);
			if (cln.Count <= 1 || cln.Contains(this as Type) || cln.Contains(other))
				return null;
			// get rid of deeper extras
			HashSet<Type> h = new HashSet<Type>();
			foreach (Type t in cln)
				h.UnionWith(t.AllDescendants);
			cln.RemoveWhere(e => h.Contains(e));
			if (cln.Count == 0)
				throw new Exception();
			// that might have done the trick
			if (cln.Count == 1)
				return null;
			return cln;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: T Y P E 
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{Name,nq} {m_id} ({_feature_info(),nq})")]
	public partial class Type : GlbDag
	{
		static FeatureInfo[] rg_featinfo_empty = new FeatureInfo[0];

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public FeatureInfo[] _dbg_features
		{
			get
			{
				if ((m_flags & Flags.LoadedNonLocalFeatures) == 0 || fc == null)
					return rg_featinfo_empty;
				return fc.Select(i_feat => tm.feat_arr[i_feat]).ToArray();
			}
		}

		String _feature_info()
		{
			int local = 0, total = 0;
			foreach (FeatureInfo fi in fc.Select(i_feat => tm.feat_arr[i_feat]))
			{
				if (fi.maximal_type == this)
					local++;
				total++;
			}
			return String.Format("{0} features: {1} local, {2} inherited.", total, local, total - local);
		}

		public static explicit operator Type(int tid)
		{
			return Grammar._singleton.tm.type_arr[tid];
		}
	};

	[DebuggerDisplay("#{i_feat} {feature.ToUpper()} ({maximal_type.Name})")]
	public partial struct FeatureInfo
	{
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: T Y P E   M A N A G E R
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public unsafe partial class TypeMgr
	{
		public int GlbCount { get { return next_glb_num; } }

		public Instance FindExpanded(Tfs e)
		{
			return AllInstances.FirstOrDefault(_e => _e.IsExpanded && _e.Expanded == e);
		}

		public Instance FindDefinition(Tfs e)
		{
			return AllInstances.FirstOrDefault(_e => _e.Definition == e);
		}

		public String FindInfo(Tfs e)
		{
			foreach (Instance inst in AllInstances)
			{
				if (inst.Definition == e)
					return "definition: " + inst.Name;
				if (inst.IsExpanded && inst.Expanded == e)
					return "expanded: " + inst.Name;
			}
			return "unknown";
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		//void FeatureModuliReport()
		//{
		//    foreach (FeatureConfig fc in fcm)
		//    {
		//        if (fc.Count == 0)
		//            continue;
		//        Console.WriteLine("{0,4} {1,2} [{2,3} {3,3}] ({4,3}) mod: {5,3}   {6}",
		//            fc.ConfigIndex,
		//            fc.Count,
		//            fc.min,
		//            fc.max,
		//            fc.range,
		//            fc.modulus,
		//            fc.Select(fix => fix.ToString().PadLeft(3)).StringJoin(" "));
		//        //	Console.WriteLine("                                   {0}", fc.Select(fix => (fix - fc.min).ToString().PadLeft(3)).StringJoin(" "));
		//        Console.WriteLine("                                   {0}", fc.Select(fix => (fix % fc.modulus).ToString().PadLeft(3)).StringJoin(" "));
		//    }
		//    Console.WriteLine("feats: {0} fcs: {1}  max feat/type: {2} max range: {3}", feat_arr.Length, fcm.Count, fcm.MaxFeaturesPerType, fcm.MaxFeatureRange);
		//}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	unsafe public struct TfsEdgeSpy
	{
		public TfsEdgeSpy(Tfs tfs, Edge* pe)
		{
			this.tfs = tfs;
			this.pe = pe;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Tfs tfs;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge* pe;

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		[DebuggerHidden]
		public ConstraintRef[] _BELOW
		{
			get
			{
				if ((pe->FlagsId & Edge.Flag.EtmNonBareType) == 0)
					return ConstraintRef.NoneBelow;
				return tfs.AllConstraintRefs(*pe).ToArray();
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public bool IsTarget { get { return tfs is TargetTfs || (tfs is TfsSection && ((TfsSection)tfs).mother.IsTarget); } }
		public override string ToString()
		{
			return String.Format("{0} {1}", tfs.id.ToString("X"), *pe);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: U N I F I C A T I O N
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public unsafe partial struct Unification
	{
		static int next_id = 0xCF00;

		String _corefs_info()
		{
			if (corefs == null)
				return "(null)";
			int target_id = target.DisplayId;
#if PARTICIPANTS
			var tfsdict = corefs.participants;
#endif
			String refs = corefs
						.Keys
						.Select(mm => (int)(mm >> 32))
						.ToTallies()
						.OrderBy(tal => tal.Item != target_id)
						.Select(tal =>
						{
#if PARTICIPANTS
							return String.Format("{0} ({1})", tfsdict[tal.Item].ToString(), tal.Count);
#else
							return String.Format("{0} ({1})", tal.Item.ToString("X"), tal.Count);
#endif
						})
						.StringJoin("  ");
			return String.Format("{0} classes, {1} refs  ▍ {2}", corefs.CountDistinctValues(), corefs.Count, refs);
		}

		[DebuggerTypeProxy(typeof(_corefs_debug_display))]
		public class _corefs : Dictionary<Int64, UnifCoref>
		{
			public _corefs(int capacity)
				: base(capacity)
			{
			}
#if PARTICIPANTS
			public Dictionary<int, Tfs> participants = new Dictionary<int, Tfs>();
#endif
			public void AddTfsArgs(params Tfs[] rgtfs)
			{
#if PARTICIPANTS
				foreach (var tfs in rgtfs)
					participants[tfs.id] = tfs;
#endif
			}
		};
		class _corefs_debug_display
		{
			Dictionary<Int64, UnifCoref> target;
			public _corefs_debug_display(Dictionary<Int64, UnifCoref> target)
			{
				this.target = target;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			MarkUnifCoref[] _listing
			{
				get
				{
					return target.Select(kvp => new MarkUnifCoref
					{
						id = (int)(kvp.Key >> 32),
						mark = (int)kvp.Key,
						uc = kvp.Value
					}).ToArray();
				}
			}

			[DebuggerDisplay("{ToString(),nq}")]
			struct MarkUnifCoref
			{
				[DebuggerBrowsable(DebuggerBrowsableState.Never)]
				public int id;
				[DebuggerBrowsable(DebuggerBrowsableState.Never)]
				public int mark;
				//[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
				public UnifCoref uc;
				public override string ToString()
				{
					return String.Format("{0,7}  ⇌{1,-7} {2}", id.ToString("X"), mark, uc);
				}
			};
		};

		public override string ToString()
		{
			return String.Format("#{0:X4} corefs: {1} target: {2}",
				id,
				corefs == null ? 0 : corefs.Count,
				target == null ? 0 : target.EdgeCount);
		}

		[DebuggerDisplay("{ToString(),nq}")]
		sealed public partial class UnifCoref
		{
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public int id;

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public UnifCoref LoopMaster
			{
				get
				{
					UnifCoref walk = this;
					while (walk.f_redirect)
						walk = walk.next;
					return walk;
				}
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public int LoopLength
			{
				get
				{
					int c = 0;
					UnifCoref walk = this;
					do
						c++;
					while ((walk = walk.next) != this);
					return c;
				}
			}

			public override string ToString()
			{
				String minf = "";
				UnifCoref walk = this;
				do
					minf += String.Format("{0}{1:X4} ", !walk.f_redirect ? "m" : " ", walk.id);
				while ((walk = walk.next) != this);

				return String.Format("{0,-25} {1} {2}",
					minf,
					e_cur.Mark != 0 ? e_cur.ToString() : "",
					c_fm);
			}

			//[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			//public TfsEdge[] _foreign_lookups
			//{
			//    get { return u.corefs.Where(kvp => kvp.Value == this).Select(kvp => new TfsEdge( kvp.Key).ToArray(); }
			//}
		};
	};

	//[DebuggerTypeProxy(typeof(_uc_corefs_debug_display))]
	public unsafe partial class UnificationNWay
	{
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		static public UnificationNWay unwy;

		//public NwayCoref[] Distinct { get { return corefs.Values.Distinct().ToArray(); } }

		//[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//public TfsidMarkUc[] All { get { return corefs.Select(kvp => new TfsidMarkUc(kvp.Key, kvp.Value)).ToArray(); } }

		public IReadOnlyCollection<TfsMark> GetArgsCollection(NwayArgs* pnwa)
		{
			return new NwayArgs._coll(pnwa);
		}
#if false

		void Reset()
		{
			//next_coref_id = 0xCF00;
			c_participants = 0;
		}
		public int CorefId(NwayCoref* pc)
		{
			return (int)(pc - unwy._corefs) + 0xCF00;
		}

		[DebuggerDisplay("Count: {unwy.c_participants}")]
		public participant_debug[] Participants
		{
			get
			{
				var rgpdb = new participant_debug[unwy.c_participants];
				for (byte i = 0; i < rgpdb.Length; i++)
					rgpdb[i] = new participant_debug { unwy = this, tfsix = i };
				return rgpdb;
			}
		}

		public _nway_coref_debug[] Corefs
		{
			get
			{
				var rg = new _nway_coref_debug[CorefCount];
				for (int i = 0; i < CorefCount; i++)
					rg[i] = new _nway_coref_debug(this, _corefs + i);
				return rg;
			}
		}
		[DebuggerDisplay("{ToString(),nq}")]
		public struct participant_debug
		{
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public UnificationNWay unwy;

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public byte tfsix;

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public participant_map_debug Map { get { return new participant_map_debug(unwy, tfsix); } }

			public override string ToString()
			{
				if (unwy == null)
					return "(null unwy)";
				if (unwy.participant_bases == null)
					return "(null participant_bases)";
				if (unwy.ppmb_next == null)
					return "(null ppmb_next)";
				if (unwy.pp_map_base == null)
					return "(null pp_map_base)";
				if (tfsix >= unwy.c_participants)
					return "tfsix out of range";
				//if (unwy.participants == null)
				//    return "(null participants)";

				Tfs tfs = unwy.participants[tfsix];
				String s_tfs, t_tfs = "";
				if (tfs == null)
					s_tfs = "(null tfs)";
				else
				{
					s_tfs = tfs.ToString();
					t_tfs = tfs.GetType().Name;
				}
				long i_base = unwy.participant_bases[tfsix] - unwy.pp_map_base;
				long i_next = (tfsix + 1 < unwy.c_participants ? unwy.participant_bases[tfsix + 1] : unwy.ppmb_next) - unwy.pp_map_base;
				String s_alloc = String.Format("{0}-{1} ({2})", i_base, i_next - 1, i_next - i_base);

				return String.Format("{0,2} {1,-17} {2,-37} {3}", tfsix, t_tfs, s_tfs, s_alloc);
			}
		};

		public struct participant_map_debug
		{
			public participant_map_debug(UnificationNWay unwy, byte tfsix)
			{
				this.unwy = unwy;
				this.tfsix = tfsix;
			}

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public UnificationNWay unwy;

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public byte tfsix;

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public participant_map_entry[] entries
			{
				get
				{
					int i_base = (int)(unwy.participant_bases[tfsix] - unwy.pp_map_base);
					int i_next = (int)((tfsix + 1 < unwy.c_participants ? unwy.participant_bases[tfsix + 1] : unwy.ppmb_next) - unwy.pp_map_base);
					int c = i_next - i_base;
					participant_map_entry[] rg = new participant_map_entry[c];
					for (int ix = 0; ix < c; ix++)
						rg[ix] = new participant_map_entry { unwy = unwy, ix = ix, tfsix = tfsix };
					return rg;
				}
			}

			[DebuggerDisplay("{ToString(),nq}")]
			public struct participant_map_entry
			{
				[DebuggerBrowsable(DebuggerBrowsableState.Never)]
				public UnificationNWay unwy;
				[DebuggerBrowsable(DebuggerBrowsableState.Never)]
				public byte tfsix;
				[DebuggerBrowsable(DebuggerBrowsableState.Never)]
				public int ix;

				[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
				public _nway_coref_debug _coref
				{
					get
					{
						return new _nway_coref_debug(unwy, unwy.participant_bases[tfsix][ix]);
					}
				}

				public override string ToString()
				{
					return String.Format("{0,3} {1}", ~ix, _coref);
				}
			};
		};
		[DebuggerDisplay("{ToString(),nq}")]
		public struct _nway_coref_debug
		{
			public static _nway_coref_debug Null = new _nway_coref_debug(UnificationNWay.unwy, null);

			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			public UnificationNWay unwy;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			NwayCoref* pc;

			public _nway_coref_debug(UnificationNWay unwy, NwayCoref* pc)
			{
				this.unwy = unwy;
				this.pc = pc;
			}

			//public FeatMark[] FeatMarks
			//{
			//    get
			//    {
			//        FeatMark[] rgfm;
			//        rgfm = new FeatMark[pc->c_fm];
			//        for (int i = 0; i < pc->c_fm; i++)
			//            rgfm[i] = new FeatMark(pc->fms[i]);
			//        return rgfm;
			//    }
			//}

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public TfsMark[] _nwa
			{
				get
				{
					if (pc == null || pc->nwa.c_args == 0)
						return TfsMark.None;
					return unwy.GetArgsCollection(&pc->nwa).ToArray();
				}
			}


			public override string ToString()
			{
				if (pc == null || pc->Equals(default(NwayCoref)))
					return String.Empty;
				return String.Format("{0:X} c_remain: {1} {2}  c_resume: {3}  c_fm: {4}",
					unwy.CorefId(pc),
					pc->c_remain,
					Edge._FlagsReport(unwy.tm, pc->nwa.f, true),
					pc->nwa.c_args,
					pc->c_fm);

				//int c = unwy.corefs_full.Count(kvp => kvp.Value == this);
				//String s;
				//fixed (NwayArgs* pnwy = &nwa)
				//{
				//    s = String.Format("{0:X4} {1} {2,20} refs: {3}  resume: {4}  fm: {5}",
				//        id,
				//        c,
				//        Edge._FlagsReport(unwy.tm, f, false),
				//        c_remain,
				//        unwy.GetArgsCollection(pnwy).StringJoin(", "),
				//        FeatMarks.Select(fm => fm.ToString()).StringJoin(", "));
				//}
				//return s;
			}
		};
#endif

		//public class _uc_corefs_debug_display
		//{
		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    UnificationNWay unwy;

		//    public _uc_corefs_debug_display(UnificationNWay unwy)
		//    {
		//        this.unwy = unwy;
		//    }

		//    //[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//};

		//public override string ToString()
		//{
		//    return String.Format("aliases: {0}  equiv-classes: {1}  reentr-remain: {2}", this.Count, this.Values.CountDistinct(), this.Values.Sum(ncf => ncf.c_remain));
		//}


		//[DebuggerTypeProxy(typeof(_uc_corefs_full_debug_display))]
		//[DebuggerDisplay("{ToString(),nq}")]
		//public class _corefs_full_debug : Dictionary<ulong, NwayCorefFull>
		//{
		//    public class _uc_corefs_full_debug_display
		//    {
		//        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//        _corefs_full_debug d;

		//        public _uc_corefs_full_debug_display(_corefs_full_debug d)
		//        {
		//            this.d = d;
		//        }

		//        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//        public TfsidMarkUcFull[] _listing
		//        {
		//            get
		//            {
		//                return d.Select(kvp => new TfsidMarkUcFull(kvp.Key, kvp.Value)).ToArray();
		//            }
		//        }
		//    };

		//    public override string ToString()
		//    {
		//        return String.Format("aliases: {0}  equiv-classes: {1}  reentr-remain: {2}", this.Count, this.Values.CountDistinct(), this.Values.Sum(ncf => ncf.c_remain));
		//    }
		//};

		//[DebuggerDisplay("{ToString(),nq}")]
		//public partial struct NwayCoref
		//{
		//    //[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    //readonly public int id;

		//    //[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//    //public TfsMark[] Refs
		//    //{
		//    //    get
		//    //    {
		//    //        return unwy.corefs
		//    //            .Where(kvp => kvp.Value == this)
		//    //            .Select(kvp => new TfsMark(unwy.participants[(int)(kvp.Key >> 32)], (int)kvp.Key))
		//    //            .ToArray();
		//    //    }
		//    //}

		//    //public override string ToString()
		//    //{
		//    //    int c = unwy.corefs.Count(kvp => kvp.Value == this);
		//    //    fixed (NwayArgs* pnwy = &nwa)
		//    //        return String.Format("{0:X4} {1} {2,20} refs: {3}  resume: {4}",
		//    //            id,
		//    //            c,
		//    //            Edge._FlagsReport(unwy.tm, f, false),
		//    //            c_remain,
		//    //            unwy.GetArgsCollection(pnwy).StringJoin(", "));
		//    //}
		//};



		//[DebuggerDisplay("{ToString(),nq}")]
		//public sealed partial class NwayCorefFull
		//{
		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    readonly public int id;

		//    //[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//    //public TfsidMark[] Refs
		//    //{
		//    //    get
		//    //    {
		//    //        return unwy.corefs_full.Where(kvp => kvp.Value == this).Select(kvp => new TfsidMark(kvp.Key)).ToArray();
		//    //    }
		//    //}

		//    //public FeatMark[] FeatMarks
		//    //{
		//    //    get
		//    //    {
		//    //        FeatMark[] rgfm;
		//    //        fixed (NwayFeatMarks* pnfmx = &nfmx)
		//    //        {
		//    //            rgfm = new FeatMark[pnfmx->Count];
		//    //            for (int i = 0; i < pnfmx->Count; i++)
		//    //                rgfm[i] = new FeatMark(pnfmx->fms[i]);
		//    //        }
		//    //        return rgfm;
		//    //    }
		//    //}

		//    public override string ToString()
		//    {
		//        int c = unwy.corefs_full.Count(kvp => kvp.Value == this);
		//        String s;
		//        fixed (NwayArgs* pnwy = &nwa)
		//        {
		//            s = String.Format("{0:X4} {1} {2,20} refs: {3}  resume: {4}  fm: {5}",
		//                id,
		//                c,
		//                Edge._FlagsReport(unwy.tm, f, false),
		//                c_remain,
		//                unwy.GetArgsCollection(pnwy).StringJoin(", "),
		//                FeatMarks.Select(fm => fm.ToString()).StringJoin(", "));
		//        }
		//        return s;
		//    }
		//};


		//[DebuggerTypeProxy(typeof(NwayArgs._nwa_debug_display))]
		[DebuggerDisplay("{ToString(),nq}")]
		public partial struct NwayArgs
		{
#if true
			public override string ToString()
			{
				fixed (NwayArgs* pnwa = &this)
				{
					return String.Format("{0}  {1} args: {2} remain: {3}  ",
						Edge._FlagsReport(this.f, true),
						this.c_args,
						unwy.GetArgsCollection(pnwa).Select(tfsm => String.Format("{0:X}/{1}", tfsm.tfs.id, tfsm.mark)).StringJoin(" "),
						this.c_remain);
				}
			}

			//public class _nwa_debug_display
			//{
			//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
			//    NwayArgs nwa;

			//    public _nwa_debug_display(NwayArgs nwa)
			//    {
			//        this.nwa = nwa;
			//    }

			//    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			//    public TfsMark[] _listing
			//    {
			//        get
			//        {
			//            fixed (NwayArgs* pnwa = &nwa)
			//            {
			//                return unwy.GetArgsCollection(pnwa).ToArray();
			//            }
			//        }
			//    }
			//};

			[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
			public TfsMark[] _listing
			{
				get
				{
					fixed (NwayArgs* pnwa = &this)
					{
						return unwy.GetArgsCollection(pnwa).ToArray();
					}
				}
			}

			public struct _coll : IReadOnlyCollection<TfsMark>
			{
				public NwayArgs* pnwa;
				public _coll(NwayArgs* pnwa)
				{
					this.pnwa = pnwa;
				}

				public TfsMark this[int ix]
				{
					get
					{
						if (ix >= pnwa->c_args)
							throw new IndexOutOfRangeException();
						TfsixMark tixm = *(TfsixMark*)&pnwa->tmx[ix];
						return new TfsMark(unwy.participants[tixm.tfsix], tixm.mark);
					}
				}

				public int Count { get { return pnwa->c_args; } }
				public bool Contains(TfsMark item) { return IndexOf(item) != -1; }
				public int IndexOf(TfsMark item) { throw new NotImplementedException(); }
				public void CopyTo(TfsMark[] array, int arrayIndex) { throw new NotImplementedException(); }
				public IEnumerator<TfsMark> GetEnumerator() { return new _enum(pnwa); }
				IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

				public struct _enum : IEnumerator<TfsMark>
				{
					NwayArgs* pnwa;
					int ix;
					public _enum(NwayArgs* pnwa)
					{
						this.pnwa = pnwa;
						this.ix = -1;
					}

					public void Reset() { ix = -1; }

					public TfsMark Current
					{
						get
						{
							TfsixMark tixm = *(TfsixMark*)&pnwa->tmx[ix];
							return new TfsMark(unwy.participants[tixm.tfsix], tixm.mark);
						}
					}

					object IEnumerator.Current { get { return Current; } }

					public bool MoveNext()
					{
						if (ix + 1 >= pnwa->c_args)
							return false;
						ix++;
						return true;
					}

					public void Dispose() { }
				};
			};
#endif
		};

#if false
		[DebuggerDisplay("{ToString(),nq}")]
		public struct TfsidMark
		{
			public TfsidMark(ulong ul)
			{
				this.tfsid = (int)(ul >> 32);
				this.mark = (int)ul;
			}
			public TfsidMark(int tfsid, int mark)
			{
				this.tfsid = tfsid;
				this.mark = mark;
			}
			public int tfsid;
			public int mark;
			public override string ToString()
			{
				return String.Format("     {0:X}/{1}", tfsid, mark);
			}
		};
#endif
		//[DebuggerDisplay("{ToString(),nq}")]
		//public struct TfsidMarkUc
		//{
		//    public TfsidMarkUc(ulong ul, NwayCoref uc)
		//    {
		//        this.tfsid = (int)(ul >> 32);
		//        this.mark = (int)ul;
		//        this.uc = uc;
		//    }
		//    public TfsidMarkUc(int tfsid, int mark, NwayCoref uc)
		//    {
		//        this.tfsid = tfsid;
		//        this.mark = mark;
		//        this.uc = uc;
		//    }
		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    public int tfsid;
		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    public int mark;
		//    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//    public NwayCoref uc;

		//    public override string ToString()
		//    {
		//        return String.Format("{0:X} {1,4} {2}", tfsid, mark, uc.ToString());
		//    }
		//};


		//[DebuggerDisplay("{ToString(),nq}")]
		//public struct TfsidMarkUcFull
		//{
		//    public TfsidMarkUcFull(ulong ul, NwayCorefFull uc)
		//    {
		//        this.tfsid = (int)(ul >> 32);
		//        this.mark = (int)ul;
		//        this.uc = uc;
		//    }
		//    public TfsidMarkUcFull(int tfsid, int mark, NwayCorefFull uc)
		//    {
		//        this.tfsid = tfsid;
		//        this.mark = mark;
		//        this.uc = uc;
		//    }
		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    public int tfsid;
		//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
		//    public int mark;
		//    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//    public NwayCorefFull uc;

		//    public override string ToString()
		//    {
		//        return String.Format("{0:X} {1,4} {2}", tfsid, mark, uc.ToString());
		//    }
		//};
	};

	[DebuggerDisplay("{ToString(),nq}")]
	public struct TfsFeatMarkEdge
	{
		public TfsFeatMarkEdge(Tfs tfs, FeatMarkEdge fme)
		{
			this.tfs = tfs;
			this.fme = fme;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Tfs tfs;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public FeatMarkEdge fme;

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		public ConstraintRef[] _BELOW
		{
			get { return tfs.AllConstraintRefs(fme.e).ToArray(); }
		}

		public override string ToString()
		{
			if (tfs == null)
				return "(null tfs)";
			return String.Format("\"{0,6:X}\" {1}", tfs.id, fme.ToString());
		}
	};

	[DebuggerDisplay("{ToString(),nq}")]
	public partial struct TfsMark
	{
		[DebuggerDisplay("count: {ABOVE.Length}")]
		public TfsFeatMarkEdge[] ABOVE
		{
			get
			{
				Tfs _tfs = tfs;
				return new Tfs.FeatMarkEdgeGatherer(tfs, int.MaxValue, mark)
									.Gather(tfs.Edge)
									.Select(fme => new TfsFeatMarkEdge(_tfs, fme))
									.ToArray();
			}
		}

		//[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		[DebuggerDisplay("count: {BELOW.Length}")]
		public TfsFeatMarkEdge[] BELOW
		{
			get
			{
				Tfs _tfs = tfs;
				return new Tfs.FeatMarkEdgeGatherer(tfs, mark, int.MaxValue)
									.Gather(tfs.Edge)
									.Select(fme => new TfsFeatMarkEdge(_tfs, fme))
									.ToArray();
			}
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// debug: G R A M M A R
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public partial class Grammar : ISysObj
	{
		public static Grammar _singleton;

#if false
		public void CheckOrphanedEdges(TextWriter tw, HashSet<TfsFeatMark> reachable)
		{
			//HashSet<TfsFeatMark> pool_pms = new HashSet<TfsFeatMark>(Pools.SelectMany(cp => cp.Marks.Select(m => new TfsFeatMark(cp, m))));

			//var y = pool_pms.OrderBy(x => x).ToArray();
			//var z = reachable.OrderBy(x => x).ToArray();

			HashSet<TfsFeatMark> garbage = new HashSet<TfsFeatMark>(pool_pms.Except(reachable));

			HashSet<TfsFeatMark> non_bare_garbage = new HashSet<TfsFeatMark>(garbage.Where(pm => pm.Constraint.Mark != 0));

			HashSet<TfsFeatMark> bare_garbage = new HashSet<TfsFeatMark>(garbage.Where(pm => pm.Constraint.Mark == 0));

			//HashSet<PoolMark> garbage_trees = new HashSet<PoolMark>(garbage.Except(garbage.SelectMany(pm => pm.Constraint.ConstrainedPoolMarksOnly(this))));
			HashSet<Edge> garbage_trees = TreeTops(garbage).ToHashSet();

			//int garbage_parents = 0;
			//			foreach (Edge ge in garbage)
			//		{
			//		if (ge.Any(ge_child => reachable.Contains(ge_child)))
			//		garbage_parents++;
			//			}

			tw.WriteLine("PoolMark Report:");
			//tw.WriteLine("        in pools: {0,6}\n       reachable: {1,6}\nmark should be 0: {2,6}\n         garbage: {3,6}\n    bare garbage: {4,6}\nnon-bare garbage: {5,6}",
			tw.WriteLine("        in pools: {0,7}\n       reachable: {1,7}\n         garbage: {2,7}\n    bare garbage: {3,7}\nnon-bare garbage: {4,7}\n   garbage trees: {5,7}",
					pool_pms.Count,
					reachable.Count,
				//bad_mark.Count,
					garbage.Count,
					bare_garbage.Count,
					non_bare_garbage.Count,
					garbage_trees.Count);

			int take_gt = int.MaxValue;
			if (garbage_trees.Count > 0)
			{
				tw.WriteLine();
				tw.Write("Garbage Trees");
				if (garbage_trees.Count > take_gt)
					tw.Write(" (first {0} of {1} shown)", take_gt, garbage_trees.Count);
				tw.WriteLine();
				tw.WriteLine("===============================");
				foreach (Edge gedge in garbage_trees.Take(take_gt))
				{
					tw.WriteLine("\"{0}\"? @{1}", tm.GetEdgeType(gedge.FlagsId).Name, gedge.Mark);
					foreach (String pth in new PathLister(this, gedge, null, true, null))//reachable))
						tw.WriteLine("\t{0}", pth);
				}
				tw.WriteLine("===============================");
			}

			int take_g = 100;
			if (garbage.Count > 0)
			{
				tw.WriteLine();
				tw.Write("Garbage PoolMarks:");
				if (garbage.Count > take_g)
					tw.Write(" (first {0} of {1} shown)", take_g, garbage.Count);
				tw.WriteLine();
				tw.WriteLine("===============================");
				foreach (TfsFeatMark gpm in garbage.Take(take_g))
					tw.WriteLine(gpm.ToString());
				tw.WriteLine("===============================");
			}
		}
#endif

	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public abstract partial class PassiveEdge : ArrayTfs, IParseObj
	{
		public List<IParseObj> _packed_edges
		{
			get
			{
				if (ctrl.config.system.MultiThreading)
					Debug.Fail("debug access to the non-concurrent list cannot be obtained when multithreading is enabled.");
				return packed_edges;
			}
		}

#if false
		public bool PackParseObj(IParseObj child)
		{
			ParseTfs pt_child = child as ParseTfs;

			/// attempt to set the 'packed' sentinal into the sub
			ConcurrentList<IParseObj> _old = null;
			if (pt_child != null)
			{
				if (!pt_child.TrySetPackedSentinal(out _old))
				{
					Nop.CodeCoverage("a");
					return false;
				}

				//if (_old != null)
				//{
				//    pt_child.packed = _old;
				//    return false;		// tmp tmp
				//}

				//pt_child.packed_into = this;
			}

			var _cur = packed;
			if (_cur == null)
			{
				var _new = new ConcurrentList<IParseObj>();
				_cur = Interlocked.CompareExchange(ref packed, _new, null) ?? _new;
				if (_cur == packed_sentinal)
				{
					/// parent got packed before we were able to pack the child. Put the child back the way it was.
					Nop.CodeCoverage("b");
					if (pt_child != null)
					{
						//	pt_child.packed_into = null;
						pt_child.packed = _old;
					}
					return false;
				}
			}
			if (_cur != Interlocked.CompareExchange(ref packed, null, null))
				throw new ParseException();
			if (_cur == packed_sentinal)
				throw new ParseException();

			//if (_old != null)
			//{
			//    foreach (var ipo in _old)
			//        _cur.Add(ipo);
			//}
			_cur.Add(child);

			return true;
		}

		bool TrySetPackedSentinal(out ConcurrentList<IParseObj> _old)
		{
			_old = packed;
			if (_old == packed_sentinal)
			{
				_old = null;
				return false;
			}
			return Interlocked.CompareExchange(ref packed, packed_sentinal, _old) == _old;
		}
#endif
		public override string ToString()
		{
			String s = SequenceControl.ToString(this) + " " + base.ToString();
			if (packed_edges != null)
			{
				s += String.Format(" peer: {0}  {1}", packed_edges.Count.ToString(), packed_edges.StringJoin(", "));
			}
			return s;
		}

	};

#endif // DEBUG
}