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

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public unsafe partial class TypeMgr
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		///
		/// Regression test
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public void RegressionTest(TextWriter tw, String file, bool f_marks)
		{
			if (!g.f_expanded_all)
				throw new Exception();

			String f_gold = String.Format("regression-trees-{0}{1}.txt", f_marks ? "-marks-" : "", file);
			String f_this = String.Format("regression-trees-latest-{0}{1}.txt", f_marks ? "-marks-" : "", file);

			long h = 0;
			if (Debugger.IsAttached)
			{
				foreach (Type t in AllTypes)
				{
					Interlocked.Add(ref h, t.Definition.TfsHash());
					if (t.IsExpanded && t.Expanded != t.Definition)
						Interlocked.Add(ref h, t.Expanded.TfsHash());
				}
			}
			else
			{
				Parallel.ForEach(AllTypes, t =>
					{
						Interlocked.Add(ref h, t.Definition.TfsHash());
						if (t.IsExpanded && t.Expanded != t.Definition)
							Interlocked.Add(ref h, t.Expanded.TfsHash());
					});
			}

			if (File.Exists(f_gold))
			{
				long hh;
				using (StreamReader gf = new StreamReader(f_gold))
					hh = (long)ulong.Parse(gf.ReadLine(), System.Globalization.NumberStyles.HexNumber);
				if (h == hh)
				{
					tw.WriteLine("Regression test succeeded. (based on hash: {0:X16})", h);
					return;
				}
				else
				{
					tw.WriteLine("Regression hash failed (hash current={0:X16}, expected={1:X16}). Generating full comparison...", h, hh);
				}
			}

			StringBuilder sb = new StringBuilder();
			sb.AppendLine(h.ToString("X16"));
			foreach (agree.Type t in AllTypes)
			{
				sb.Append(t.Definition.ToPathList("definition: " + t.Name, f_marks));
			}
			foreach (agree.Type t in AllTypes)
			{
				if (t.IsExpanded && t.Expanded != t.Definition)
					sb.Append(t.Expanded.ToPathList("expanded: " + t.Name, f_marks));
			}

			if (!File.Exists(f_gold))
			{
				File.WriteAllText(f_gold, sb.ToString());
				tw.WriteLine("Wrote new regression trees (hash {0:X16})", h);
			}
			else
			{
				File.WriteAllText(f_this, sb.ToString());
				tw.WriteLine("done.");
				throw new RegressionTestFailedException("Regression test failed");
			}
		}

		public class RegressionTestFailedException : Exception
		{
			public RegressionTestFailedException(String msg)
				: base(msg)
			{
			}
		};
	};

	public partial class Grammar : ISysObj
	{
		public String GarbageReport(HashSet<TfsFeatMark> hspm = null)
		{
			using (StringWriter sw = new StringWriter())
			{
				sw.WriteLine("TfsFeatMark Garbage Report:");
				int c = 0;
				foreach (Instance t in tm.AllInstances)
				{
					if (t.Definition != null)
					{
						c += t.Definition.GarbageReport(sw);
						if (t.IsExpanded && t.Expanded != t.Definition)
							c += t.Expanded.GarbageReport(sw);
					}
				}
				sw.WriteLine("{0}", c);
				return sw.ToString();
			}
		}
	};
}