using System;
using System.Diagnostics;
using System.Threading;

using glue.Collections.XSpinLock;
using glue.Debugging;
using glue;

#pragma warning disable 0649

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public partial class Strings
	{
		FalseSharing.Padding60 fsp1;
		int next_string_id = 1;
		FalseSharing.Padding60 fsp2;

		readonly ConcurrentSymmetricDictionary<String, Int32> dict = new ConcurrentSymmetricDictionary<String, Int32>();
		readonly TypeMgr tm;
		public int string_id;
		public bool f_petrified = false;

		public Strings(TypeMgr tm)
		{
			this.tm = tm;
			Nop.X(fsp1, fsp2);
		}

		public void Petrify()
		{
			f_petrified = true;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// Guaranteed to preserve the coreference flag and return an _existing_ string mark, if successful
		/// Implicitly unifies down to *string* (at least)
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public bool Unify(int m_recycle, Edge e1, Edge e2, Tray tr_dst, out Edge result)
		{
			//Debug.Assert((e1.FlagsId & Edge.Flag.EtmMask) == Edge.Flag.EtmString || (e2.FlagsId & Edge.Flag.EtmMask) == Edge.Flag.EtmString);

			int id1 = (int)(e1.FlagsId & tm.MultiIdMask);
			int id2 = (int)(e2.FlagsId & tm.MultiIdMask);
			Edge.Flag f_coref = ((e1.FlagsId | e2.FlagsId) & Edge.Flag.Coreference);

			/// check for e1 not being a string type
			if ((e1.FlagsId & Edge.Flag.EtmMask) != Edge.Flag.EtmString)
			{
				if (!tm.IsTopId(e1) && !tm.CanUnify(string_id, id1))
					goto failed;
				id1 = 0;
				//goto use_e2;
			}

			/// check for e2 not being a string type
			if ((e2.FlagsId & Edge.Flag.EtmMask) != Edge.Flag.EtmString)
			{
				if (!tm.IsTopId(e2) && !tm.CanUnify(string_id, id2))
					goto failed;
				id2 = 0;
				//goto use_e1;
			}

			/// both are some kind of string
			if (id2 == 0 || id1 == id2)
				goto use_e1;
			if (id1 == 0)
				goto use_e2;

		failed:
			result = default(Edge);
			return false;

		use_e2:
			result = tr_dst.CreateRecycledEdge(f_coref | Edge.Flag.EtmString | (Edge.Flag)id2, m_recycle);
			return true;

		use_e1:
			result = tr_dst.CreateRecycledEdge(f_coref | Edge.Flag.EtmString | (Edge.Flag)id1, m_recycle);
			return true;
		}

		public String Get(Int32 sid)
		{
			return dict[sid];
		}

		public int GetOrAdd(String s)
		{
			return dict.GetOrAdd(s, Interlocked.Increment(ref next_string_id));
		}

		public int Count { get { return dict.Count; } }
	};
}