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

using glue.Extensions.String;
using glue.Debugging;


namespace agree
{
#if false
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	sealed public class TrackingTray : Tray
	{
		public TrackingTray(int tix, TypeMgr tm, int next_mark, int next_id)
			: base(tix, tm, next_mark, next_id)
		{
			for (int i = 0; i < Pools.Length; i++)
				Pools[i] = new TrackingConcurrentDictionaryConstraintPool(this, i);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		///
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public Dictionary<int, HashSet<PoolMark>> garbage_tracking = new Dictionary<int, HashSet<PoolMark>>();
		public bool garbage_tracking_enable = false;
		public HashSet<int> stops = new HashSet<int> { 37332, 40643, 38046, 38048, 52433, 37332, 40643 };

		public void StartGarbageTracking()
		{
			Action<Edge> f = null;
			f = (e) =>
			{
				if (e.IsConstrained)
				{
					foreach (int fix in tm.GetEdgeType(e.FlagsId)._deprec_feat_indexes)
					{
						ConstraintPool cp = Pools[fix];
						Edge q;
						if (cp.TryGetEdge(e.Mark, out q))
						{
							//if (cp_outer.HasValue)
							{
								HashSet<PoolMark> hspm;
								if (!garbage_tracking.TryGetValue(q.Mark, out hspm))
									garbage_tracking.Add(q.Mark, hspm = new HashSet<PoolMark>());
								hspm.Add(new PoolMark(cp, e.Mark));
							}
							f(q);
						}
					}
				}
			};

			foreach (Type t in tm.type_dict.Values)
			{
				f(t.Definition.Edge);
				if (t.m_flags.HasFlag(Type.Flags.Expanded) && t.Expanded.Edge != t.Definition.Edge)
					f(t.Expanded.Edge);
			}

			Debug.WriteLine("enabling garbage tracking");
			garbage_tracking_enable = true;
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class TrackingConcurrentDictionaryConstraintPool : ConcurrentTray.ConcurrentDictionaryConstraintPool
	{
		TrackingTray ctr;

		public TrackingConcurrentDictionaryConstraintPool(TrackingTray tr, int i_feat)
			: base(tr, i_feat)
		{
			this.ctr = tr;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Store the constraint for the specified mark. Handle Edge value semantics properly.
		/// Allows detached mark to be set for bare or atomic types
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public override void SetEdge(Int32 in_mark, Edge e_new)
		{
			Debug.Assert(in_mark != 0 && in_mark >= tr._protect_mark);

			if (!ctr.garbage_tracking_enable)
			{
				base.SetEdge(in_mark, e_new);
				return;
			}

			HashSet<PoolMark> hspm;
			PoolMark pm = new PoolMark(this, in_mark);
			Edge e_old;
			if (this.TryGetEdge(in_mark, out e_old))
			{
				if (e_old == e_new)
					return;
				if (e_old.Mark != e_new.Mark)
				{
					hspm = ctr.garbage_tracking[e_old.Mark];
					if (!hspm.Contains(pm))
						Debugger.Break();
					hspm.Remove(pm);

					if (hspm.Count == 0)
					{
						ctr.garbage_tracking.Remove(e_old.Mark);

						if (e_old != default(Edge))
						{
							Debug.WriteLine("last access for children of {0} was lost when it was switched to {1} in PoolMark {2}-{3}", e_old, e_new, this.Feature.ToUpper(), in_mark);
							Debug.Write("\t" + new StackTrace(true).GetFrames()[3]);
						}
					}
				}
			}

			//////////////////////////////////////////////////////////////////////////////
			if (e_new == default(Edge))
			{
				base.RemoveEdge(in_mark);
				return;
			}
			//////////////////////////////////////////////////////////////////////////////
			base.cd[in_mark] = e_new;
			//////////////////////////////////////////////////////////////////////////////

			if (!ctr.garbage_tracking.TryGetValue(e_new.Mark, out hspm))
				ctr.garbage_tracking.Add(e_new.Mark, hspm = new HashSet<PoolMark>());

			hspm.Add(pm);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public override void RemoveEdge(Int32 in_mark)
		{
			if (!ctr.garbage_tracking_enable)
			{
				base.RemoveEdge(in_mark);
				return;
			}

			Edge e_old;
			if (this.TryGetEdge(in_mark, out e_old))
			{
				PoolMark pm = new PoolMark(this, in_mark);

				HashSet<PoolMark> hspm = ctr.garbage_tracking[e_old.Mark];
				if (!hspm.Contains(pm))
					Debugger.Break();
				hspm.Remove(pm);
				if (hspm.Count == 0)
					ctr.garbage_tracking.Remove(e_old.Mark);

#if true
				if (hspm.Count == 0)
				{
					if (ctr.stops.Contains(in_mark))
					{
						Debug.WriteLine("last access for children of {0} was lost when it was removed from PoolMark {1}-{2}", e_old, this.Feature.ToUpper(), in_mark);
						//Debug.WriteLine("\t immediate children: " + e_old.ConstrainedRefsOnly().Select(cr => cr.ToString()).StringJoin(" "));
						Debug.Write("\t" + new StackTrace(true).GetFrames()[2]);
					}
				}
#endif
				base.RemoveEdge(in_mark);
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public override bool TryRemoveEdge(int in_mark, out Edge e)
		{
			return cd.TryRemove(in_mark, out e);
		}
	};
#endif
}