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

using miew.Tally;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// Tfs interface
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public interface ITfs
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		///  Core access
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		void SetEdge(int i_feat, int mark, Edge e);
		bool TryGetEdge(int i_feat, int mark, out Edge e);
		bool RemoveEdge(int i_feat, int mark);
		void AddEdge(int i_feat, int mark, Edge e);
		Edge GetEdge(int i_feat, int mark);
		IEnumerable<FeatMarkEdge> FeatMarkEdges { get; }
		bool ContainsFeatMark(int i_feat, int mark);
		int EdgeCount { get; }

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		///  Coref management
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		Tfs Clone();

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		///  Debugging use
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		bool _ContainsInMark(int mark);
	};

	public interface ITarget
	{
	};

	public interface ITargetTfs : ITfs, ITarget
	{

	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract partial class Tfs : ISysObj
	{
		static public miew.Concurrency.FalseSharing.Padding56 p1;
		static public int next_tfs_id = 0;
		static public miew.Concurrency.FalseSharing.Padding56 p2;

		protected Tfs(TypeMgr tm)
		{
			this.tm = tm;
			//this.id = tm.config.system.MultiThreading ? Interlocked.Increment(ref next_id) : ++next_id;
			this.id = Interlocked.Increment(ref next_tfs_id);
			//this.id = this.GetHashCode();
		}
		protected Tfs(TypeMgr tm, Edge e)
			: this(tm)
		{
			this.Edge = e;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		readonly public TypeMgr tm;

		public int id;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public int DisplayId { get { return id; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Edge Edge;

		public String Name;

		public byte[] coref_tally_map;

		public byte[] coref_tally_map_restricted;

		public int next_mark = 1;
		public int next_coref_mark = -1;

		public static readonly byte[] NoCorefsTallyMap = new byte[0];

		public abstract void SetEdge(int i_feat, int mark, Edge e);
		public abstract bool TryGetEdge(int i_feat, int mark, out Edge e);
		public abstract Edge.Flag TryGetFlagsMark(int i_feat, int mark, out int m);
		public abstract ulong GetUlEdge(FeatMark fm);
		public abstract bool RemoveEdge(int i_feat, int mark);
		public abstract void AddEdge(int i_feat, int mark, Edge e);
		public abstract Edge GetEdge(int i_feat, int mark);
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public abstract IEnumerable<FeatMarkEdge> FeatMarkEdges { get; }
		public abstract bool ContainsFeatMark(int i_feat, int mark);
		public abstract int EdgeCount { get; }
		public virtual int ScratchAlloc { get { return EdgeCount; } }
		public abstract bool _ContainsInMark(int mark);

		public virtual bool IsRestricted
		{
			get { return false; }
		}

		/// <summary>
		/// Cloning a TFS allows it to be used multiple times within the same unification operation (including within the
		/// same TFS) while having its coreferences maintained as distinct.
		/// </summary>
		public abstract Tfs Clone();

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public Type Type
		{
			get
			{
				return (Edge.FlagsId & Edge.Flag.EtmMask) == agree.Edge.Flag.EtmString ?
					tm.StringType :
					tm.type_arr[(int)(Edge.FlagsId & Edge.Flag.MultiIdMask)];
			}
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public TfsSection GetSection(Edge e, int ix)
		{
			//Debug.Assert(this._ContainsInMark(e.Mark));
			return new TfsSection(this, e, ix);
		}

		public TfsSection GetSection(PathEdge pe, int ix)
		{
			//Debug.Assert(this._ContainsInMark(e.Mark));
			return new TfsSection(this, pe, ix);
		}

		public TfsSection GetSection(FsPath p)
		{
			Edge e = Edge;
			foreach (String f in p)
			{
				if (e.Mark == 0)
					return null;
				int i_feat = tm.GetFeatureIndex(f);
				if (i_feat == -1 || !TryGetEdge(i_feat, e.Mark, out e))
					return null;
			}
			return new TfsSection(this, e, 0);
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TfsEdge TfsEdge { get { return new TfsEdge(this, Edge); } }

		public TfsEdge GetSectionTfsEdge(Edge e)
		{
			return new TfsEdge(this, e);
		}

		//public Edge GetEdge(int mark)
		//{
		//    foreach (var fme in FeatMarkEdges)
		//        if (fme.mark == mark)
		//            return fme.e;
		//    return default(Edge);
		//}
		public Edge GetCorefEdge(int out_mark)
		{
			if (out_mark == Edge.Mark)
				return Edge;
			foreach (var fme in FeatMarkEdges)
				if (fme.e.Mark == out_mark)
					return fme.e;
			return default(Edge);
		}
		public FeatMark GetHostFeatMark(int out_mark)
		{
			Debug.Assert(out_mark > 0);	/// if coreferenced, there are multiple possible results
			if (out_mark != Edge.Mark)
				foreach (var fme in FeatMarkEdges)
					if (fme.e.Mark == out_mark)
						return fme.FeatMark;
			return default(FeatMark);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// ISysObj.SysObjName
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public string SysObjName
		{
			get { return ToString(); }
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// ISysObj.SysObjDescription
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public string SysObjDescription
		{
			get { return ToString(); }
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// ISysObj.SysObjChildren
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public miew.ReadOnly.IReadOnlyDictionary<string, ISysObj> SysObjChildren
		{
			get { return SysObjHelper<ISysObj>.Empty; }
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// ISysObj.SysObjParent
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public ISysObj SysObjParent
		{
			get { return tm.g; }
		}

		public bool IsTarget { get { return this is TargetTfs || (this is TfsSection && ((TfsSection)this).mother.IsTarget); } }
		static readonly Char[] tc = { '…', ' ', '⊣' };
		public override string ToString()
		{
			return String.Format("#{0}:{1}", id.ToString("X"), Edge.ToString(tm).TrimEnd(tc).Replace(' ', '/'));
		}
		public string ToString(bool f_type)
		{
			return f_type ? ToString() : String.Format("#{0}:@{1}", id.ToString("X"), Edge.Mark);
		}
	};
}