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

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public partial struct FeatMark : IEquatable<FeatMark>, IComparable<FeatMark>
	{
		public static readonly HashSet<FeatMark> EmptyHashSet = new HashSet<FeatMark>();

		public FeatMark(int i_feat, int m)
		{
			this.i_feat = i_feat;
			this.m = m;
		}
		public unsafe FeatMark(ulong ul)
		{
			this = *(FeatMark*)&ul;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int i_feat;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int m;

		public bool Equals(FeatMark other)
		{
			return m == other.m && i_feat == other.i_feat;
		}
		public override int GetHashCode()
		{
			return m ^ i_feat;
		}
		public int CompareTo(FeatMark other)
		{
			int d = m - other.m;
			return d != 0 ? d : i_feat - other.i_feat;
		}
		public Edge Constraint(Tfs tfs)
		{
			return tfs.GetEdge(i_feat, m);
		}
		public static unsafe explicit operator ulong(FeatMark fm)
		{
			return *(ulong *)&fm;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public struct FeatMarkEdge : IComparable<FeatMarkEdge>, IEquatable<FeatMarkEdge>
	{
		public FeatMarkEdge(FeatMark fm, Edge e)
		{
			this.i_feat = fm.i_feat;
			this.mark = fm.m;
			this.e = e;
		}
		public FeatMarkEdge(int i_feat, int mark, Edge e)
		{
			this.i_feat = i_feat;
			this.mark = mark;
			this.e = e;
		}
		public FeatMarkEdge(ulong ul, Edge e)
		{
			this.i_feat = (int)(ul >> 32);
			this.mark = (int)ul;
			this.e = e;
		}
		public FeatMarkEdge(int i_feat, int mark)
		{
			this.i_feat = i_feat;
			this.mark = mark;
			this.e = default(Edge);
		}
		public int i_feat;
		public int mark;
		public Edge e;

		public FeatMark FeatMark { get { return new FeatMark(i_feat, mark); } }

		public int CompareTo(FeatMarkEdge other)
		{
			int d = mark - other.mark;
			return d != 0 ? d : i_feat - other.i_feat;
		}

#if DEBUG
		public override string ToString()
		{
			Grammar g = Grammar._singleton;
			TypeMgr tm;
			FeatureInfo[] rgfi;
			String f;
			if (g == null || (tm = g.tm) == null || (rgfi = tm.feat_arr) == null || i_feat >= rgfi.Length || (f = rgfi[i_feat].feature) == null)
				return String.Format("{0} {1} {2}", i_feat, mark, e.ToString());
			String s = mark + "/" + rgfi[i_feat].feature.ToUpper();
			return String.Format("{0,20} {1}", s, e);
		}
#endif

		public bool Equals(FeatMarkEdge other)
		{
			return this.mark == other.mark && this.i_feat == other.i_feat && this.e.Mark == other.e.Mark && this.e.FlagsId == other.e.FlagsId;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public struct TfsFeatMark : IEquatable<TfsFeatMark>
	{
		public static readonly HashSet<TfsFeatMark> EmptyHashSet = new HashSet<TfsFeatMark>();

		public TfsFeatMark(Tfs tfs, int i_feat, int m)
		{
			this.tfs = tfs;
			this.i_feat = i_feat;
			this.m = m;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Tfs tfs;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int i_feat;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int m;

		public bool Equals(TfsFeatMark other)
		{
			return m == other.m && i_feat == other.i_feat && tfs == other.tfs;
		}
		public override int GetHashCode()
		{
			return m ^ i_feat ^ tfs.id;
		}
		public Edge Constraint
		{
			get { return tfs.GetEdge(i_feat, m); }
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public struct TfsEdge : IEquatable<TfsEdge>, IComparable<TfsEdge>
	{
		public TfsEdge(Tfs tfs, Edge e)
		{
			this.tfs = tfs;
			this.e = e;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Tfs tfs;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge e;

		public bool Equals(TfsEdge other)
		{
			return e.Mark == other.e.Mark && e.FlagsId == other.e.FlagsId && tfs == other.tfs;
		}
		public override int GetHashCode()
		{
			return e.Mark ^ (int)e.FlagsId ^ tfs.id;
		}

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

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

		public int CompareTo(TfsEdge other)
		{
			int d = this.tfs.id - other.tfs.id;
			if (d == 0 && (d = this.e.Mark - other.e.Mark) == 0)
				d = this.e.FlagsId - other.e.FlagsId;
			return d;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public struct TfsixEdge : IEquatable<TfsixEdge>, IComparable<TfsixEdge>
	{
		[DebuggerHidden]
		public TfsixEdge(short tfsix, Edge e)
		{
			this.tfsix = tfsix;
			this.e = e;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public short tfsix;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge e;

		public bool Equals(TfsixEdge other)
		{
			return e.Mark == other.e.Mark && e.FlagsId == other.e.FlagsId && tfsix == other.tfsix;
		}
		public override int GetHashCode()
		{
			return e.Mark ^ (int)e.FlagsId ^ tfsix;
		}

		//[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		//public ConstraintRef[] _BELOW
		//{
		//    get
		//    {
		//        if ((e.FlagsId & Edge.Flag.EtmNonBareType) == 0)
		//            return ConstraintRef.NoneBelow;
		//        return tfs.AllConstraintRefs(e).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("ix: {0} {1}", tfsix, e);
		}

		public int CompareTo(TfsixEdge other)
		{
			int d = this.tfsix - other.tfsix;
			if (d == 0 && (d = this.e.Mark - other.e.Mark) == 0)
				d = this.e.FlagsId - other.e.FlagsId;
			return d;
		}
	};

	public partial struct TfsMark
	{
		static public TfsMark[] None = new TfsMark[0];

		public TfsMark(Tfs tfs, int mark)
		{
			this.tfs = tfs;
			this.mark = mark;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Tfs tfs;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int mark;
		public override string ToString()
		{
			if (tfs == null)
				return "(null tfs)";
			return String.Format("     {0:X}/{1} ({2})", tfs.id, mark, tfs.GetCorefEdge(mark).ToString());
		}
	};
}