using System;
using System.Collections.Generic;
using System.Diagnostics;
using glue.Debugging;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// Lightweight, immutable encapsulation of a reference to a constraint (Edge) in the persistent store (ConstraintPool).
	/// This is used by unification for keeping a list the edges that need to be patched over as successive coreferences are
	/// discovered.
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public partial struct PoolMark : IEquatable<PoolMark>, IComparable<PoolMark>
	{
		public static readonly HashSet<PoolMark> EmptyPoolMarkHashSet = new HashSet<PoolMark>();

		public PoolMark(ConstraintPool cp, Int32 in_mark)
		{
			this.Pool = cp;
			this.in_mark = in_mark;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// The constraint pool in which the target constraint resides
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		readonly public ConstraintPool Pool;

		[DebuggerDisplay("{Feature.ToUpper(),nq}")]
		public String Feature { get { return Pool.Feature; } }

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// The mark to use in the specified constraint pool
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		readonly public Int32 in_mark;

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// The target constraint
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public Edge Constraint
		{
			get { return Pool.GetEdge(in_mark); }
		}
		public void SetConstraint(Edge e)
		{
			Pool.SetEdge(in_mark, e);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public void RemoveConstraint()
		{
			Pool.RemoveEdge(in_mark);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Type of the target constraint
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Type ConstraintType
		{
			get
			{
				Edge e;
				TypeMgr tm = Pool.tm;
				if (!Pool.TryGetEdge(in_mark, out e))
					return tm.TopType;
				return tm.GetEdgeType(e.FlagsId);
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// PoolMarks can be compared for equality and have a stable ordering
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public bool Equals(PoolMark other)
		{
			return in_mark == other.in_mark && Pool == other.Pool;
		}
		public static bool operator ==(PoolMark x, PoolMark y) { throw new NotImplementedException(); }
		public static bool operator !=(PoolMark x, PoolMark y) { throw new NotImplementedException(); }
		public override bool Equals(object obj)
		{
			throw new NotImplementedException();
		}
		public override int GetHashCode() { return (in_mark << 8) | Pool.i_feat; }

		public int CompareTo(PoolMark other)
		{
			if (this.Equals(other))
				return 0;
			int cm = this.in_mark - other.in_mark;
			if (cm != 0)
				return cm;
			return this.Pool.IntroducedBy.m_id - other.Pool.IntroducedBy.m_id;
		}
	};
}