using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace miew.Debugging
{
	using String = System.String;

	public static class Nop
	{
		[MethodImpl(MethodImplOptions.NoInlining)]
		public static void X(params Object[] objs) { }

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static void X() { }

		public static void CodeCoverage(bool condition = true)
		{
			if (condition)
			{
				if (Debugger.IsAttached)
					Debugger.Break();
				else if (!IsGuiApplication)
				{
					Console.Out.WriteLineColorSync("$red code coverage");
					Console.WriteLine(new StackTrace().GetFrames().Skip(1).First().ToString());
				}
				else
				{
					MessageBox("code coverage");
				}
			}
		}
		public static void CodeCoverage(String msg)
		{
			if (Debugger.IsAttached)
				Debugger.Break();
			else if (!IsGuiApplication)
			{
				Console.Out.WriteLineColorSync("$red code coverage: " + msg);
				Console.WriteLine(new StackTrace().GetFrames().Skip(1).First().ToString());
			}
			else
			{
				MessageBox("code coverage: " + msg);
			}
		}

		public static void MessageBox(String text)
		{
			var pf_mod = AppDomain.CurrentDomain
				.GetAssemblies()
				.First(a => a.ManifestModule.Name.ToLower().StartsWith("presentationframework."));

			if (pf_mod == null)
				throw new Exception(text);

			pf_mod.GetType("System.Windows.MessageBox")
				.GetMethod("Show", new System.Type[] { typeof(String) })
				.Invoke(null, new Object[] { text });
		}

		public static bool single_threaded = false;

		static int i_gui = -1;
		static public bool IsGuiApplication
		{
			get
			{
				if (i_gui == -1)
					i_gui = AppDomain.CurrentDomain.GetAssemblies().Any(a => a.ManifestModule.Name.ToLower().StartsWith("windowsbase.")) ? 1 : 0;
				return i_gui == 1;
			}
		}

		static public readonly bool False = false;

	};

	public class DebugTextWriter : StreamWriter
	{
		public DebugTextWriter()
			: base(new DebugOutStream(), Encoding.Unicode, 1024)
		{
			this.AutoFlush = true;
		}

		class DebugOutStream : Stream
		{
			public override void Write(byte[] buffer, int offset, int count)
			{
				Debug.Write(Encoding.Unicode.GetString(buffer, offset, count));
			}

			public override bool CanRead { get { return false; } }
			public override bool CanSeek { get { return false; } }
			public override bool CanWrite { get { return true; } }
			public override void Flush() { Debug.Flush(); }
			public override long Length { get { throw new InvalidOperationException(); } }
			public override int Read(byte[] buffer, int offset, int count) { throw new InvalidOperationException(); }
			public override long Seek(long offset, SeekOrigin origin) { throw new InvalidOperationException(); }
			public override void SetLength(long value) { throw new InvalidOperationException(); }
			public override long Position
			{
				get { throw new InvalidOperationException(); }
				set { throw new InvalidOperationException(); }
			}
		};
	};

	public class TimingReport : IDisposable
	{
		Stopwatch sw;
		TextWriter tw;
		public TimingReport(TextWriter tw, String name)
		{
			this.tw = tw;
			tw.Write("========== ");
			if (tw == Console.Out)
				Console.ForegroundColor = ConsoleColor.Yellow;
			tw.Write(name);
			if (tw == Console.Out)
				Console.ResetColor();
			tw.WriteLine(" " + new String('=', System.Math.Max(80 - name.Length, 5)));
			sw = Stopwatch.StartNew();
		}

		public void Dispose()
		{
			String time;
			double ms = sw.ElapsedMilliseconds;
			if (ms < 10000)
				time = ms.ToString("0") + " ms";
			else
			{
				ms /= 1000.0;
				if (ms < 120)
					time = ms.ToString("0.00") + " s";
				else
					time = sw.Elapsed.ToString("hh\\:mm\\:ss");
			}
			String m = "ok: " + time;
			tw.Write("============================================================ ");
			if (tw == Console.Out)
				Console.ForegroundColor = ConsoleColor.Green;
			tw.Write(m);
			if (tw == Console.Out)
				Console.ResetColor();
			tw.WriteLine(" " + new String('=', 30 - m.Length));
		}
	};

	public static class Extensions
	{
		public static void WriteLineColorSync(this TextWriter tw, String fmt, params Object[] args)
		{
			tw.WriteColorSync(fmt + Environment.NewLine, args);
		}

		public static void WriteColorSync(this TextWriter tw, String fmt, params Object[] args)
		{
			String z = String.Format(fmt, args);

			if (tw != Console.Out)
			{
				StringBuilder sb = new StringBuilder();
				IEnumerator<String> ies = z.Split(new Char[] { '$' }).AsEnumerable<String>().GetEnumerator();
				if (!ies.MoveNext())
					return;
				sb.Append(ies.Current);
				while (ies.MoveNext())
				{
					String part = ies.Current;
					int ixsp = part.IndexOf(' ');
					if (ixsp == -1)
						throw new Exception();
					part = part.Substring(ixsp + 1);
					sb.Append(part);
				}
				tw.WriteLine(sb.ToString());
				return;
			}

			z = z.Replace("↻", "E");
			lock (Console.Out)
			{
				IEnumerator<String> ies = z.Split(new Char[] { '$' }).AsEnumerable<String>().GetEnumerator();
				if (!ies.MoveNext())
					return;
				Console.Write(ies.Current);
				while (ies.MoveNext())
				{
					String part = ies.Current;
					int ixsp = part.IndexOf(' ');
					if (ixsp == -1)
						ixsp = part.Length - 1;
					String s_color = part.Substring(0, ixsp).ToLower();
					part = part.Substring(ixsp + 1);
					if (s_color == "")
					{
						Console.ResetColor();
						part = " " + part;
					}
					else if (s_color == "reset")
						Console.ResetColor();
					else
					{
						ConsoleColor cc;
						if (Enum.TryParse<ConsoleColor>(s_color, true, out cc))
							Console.ForegroundColor = cc;
					}
					Console.Write(part);
				}
				Console.ResetColor();
			}
		}

		public static void WriteLineColor(this TextWriter console, String fmt, params Object[] args)
		{
			WriteLineColor(console, CancellationToken.None, fmt, args);
		}
		public static void WriteLineColor(this TextWriter tw, CancellationToken ct, String fmt, params Object[] args)
		{
			String z = String.Format(fmt, args);

			if (tw != Console.Out)
			{
				StringBuilder sb = new StringBuilder();
				IEnumerator<String> ies = z.Split(new Char[] { '$' }).AsEnumerable<String>().GetEnumerator();
				if (!ies.MoveNext())
					return;
				sb.Append(ies.Current);
				while (ies.MoveNext())
				{
					String part = ies.Current;
					int ixsp = part.IndexOf(' ');
					if (ixsp == -1)
						throw new Exception();
					part = part.Substring(ixsp + 1);
					sb.Append(part);
				}
				tw.WriteLine(sb.ToString());
				return;
			}

			Action a = () =>
			{
				z = z.Replace("↻", "E");
				lock (tw)
				{
					IEnumerator<String> ies = z.Split(new Char[] { '$' }).AsEnumerable<String>().GetEnumerator();
					if (!ies.MoveNext())
						return;
					Console.Write(ies.Current);
					while (ies.MoveNext())
					{
						String part = ies.Current;
						int ixsp = part.IndexOf(' ');
						if (ixsp == -1)
							throw new Exception();
						String s_color = part.Substring(0, ixsp).ToLower();
						part = part.Substring(ixsp + 1);
						if (s_color == "")
						{
							Console.ResetColor();
							part = " " + part;
						}
						else if (s_color == "reset")
							Console.ResetColor();
						else
						{
							ConsoleColor cc;
							if (Enum.TryParse<ConsoleColor>(s_color, true, out cc))
								Console.ForegroundColor = cc;
						}
						Console.Write(part);
					}
					Console.ResetColor();
					Console.WriteLine();
				}
			};

			Task wlc = Task.Factory.StartNew(a, ct);
		}
	};
}