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

using miew.Concurrency;
using miew.Debugging;
using miew.Tokenization;
using miew.Enumerable;

#pragma warning disable 0649

namespace agree
{
	public sealed partial class ParseControl : ISysObj, IDisposable
	{
		public class Stats
		{
			public enum Visibility { Public = 0, Private };

			ParseControl ctrl;
			public Stats(ParseControl ctrl)
			{
				this.ctrl = ctrl;
				this.Morphology = new _morphology(this);
				this.Parsing = new _parsing(this);
				this.Totals = new _totals(this);
			}

			public void Disconnect()
			{
				/// don't hold on to the chart or parse control structure just on account of someone retaining these stats
				ctrl.chart = null;
				ctrl = null;
			}

			public _morphology Morphology;
			public _parsing Parsing;
			public _totals Totals;
			public _system_info SystemInfo;

			public struct _unification
			{
				Visibility vis;
				public _unification(Visibility vis)
				{
					this.vis = vis;
					this.c_attempted = 0;
					this.c_succeeded = 0;
				}

				public int c_attempted;
				public int c_succeeded;

				public void AddAttempts(int c)
				{
					if (vis == Visibility.Public)
						Interlocked.Add(ref c_attempted, c);
					else
						c_attempted += c;
				}
				public void AddSuccesses(int c)
				{
					if (vis == Visibility.Public)
						Interlocked.Add(ref c_succeeded, c);
					else
						c_succeeded += c;
				}

				public double SuccessRatio { get { return c_succeeded / (double)c_attempted; } }

				public void Add(_unification other)
				{
					if (vis == Visibility.Public)
					{
						Interlocked.Add(ref c_attempted, other.c_attempted);
						Interlocked.Add(ref c_succeeded, other.c_succeeded);
					}
					else
					{
						c_attempted += other.c_attempted;
						c_succeeded += other.c_succeeded;
					}
				}

				public void RecordEvent(Object o)
				{
					if (vis == Visibility.Public)
					{
						Interlocked.Increment(ref c_attempted);
						if (o != null)
							Interlocked.Increment(ref c_succeeded);
					}
					else
					{
						c_attempted++;
						if (o != null)
							c_succeeded++;
					}
				}

				public void RecordEvent(bool b)
				{
					if (vis == Visibility.Public)
					{
						Interlocked.Increment(ref c_attempted);
						if (b)
							Interlocked.Increment(ref c_succeeded);
					}
					else
					{
						c_attempted++;
						if (b)
							c_succeeded++;
					}
				}
			};

			public struct _morphology
			{
				Stats s;
				public _morphology(Stats s)
					: this()
				{
					this.s = s;
				}
				public _unification Unification;

				public int c_lexical_transforms;
				public int c_analysis_stacks;
				public long ms_time;

				public double TimeRatio { get { return (double)ms_time / s.Totals.ms_time; } }

				public void SetComplete() { ms_time = s.ctrl.timer.ElapsedMilliseconds; }
			};

			public struct _parsing
			{
				Stats s;
				public _parsing(Stats s)
				{
					this.s = s;
					this.Chart = new _chart(s);
					this.Unification = default(_unification);
					this.Packing = default(_packing);
					this.Unpacking = new _unpacking(s);
					this.QuickCheck = default(_quick_check);
				}
				public _chart Chart;
				public _unification Unification;
				public _packing Packing;
				public _unpacking Unpacking;
				public _quick_check QuickCheck;

				public struct _chart
				{
					Stats s;
					long _ms_time;
					public _chart(Stats s)
						: this()
					{
						this.s = s;
					}
					public int c_passive_edges;
					public int c_active_edges;
					public int c_root_edges;
					public long ms_time { get { return _ms_time - s.Morphology.ms_time; } }
					public double TimeRatio { get { return (double)ms_time / s.Totals.ms_time; } }

					public void PassiveEdge() { Interlocked.Increment(ref c_passive_edges); }
					public void ActiveEdge() { Interlocked.Increment(ref c_active_edges); }
					public void RootEdge() { Interlocked.Increment(ref c_root_edges); }
					public void SetElapsed(long ms) { _ms_time = ms; }
				};

				public struct _packing
				{
					public int c_tests;
					public int c_proactive;
					public int c_retroactive;
					public int c_equivalence;

					public void RecordEvent(sbyte sb)
					{
						Interlocked.Increment(ref c_tests);
						if (sb == Subsumption.Equivalent)
							Interlocked.Increment(ref c_equivalence);
						else if (sb == Subsumption.FirstSubsumesSecond)
							Interlocked.Increment(ref c_proactive);
						else if (sb == Subsumption.SecondSubsumesFirst)
							Interlocked.Increment(ref c_retroactive);
					}
				};

				public struct _unpacking
				{
					Stats s;
					public _unpacking(Stats s)
						: this()
					{
						this.s = s;
					}
					public int c_restricted_parses;
					public int c_rejected_derivations;
					public int c_derivations;
					public long ms_time { get { return s.Totals.ms_time - s.Parsing.Chart.ms_time - s.Morphology.ms_time; } }
					public double TimeRatio { get { return (double)ms_time / s.Totals.ms_time; } }

					public _unification Unification;
				};

				public struct _quick_check
				{
					public int c_evaluated;
					public int c_avoided;

					public double PercentAvoided { get { return c_evaluated == 0 ? double.NaN : c_avoided / (double)c_evaluated; } }
				};
			};

			public struct _system_info
			{
				Stats s;
				public _system_info(Stats s)
				{
					this.s = s;
				}

				public int ProcessorCount
				{
					get { return Environment.ProcessorCount; }
				}

				public bool Is64Bit
				{
					get { return Environment.Is64BitProcess; }
				}
			};

			public struct _totals
			{
				Stats s;
				public _totals(Stats s)
				{
					this.s = s;
					this.ms_time = 0;
					this.Unification = new _unification(s);
				}

				public _unification Unification;

				public long ms_time;

				public double sec_time { get { return ms_time / 1000.0; } }

				public struct _unification
				{
					Stats s;
					public _unification(Stats s)
					{
						this.s = s;
						//this.QuickCheck = new _quick_check(s);
					}

					//				public _quick_check QuickCheck;

					public int c_attempted
					{
						get
						{
							return s.Morphology.Unification.c_attempted +
									s.Parsing.Unification.c_attempted +
									s.Parsing.Unpacking.Unification.c_attempted;
						}
					}
					public int c_succeeded
					{
						get
						{
							return s.Morphology.Unification.c_succeeded +
									s.Parsing.Unification.c_succeeded +
									s.Parsing.Unpacking.Unification.c_succeeded;
						}
					}

					//public struct _quick_check
					//{
					//    Stats s;
					//    public _quick_check(Stats s)
					//    {
					//        this.s = s;
					//    }
					//    public int c_evaluated
					//    {
					//        get
					//        {
					//            return s.Morphology.Unification.QuickCheck.c_evaluated +
					//                    s.Parsing.Unification.QuickCheck.c_evaluated;
					//        }
					//    }
					//    public int c_avoided
					//    {
					//        get
					//        {
					//            return s.Morphology.Unification.QuickCheck.c_avoided +
					//                    s.Parsing.Unification.QuickCheck.c_avoided;
					//        }
					//    }
					//};
				};
			}
		};
	};
}