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

using miew.BitArray;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract partial class GlbDag : Instance
	{
		public GlbDag(TypeMgr mgr, String name, List<BaseFeatConstraint> bfc)
			: base(mgr, name, bfc)
		{
		}

		public int m_id;
		public ushort m_level;
		public BitArr m_code;

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		protected HashSet<Type> i_parents = new HashSet<Type>();

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		protected HashSet<Type> i_children = new HashSet<Type>();

		public ushort FindLevel()
		{
			if (m_level == 0 && this != tm.TopType)
			{
				if (i_children.Count == 0)
					m_flags |= Flags.Leaf;
				m_level = (ushort)(i_parents.Max(p => p.FindLevel()) + 1);
			}
			return m_level;
		}

		public int ChildCount { get { return i_children.Count; } }

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public bool IsGlb { get { return (m_flags & Flags.GlbType) > 0; } }

		/// <summary>
		/// leaf types have no children. They may have appropriate features
		/// </summary>
		public bool IsLeaf { get { return (m_flags & Flags.Leaf) > 0; } }

		public void AddIParent(Type p)
		{
			i_parents.Add(p);
			p.i_children.Add((Type)this);
		}

		public void RemoveIParent(Type p)
		{
			p.i_children.Remove((Type)this);
			i_parents.Remove(p);
		}

		public void AddIChild(Type c)
		{
			if (c == this)
				return;
			i_children.Add(c);
			c.i_parents.Add((Type)this);
		}

		public void RemoveIChild(Type c)
		{
			c.i_parents.Remove((Type)this);
			i_children.Remove(c);
		}

		/// <summary>
		/// Immediate parents only. Does not include this node
		/// </summary>
		public HashSet<Type> Parents { get { return i_parents; } }

		/// <summary>
		/// Immediate children only. Does not include this node
		/// </summary>
		public HashSet<Type> Children { get { return i_children; } }

		/// <summary>
		/// does not include this node
		/// </summary>
		public HashSet<Type> AllAncestors
		{
			get
			{
				HashSet<Type> l = AllAncestorsInclusive;
				l.Remove((Type)this);
				return l;
			}
		}

		public HashSet<Type> AllAncestorsInclusive
		{
			get
			{
				HashSet<Type> l = new HashSet<Type>();
				Action<Type> f = null;
				f = (n) =>
				{
					foreach (Type t in n.i_parents)
						if (!l.Contains(t))
							f(t);
					l.Add(n);
				};
				f((Type)this);
				return l;
			}
		}

		/// <summary>
		/// does not include this node
		/// </summary>
		public HashSet<Type> AllDescendants
		{
			get
			{
				HashSet<Type> l = AllDescendantsInclusive;
				l.Remove((Type)this);
				return l;
			}
		}

		public HashSet<Type> AllDescendantsInclusive
		{
			get
			{
				HashSet<Type> l = new HashSet<Type>();
				Action<Type> f = null;
				f = (n) =>
				{
					foreach (Type t in n.i_children)
						if (!l.Contains(t))
							f(t);
					l.Add(n);
				};
				f((Type)this);
				return l;
			}
		}

		public void SetHasAnyFeaturesFlagBelow()
		{
			m_flags |= Flags.HasAnyFeatures;
			foreach (Type c in this.i_children)
			{
				if ((c.m_flags & Flags.HasAnyFeatures) == 0)
					c.SetHasAnyFeaturesFlagBelow();
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Proper subtype relationship, ⊐, as in: t ⊐ *top*
		/// Returns 'true' if this node is in the proper child graph of the specified argument.
		/// Complementary to IsSupertypeOf.
		/// This is used by the graph closure, so it does not use the GLB cache, and must not be made to do so.
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public bool IsSubtypeOf(Type tt_other)
		{
			return (tt_other == this) ? false : m_code.AndGivesExact(tt_other.m_code);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Proper subsumption, ⊏, as in: top.Subsumes(everything-else).
		/// Returns 'true' if this node is properly in the parent graph of the specified argument.
		/// Complementary to IsSubtypeOf.
		/// This is used by the graph closure, so it does not use the GLB cache, and must not be made to do so.
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public bool IsSupertypeOf(Type tt_other)
		{
			return (tt_other == this) ? false : tt_other.m_code.AndGivesExact(m_code);
		}
	};
}