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

class Program
{
	public class TestException : Exception
	{
	}

	//static LockFreeDictionary<String, String> d_ss = new LockFreeDictionary<String, String>();
	//static LockFreeDictionary<int, String> d_is = new LockFreeDictionary<int, String>();
	static LockFreeDictionary<Guid, String> d_gs = new LockFreeDictionary<Guid, string>();
	static public bool f_stop = false;

	static void Main(string[] args)
	{
		//int? i = null;
		//int? j = null;
		//bool zzz = i.Equals(null);
		//Nullable.Equals(i, j);
		
		//var z = new Dictionary<String, String>();
		//z.Add("foo", "bar");
		//z.Add("foo", "bar");

		//d_ss.Add("Hello", "Lock-free");

		//Debug.Assert(d_ss["Hello"] == "Lock-free");

		//Test();
#if false
		//unchecked
		{
			ulong h = 0;// 0xaaaaaaaaaaaaaaaa;
			while (true)
			{
				h ^= 0x55555555aaaaaaaa;
				h ^= 0xaaaaaaaa55555555;
				if (h != 0xffffffffffffffff)
					Debugger.Break();
			}
		}
#endif
#if false
		unchecked
		{
			long m_tail = 0;
			long new_tail;
			long tail = 0x0000170e000000e9;
			int gx = -1;
			while (true)
			{
				/// the tail needs to be advanced
				new_tail = tail + 0x0000000100000000;
				new_tail &= (long)0xFFFFFFFF00000000;
				new_tail |= (uint)gx;

				if ((new_tail & 0x0ff0) == 0x0ff0)
				{
					Debugger.Break();
				}

				//Int64 prev = 
				Interlocked.CompareExchange(ref m_tail, new_tail, tail);
			}
		}
#endif
		//LockFreeDictionary<int, String> foo = new LockFreeDictionary<int, string>();
		//foo.Add(99, "hello");


		//		d_gs.m_config.TestFreelist();
		//	Environment.Exit(0);
#if false
		d_is.Add(99999, "five nines");

		d_is.Add(13, "first");
		d_is.Add(50, "second");
		d_is.Add(87, "third");
		d_is.Add(124, "fourth");
		d_is.Add(161, "fifth");


		String s;
		Debug.Assert(d_is.TryRemove(87, out s));
#endif
#if false
		Int64 h = 0;
		Action a1 = () =>
		{
			while (true)
			{
				Interlocked.Exchange(ref h, 0x2aaaaaaaaaaaaaaa);
				Interlocked.Exchange(ref h, 0x5555555555555555);
			}
		};

		Action a2 = () =>
		{
			while (true)
			{
				Int64 i = Read64(ref h);
				if (i != 0x2aaaaaaaaaaaaaaa && i != 0x5555555555555555)
					throw new Exception("immediately fails with a torn read on 32-bit .NET");
			}
		};

		Task.Factory.StartNew(a1);
		Task.Factory.StartNew(a1);
		Task.Factory.StartNew(a1);
		Task.Factory.StartNew(a2);



		Console.ReadKey();
		//d_ss.m_config.Test();
#endif


		//Console.WriteLine(d_is.m_config.Dump());

		//Guid gg = Guid.NewGuid();
		//d_gs.Add(gg, "abcd");
		//d_gs.TryUpdate(gg, String.Intern("efgh"), "abcd");
		//	Test();

		int c_tasks = Environment.ProcessorCount;
		//c_tasks = 1;

		Task[] tasks = new Task[c_tasks];

		int i = 0;
		while (true)
		{
			g_num = 0;
			d_gs = new LockFreeDictionary<Guid, string>();
			if (Debugger.IsAttached)
			{
				Console.WriteLine("=============== start {0} =================", i);
				Console.Out.Flush();
			}

#if true
			for (int z = 0; z < tasks.Length; z++)
			{
				tasks[z] = Task.Factory.StartNew(Test);
			}

			for (int z = 0; z < tasks.Length; z++)
			{
				try
				{
					tasks[z].Wait();
				}
				catch (AggregateException aex)
				{
					if (!(aex.Flatten().InnerException is TestException))
						throw;
				}
#if false
				catch
				{
					Console.ForegroundColor = ConsoleColor.Red;
					Console.WriteLine("failed");
					Console.Out.Flush();
					Console.ResetColor();
					break;
				}
#endif
			}

			if (i % 1000 == 0)
				Console.WriteLine(i);

			if (Debugger.IsAttached)
				Console.Write("check...");
			if (!d_gs.m_config.m_buckets.Check())
				throw new Exception();
			if (Debugger.IsAttached)
				Console.WriteLine(" ok");

			//		Console.ReadKey();
			//		f_stop = true;
			//Task.WaitAll(tasks);
			d_gs = null;
			i++;
		}
#endif
	}
	static int g_num = 0;

	static public ManualResetEvent mre_go = new ManualResetEvent(true);

	static void Test()
	{
		int num = Interlocked.Increment(ref g_num);
		int iter = 0;
		Random rnd = new Random(Guid.NewGuid().ToByteArray()[0]);
		Dictionary<Guid, String> netd = new Dictionary<Guid, string>();
		while (!f_stop && d_gs.Count < 1000)
		{
			mre_go.WaitOne();

			int r = rnd.Next();
			if ((netd.Count > 0 && (r & 1) == 1)  )// || netd.Count > 200)
			{
				// remove and check

				var kvp = netd.ElementAt(rnd.Next(netd.Count));

				String got_val;
				if (!d_gs.TryGetValue(kvp.Key, out got_val))
				{
					Console.ForegroundColor = ConsoleColor.Red;
					int retry = 0;
					do
					{
						Console.WriteLine("didn't get {0} {1}\r\npause and retry #{2}...", kvp.Key, kvp.Value, retry);
						Thread.Sleep(10);
						if (d_gs.TryGetValue(kvp.Key, out got_val))
						{
							Console.WriteLine("ok!");
							Console.Out.Flush();
							Console.ResetColor();
							goto ok;
						}
					}
					while (retry++ < 5);

					Console.Out.Flush();
					Console.ResetColor();

					netd.Remove(kvp.Key);
					continue;
				}
			ok:
				if (kvp.Value != got_val)
				{
					Console.ForegroundColor = ConsoleColor.Red;
					Console.WriteLine("wrong value for {0} {1} : got {2}", kvp.Key, kvp.Value, got_val);
					Console.Out.Flush();
					Console.ResetColor();
				}

				if (!d_gs.TryRemove(kvp.Key, out got_val))
				{
					Console.Beep();
					Console.Beep();
					Console.ForegroundColor = ConsoleColor.Red;
					Console.WriteLine("couldn't remove confirmed value {0} {1}", kvp.Key, got_val);
					Console.Out.Flush();
					Console.ResetColor();
				}
				else
				{
					if (got_val != kvp.Value)
					{
						Console.ForegroundColor = ConsoleColor.Red;
						Console.WriteLine("wrong value during removal {0} {1} : got {2}", kvp.Key, kvp.Value, got_val);
						Console.Out.Flush();
						Console.ResetColor();
					}

					if (!netd.Remove(kvp.Key))
					{
						Console.ForegroundColor = ConsoleColor.Red;
						Console.WriteLine("remove error in the .NET reference dict {0} {1} : got {2}", kvp.Key, kvp.Value);
						Console.Out.Flush();
						Console.ResetColor();
					}
				}
			}
			else
			{
				// add
				var rgb = Guid.NewGuid().ToByteArray();
				rgb[0] = (byte)num;
				Guid k = new Guid(rgb);

				String v = "--" + k.ToString() + "--";

				if (netd.ContainsKey(k))
				{
					if (!d_gs.ContainsKey(k))
					{
						Console.Beep();
						Console.Beep();
						Console.ForegroundColor = ConsoleColor.Red;
						Console.WriteLine("selected Add key from control dict not found {0}", k);
						Console.Out.Flush();
						Console.ResetColor();
					}
				}
				else
				{
					if (!d_gs.TryAdd(k, v))
					{
						Console.Beep();
						Console.Beep();
						Console.ForegroundColor = ConsoleColor.Red;
						Console.WriteLine("add error {0} {1}", k, v);
						Console.Out.Flush();
						Console.ResetColor();
					}
					netd.Add(k, v);
				}
			}

			iter++;
			if (num == 1)
			{
				//if (iter % 1000 == 0)
					//Console.WriteLine("{0} {1,-4} {2,-4}", iter, netd.Count, d_gs.m_config.m_c_free);

#if false
				if (iter == 100)
				{
					d_gs.m_config.Verify();
				}
#endif

#if false
				if (iter == 200000)
				{
					f_stop = true;
					Thread.Sleep(15);
					Console.WriteLine(d_gs.m_config.Dump());
					Console.Out.Flush();
					Debugger.Break();
				}
#endif
				//if (iter % 10000 == 0)
					//Console.WriteLine("{0}", d_gs.m_config.m_c_free);
#if false
				if (iter == 1000)
				{
				//	f_stop = true;
					Thread.Sleep(15);
					Console.WriteLine(d_gs.m_config.Dump());
					Debugger.Break();
				}
#endif
			}

		//	if (iter == 500000)
				//return;
		}
	}
}