using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

/// http://download.microsoft.com/download/B/C/F/BCFD4868-1354-45E3-B71B-B851CD78733D/PerformanceCharacteristicsOfThreadSafeCollection.pdf

namespace tgcs.Util.Concurrency
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class ConcurrentList<T> : ConcurrentContainer<T>
	{
		readonly List<T> list = new List<T>();
		SpinLock m_lock = new SpinLock();	// do not make this 'readonly'
		int c_inert = 0;

		public override void Clear()
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				list.Clear();
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public override bool Add(T item)
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				list.Add(item);
				return true;
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		/// <summary>
		/// (useless for concurrency)
		/// </summary>
		public override bool Contains(T item)
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				return list.Contains(item);
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		/// <summary>
		/// (useless for concurrency)
		/// </summary>
		public override int Count
		{
			get
			{
				bool entered = false;
				try
				{
					m_lock.Enter(ref entered);
					return list.Count - c_inert;
				}
				finally
				{
					if (entered)
						m_lock.Exit();
				}
			}
		}

		public override IEnumerator<T> GetEnumerator()
		{
			int i = 0;
			while (true)
			{
				bool entered = false;
				try
				{
					m_lock.Enter(ref entered);
					while (true)
					{
						if (i >= list.Count)
							yield break;
						else
						{
							T item = list[i++];
							// exiting a 'try' block with 'yield return' does not execute 'finally' each time
							// http://blogs.msdn.com/b/oldnewthing/archive/2008/08/14/8862242.aspx
							entered = false;
							m_lock.Exit();
							yield return item;
							m_lock.Enter(ref entered);
							break;
						}
					}
				}
				finally
				{
					if (entered)
						m_lock.Exit();
				}
			}
		}

		public T[] ToArray()
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				return list.ToArray();
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		/// <summary>
		/// Would interfere with in-situ enumeration
		/// </summary>
		public override bool Remove(T item) { throw new NotSupportedException(); }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class ConcurrentHashSet<T> : ConcurrentContainer<T>
	{
		readonly HashSet<T> hs = new HashSet<T>();
		SpinLock m_lock = new SpinLock();	// do not make this 'readonly'
		T any = default(T);

		public T Peek() { return any; }

		public override bool Add(T item)
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				bool b = hs.Add(item);
				if (b)
					any = item;
				return b;
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public override bool Remove(T item)
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				bool b = hs.Remove(item);
				if (b && any.Equals(item))
				{
					if (hs.Count == 0)
						any = default(T);
					else
					{
						var e = hs.GetEnumerator();
						e.MoveNext();
						any = e.Current;
					}
				}
				return b;
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public override void Clear()
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				hs.Clear();
				any = default(T);
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public override bool Contains(T item)
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				return hs.Contains(item);
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public T[] ToArray()
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				return hs.ToArray();
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public override int Count { get { return hs.Count; } }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class ConcurrentStringBuilder
	{
		readonly StringBuilder sb = new StringBuilder();
		SpinLock m_lock = new SpinLock();	// do not make this 'readonly'

		public void Clear()
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				sb.Clear();
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public ConcurrentStringBuilder Append(String s)
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				sb.Append(s);
				return this;
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public ConcurrentStringBuilder AppendFormat(String fmt, params Object[] args)
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				sb.AppendFormat(fmt, args);
				return this;
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public override String ToString()
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				return sb.ToString();
			}
			finally
			{
				if (entered)
					m_lock.Exit();
			}
		}

		public int Length
		{
			get
			{
				bool entered = false;
				try
				{
					m_lock.Enter(ref entered);
					return sb.Length;
				}
				finally
				{
					if (entered)
						m_lock.Exit();
				}
			}
			set
			{
				bool entered = false;
				try
				{
					m_lock.Enter(ref entered);
					sb.Length = value;
				}
				finally
				{
					if (entered)
						m_lock.Exit();
				}
			}
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class ConcurrentContainer<T> : ISet<T>
	{
		public abstract bool Add(T item);

		public abstract void Clear();

		public abstract bool Contains(T item);

		public abstract int Count { get; }

		public abstract bool Remove(T item);

		public virtual IEnumerator<T> GetEnumerator() { throw new NotImplementedException(); }

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }

		void ICollection<T>.Add(T item) { Add(item); }

		public bool IsReadOnly { get { return false; } }

		public void CopyTo(T[] array, int arrayIndex) { throw new NotSupportedException(); }

		public void ExceptWith(IEnumerable<T> other) { throw new NotSupportedException(); }

		public void IntersectWith(IEnumerable<T> other) { throw new NotSupportedException(); }

		public bool IsProperSubsetOf(IEnumerable<T> other) { throw new NotSupportedException(); }

		public bool IsProperSupersetOf(IEnumerable<T> other) { throw new NotSupportedException(); }

		public bool IsSubsetOf(IEnumerable<T> other) { throw new NotSupportedException(); }

		public bool IsSupersetOf(IEnumerable<T> other) { throw new NotSupportedException(); }

		public bool Overlaps(IEnumerable<T> other) { throw new NotSupportedException(); }

		public bool SetEquals(IEnumerable<T> other) { throw new NotSupportedException(); }

		public void SymmetricExceptWith(IEnumerable<T> other) { throw new NotSupportedException(); }

		public void UnionWith(IEnumerable<T> other) { throw new NotSupportedException(); }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class ConcurrentSymmetricDictionary<K1, K2>
	{
		SpinLock slock = new SpinLock(false);	// do not make this 'readonly'
		Dictionary<K1, K2> forward;
		Dictionary<K2, K1> reverse;

		public ConcurrentSymmetricDictionary(IEqualityComparer<K1> c)
		{
			forward = new Dictionary<K1, K2>(c);
			reverse = new Dictionary<K2, K1>();
		}

		public ConcurrentSymmetricDictionary(IEqualityComparer<K2> c)
		{
			forward = new Dictionary<K1, K2>();
			reverse = new Dictionary<K2, K1>(c);
		}

		public ConcurrentSymmetricDictionary()
		{
			forward = new Dictionary<K1, K2>();
			reverse = new Dictionary<K2, K1>();
		}

		public K2 this[K1 k1]
		{
			get
			{
				return forward[k1];
			}
			set
			{
				bool _b = false;
				try
				{
					slock.Enter(ref _b);
					forward[k1] = value;
					reverse[value] = k1;
				}
				finally
				{
					if (_b) slock.Exit();
				}
			}
		}

		public K1 this[K2 k2]
		{
			get
			{
				return reverse[k2];
			}
			set
			{
				bool _b = false;
				try
				{
					slock.Enter(ref _b);
					reverse[k2] = value;
					forward[value] = k2;
				}
				finally
				{
					if (_b) slock.Exit();
				}
			}
		}

		public void Add(K1 k1, K2 k2)
		{
			bool _b = false;
			try
			{
				slock.Enter(ref _b);
				forward.Add(k1, k2);
				reverse.Add(k2, k1);
			}
			finally
			{
				if (_b) slock.Exit();
			}
		}


		public bool Remove(K1 k1)
		{
			bool _b = false;
			try
			{
				slock.Enter(ref _b);
				K2 k2;
				if (!forward.TryGetValue(k1, out k2))
					return false;
				forward.Remove(k1);
				reverse.Remove(k2);
				return true;
			}
			finally
			{
				if (_b) slock.Exit();
			}
		}

		public bool Remove(K2 k2)
		{
			bool _b = false;
			try
			{
				slock.Enter(ref _b);
				K1 k1;
				if (!reverse.TryGetValue(k2, out k1))
					return false;
				reverse.Remove(k2);
				forward.Remove(k1);
			}
			finally
			{
				if (_b) slock.Exit();
			}
			return true;
		}

		public void Clear()
		{
			bool _b = false;
			try
			{
				slock.Enter(ref _b);
				forward.Clear();
				reverse.Clear();
			}
			finally
			{
				if (_b) slock.Exit();
			}
		}

		public bool TryGetValue(K2 k2, out K1 k1)
		{
			return reverse.TryGetValue(k2, out k1);
		}
		public bool TryGetValue(K1 k1, out K2 k2)
		{
			return forward.TryGetValue(k1, out k2);
		}

		public K2 GetOrAdd(K1 k1, K2 k2)
		{
			bool _b = false;
			try
			{
				slock.Enter(ref _b);
				K2 v;
				if (!forward.TryGetValue(k1, out v))
				{
					v = k2;
					forward.Add(k1, v);
					reverse.Add(v, k1);
				}
				return v;
			}
			finally
			{
				if (_b) slock.Exit();
			}
		}
	};
}