using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using glue;
using glue.Debugging;
using System.Runtime.InteropServices;
using glue.Collections.XSpinLock;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class HybridTray : Tray, IFreezableTray
	{
		public HybridTray(int tix, TypeMgr tm, int last_mark, int next_id)
			: base(tix, tm, last_mark, next_id)
		{
		}

		public void Freeze()
		{
			if (last_frozen_mark != uint.MaxValue)
				throw new Exception();
			last_frozen_mark = (uint)last_mark_issued;
		}

		public uint last_frozen_mark = uint.MaxValue;
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class HybridTray<T> : HybridTray where T : IDictionary<Int32, Edge>
	{
		public HybridTray(int tix, TypeMgr tm, int last_mark, int next_id)
			: base(tix, tm, last_mark, next_id)
		{
			for (int i = 0; i < Pools.Length; i++)
				Pools[i] = new HybridTrayConstraintPool(this, i);
		}

		public override string ToString()
		{
			return base.ToString() + typeof(T).ToString();
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		sealed public class HybridTrayConstraintPool : ConstraintPool
		{
			public HybridTrayConstraintPool(Tray tr, int i_feat)
				: base(tr, i_feat)
			{
				singl = new Dictionary<Int32, Edge>();
				var o = new FalseSharing.Padding2048();
				multi = (T)Activator.CreateInstance(typeof(T));
				Nop.X(o);
			}

			Dictionary<Int32, Edge> singl;
			T multi;

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override Edge GetEdge(Int32 m)
			{
				Debug.Assert(m != 0);
				Edge c;
				((uint)m <= ((HybridTray<T>)tr).last_frozen_mark ? (IDictionary<Int32, Edge>)singl : multi).TryGetValue(m, out c);
				return c;
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override bool TryGetEdge(int m, out Edge e)
			{
				Debug.Assert(m != 0);
				return ((uint)m <= ((HybridTray<T>)tr).last_frozen_mark ? (IDictionary<Int32, Edge>)singl : multi).TryGetValue(m, out e);
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <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 m, Edge c)
			{
				Debug.Assert(m != 0 && m >= tr._protect_mark);
				((uint)m <= ((HybridTray<T>)tr).last_frozen_mark ? (IDictionary<Int32, Edge>)singl : multi)[m] = c;
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override void RemoveEdge(Int32 m)
			{
				Debug.Assert(m != 0 && m >= tr._protect_mark);
				((uint)m <= ((HybridTray<T>)tr).last_frozen_mark ? (IDictionary<Int32, Edge>)singl : multi).Remove(m);
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override bool TryRemoveEdge(Int32 m, out Edge e)
			{
				Debug.Assert(m != 0 && m >= tr._protect_mark);
				IDictionary<Int32,Edge> d = (uint)m <= ((HybridTray<T>)tr).last_frozen_mark ? (IDictionary<Int32, Edge>)singl : multi;
				return d.TryGetValue(m, out e) ? d.Remove(m) : false;
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override bool ContainsInMark(Int32 m)
			{
				Debug.Assert(m != 0);
				return ((uint)m <= ((HybridTray<T>)tr).last_frozen_mark ? (IDictionary<Int32, Edge>)singl : multi).ContainsKey(m);
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override int Count
			{
				get { return singl.Count + multi.Count; }
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override IEnumerable<int> Marks
			{
				get
				{
					tr.mre_truncate_ok.WaitOne();
					return singl.Keys.Concat(multi.Keys);
				}
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override IEnumerable<Edge> Edges
			{
				get
				{
					tr.mre_truncate_ok.WaitOne();
					return singl.Values.Concat(multi.Values);
				}
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/// <summary>
			/// 
			/// </summary>
			///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			public override IEnumerable<KeyValuePair<int, Edge>> PoolEdges
			{
				get
				{
					tr.mre_truncate_ok.WaitOne();
					return singl.Concat(multi);
				}
			}
		};
	};
}