using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

#pragma warning disable 0649

namespace miew.Concurrency
{
	static public class Tasks
	{
		static Tasks()
		{
			TaskCompletionSource<Object> tcs = new TaskCompletionSource<Object>();
			tcs.SetResult(null);
			CompletedTask = tcs.Task;
		}

		static readonly public Task CompletedTask;

		static public Task<T> FromResult<T>(T result)
		{
			TaskCompletionSource<T> tcs = new TaskCompletionSource<T>(TaskCreationOptions.AttachedToParent);
			tcs.SetResult(result);
			return tcs.Task;
		}

		/// <summary>
		/// Caution: elements in the enumeration might be iterated more than once; beware of side-effects
		/// </summary>
		//static public Task WhenAllXX(IEnumerable<Task> iet)
		//{
		//    var c = iet as ICollection<Task>;
		//    if ((c != null && c.Count > 0) || iet.GetEnumerator().MoveNext())
		//        return TaskEx.WhenAll(iet);
		//    return CompletedTask;
		//}

		static public void RgtaskNop(Task[] rgt) { }

		public static Task Self
		{
			get
			{
				return Task.Factory.StartNew(Nop, CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Default).Parent();
			}
		}
		static void Nop() { }
	};

	public class TimedTask<T> : Task<T>
	{
		public TimedTask(Func<T> f)
			: base(f)
		{
		}
		public long Milliseconds { get { return ms; } }
		protected long ms;
		public new void Start()
		{
			Stopwatch sw = Stopwatch.StartNew();
			base.Start();
			base.ContinueWith(t => ms = sw.ElapsedMilliseconds, TaskContinuationOptions.ExecuteSynchronously);
		}
	};

	static public class Extensions
	{
		public static Task Parent(this Task t)
		{
			FieldInfo info = typeof(Task).GetField("m_parent", BindingFlags.NonPublic | BindingFlags.Instance);
			return info != null ? (Task)info.GetValue(t) : null;
		}

		public static bool HasAsAncestor(this Task t, Task parent)
		{
			Task walk = t;
			while ((walk = walk.Parent()) != null)
				if (walk == t)
					return true;
			return false;
		}

		public static bool AtomicStoreIfNull<T>(ref T pt, ref T in_out) where T : class
		{
			T actual = Interlocked.CompareExchange<T>(ref pt, in_out, null);
			if (actual == null)
				return true;
			in_out = actual;
			return false;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class ConcurrentList<T> : List<T>//: ConcurrentContainer<T>
	{
		//readonly List<T> list = new List<T>();
		SpinLock m_lock = new SpinLock(false);	// do not make this 'readonly'

		public ConcurrentList()
		{
		}

		public ConcurrentList(T t)
		{
			this.Add(t);
		}

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

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

		public new void AddRange(IEnumerable<T> items)
		{
			bool entered = false;
			try
			{
				m_lock.Enter(ref entered);
				base.AddRange(items);
			}
			finally
			{
				if (entered)
					m_lock.Exit(false);
			}
		}

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

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

		public new /*override*/ IEnumerator<T> GetEnumerator()
		{
			while (true)
			{
				bool entered = false;
				try
				{
					m_lock.Enter(ref entered);
					return base.ToArray().AsEnumerable<T>().GetEnumerator();
				}
				finally
				{
					if (entered)
						m_lock.Exit(false);
				}
			}
		}

		public IEnumerable<T> GetEnumerableUnsafe()
		{
			return base.ToArray().AsEnumerable<T>();
		}

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

		/// <summary>
		/// 
		/// </summary>
		public new /*override*/ bool Remove(T item) { throw new NotImplementedException(); }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class ConcurrentHashSet<T> : ConcurrentContainer<T>
	{
		readonly HashSet<T> hs = new HashSet<T>();
		SpinLock m_lock = new SpinLock(false);	// 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(false);
			}
		}

		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(false);
			}
		}

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

		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(false);
			}
		}

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

		public override IEnumerator<T> GetEnumerator()
		{
			return ToArray().AsEnumerable<T>().GetEnumerator();
		}


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


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class ConcurrentStringBuilder
	{
		readonly System.Text.StringBuilder sb = new System.Text.StringBuilder();
		SpinLock m_lock = new SpinLock(false);	// 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(false);
			}
		}

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

		public ConcurrentStringBuilder AppendFormat(System.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(false);
			}
		}

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

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


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <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 sealed class ConcurrentSymmetricDictionary<K1, K2>
	{
		FalseSharing.Padding60 fsp1;
		SpinLock slock = new SpinLock(false);	// do not make this 'readonly'
		FalseSharing.Padding60 fsp2;

		Dictionary<K1, K2> forward;
		Dictionary<K2, K1> reverse;

		public ConcurrentSymmetricDictionary(IEqualityComparer<K1> c)
		{
			forward = new Dictionary<K1, K2>(c);
			reverse = new Dictionary<K2, K1>();
			Debugging.Nop.X(fsp1, fsp2);
		}

		public ConcurrentSymmetricDictionary(IEqualityComparer<K2> c)
		{
			forward = new Dictionary<K1, K2>();
			reverse = new Dictionary<K2, K1>(c);
			Debugging.Nop.X(fsp1, fsp2);
		}

		public ConcurrentSymmetricDictionary()
		{
			forward = new Dictionary<K1, K2>();
			reverse = new Dictionary<K2, K1>();
			Debugging.Nop.X(fsp1, fsp2);
		}

		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 bool ContainsKey(K1 k1)
		{
			bool _b = false;
			try
			{
				slock.Enter(ref _b);
				return forward.ContainsKey(k1);
			}
			finally
			{
				if (_b) slock.Exit();
			}
		}

		public bool ContainsKey(K2 k2)
		{
			bool _b = false;
			try
			{
				slock.Enter(ref _b);
				return reverse.ContainsKey(k2);
			}
			finally
			{
				if (_b) slock.Exit();
			}
		}

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

		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();
			}
		}

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

		public IEnumerable<KeyValuePair<K1, K2>> Enumerate()
		{
			return forward;
		}
	};

	public static class FalseSharing
	{
		[StructLayout(LayoutKind.Explicit, Size = 56)]
		public struct Padding56
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 60)]
		public struct Padding60
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 64)]
		public struct Padding64
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 120)]
		public struct Padding120
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 124)]
		public struct Padding124
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 128)]
		public struct Padding128
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 248)]
		public struct Padding248
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 252)]
		public struct Padding252
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 256)]
		public struct Padding256
		{
		};

		[StructLayout(LayoutKind.Explicit, Size = 2048)]
		public struct Padding2048
		{
		};
	};

}