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

using glue.Tasks;
using glue.Debugging;

namespace agree.Parse
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class ParseException : Exception
	{
		static int next_id = 0;

		public ParseException(String fmt, params Object[] args)
			: base(fmt == null ? String.Empty : String.Format(fmt, args))
		{
			id = Interlocked.Increment(ref next_id);
		}
		protected ParseException()
			: this(null)
		{
		}

		readonly int id;
		public int Id { get { return id; } }
	};

	public class ParseTimeoutException : ParseException
	{
		public ParseTimeoutException()
		{
		}
		public ParseTimeoutException(String fmt, params Object[] args)
			: base(String.Format(fmt, args))
		{
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	/// coordination of asynchronous chart tasks: creation and cancellation
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	abstract public class TaskCancellationChart<T> : ChartBase<T> where T : ChartBase<T>.IMotherDaughter, IEquatable<T>
	{
		internal TaskCancellationChart(ParserConfiguration config, ISysObj so_owner, String source_text, int c_cols)
			: base(config, so_owner, source_text, c_cols)
		{
			cancel_tok_src = new CancellationTokenSource();
			tf = new TaskFactory(
						cancel_tok_src.Token,
						TaskCreationOptions.AttachedToParent,
						TaskContinuationOptions.AttachedToParent,
						TaskScheduler.Default);
		}

		readonly protected Stopwatch timer = new Stopwatch();
		readonly CancellationTokenSource cancel_tok_src;
		readonly TaskFactory tf;

		public TimeSpan ParseTime { get { return timer.Elapsed; } }

		int c_tasks = 0;
		static public int c_tasks_max = int.MaxValue;

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

		internal Task StartAttachedChildTask(Action a)
		{
			if (c_tasks_max == int.MaxValue)
				return tf.StartNew(a);

			if (c_tasks > c_tasks_max)
			{
				try { a(); }
				catch (Exception) { throw; }
				return Tasks.CompletedTask;
			}
			Interlocked.Increment(ref c_tasks);
			return tf.StartNew(() =>
				{
					a();
					Interlocked.Decrement(ref c_tasks);
				});
		}

#if false
		internal Task<X> StartAttachedChildTask<X>(Func<X> f)
		{
			if (Nop.single_threaded)
			{
				X x = default(X);
				try { x = f(); }
				catch (Exception) { throw; }
				return Tasks.FromResult(x);
			}
			else
			{
				return tf.StartNew<X>(f);
			}
		}
#endif

		internal Task StartAttachedChildTask<X>(Action<X> ax, X x)
		{
			if (c_tasks_max == int.MaxValue)
				return tf.StartNew(() => ax(x));

			if (c_tasks > c_tasks_max)
			{
				try { ax(x); }
				catch (Exception) { throw; }
				return Tasks.CompletedTask;
			}
			Interlocked.Increment(ref c_tasks);
			return tf.StartNew(() =>
				{
					ax(x);
					Interlocked.Decrement(ref c_tasks);
				});
		}

		protected void CancelParse()
		{
			cancel_tok_src.Cancel(false);
		}

		protected CancellationToken CancelTok { get { return cancel_tok_src.Token; } }
		protected TaskFactory TaskFactory { get { return tf; } }
	};
}