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

using glue;
using glue.Tasks;
using glue.Debugging;

#pragma warning disable 0649

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 : ChartBase
	{
		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);
			Nop.X(fsp1, fsp2);
		}

		FalseSharing.Padding60 fsp1;
		int c_tasks = 0;
		FalseSharing.Padding60 fsp2;

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

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

		[Flags]
		public enum Status : int
		{
			_StatusMask = 0x000F,
			Run			= 0x0001,
			Pause		= 0x0002,
			Complete	= 0x0003,

			_DispositionMask	= 0x00F0,
			Ok					= 0x0000,
			Cancelled			= 0x0020,
			Faulted				= 0x0040,

			Disposing	= 0x0100,
			Disposed	= 0x0300,
		}

	//	ManualResetEvent run = new ManualResetEvent(true);

		public Status m_status = Status.Run;

		public void Pause()
		{
			if (m_status == Status.Run)
			{
				timer.Stop();
				//run.Reset();
				new_task_priority = ThreadPriority.BelowNormal;
				m_status = Status.Pause;
			}
		}

		public void Resume()
		{
			if (m_status == Status.Pause)
			{
				m_status = Status.Run;
				//run.Set();
				new_task_priority = ThreadPriority.AboveNormal;
				timer.Start();
			}
		}

		public void SetComplete()
		{
			if ((m_status & Status._StatusMask) != Status.Complete)
			{
				timer.Stop();
				m_status |= TaskCancellationChart.Status.Complete;
				//run.Set();
			}
		}

		ThreadPriority new_task_priority = ThreadPriority.AboveNormal;

		static public int c_tasks_max = int.MaxValue;

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

		internal Task StartAttachedChildTask(Action a)
		{
			//if (m_status == Status.Pause)
			//    run.WaitOne();

			if (c_tasks_max == int.MaxValue)
				return tf.StartNew(() =>
					{
						using (var q = new ThreadPriorityRegion(new_task_priority))
						{
							a();
						}
					});

			if (c_tasks > c_tasks_max)
			{
				try { a(); }
				catch (Exception) { throw; }
				return Tasks.CompletedTask;
			}
			Interlocked.Increment(ref c_tasks);
			return tf.StartNew(() =>
				{
					using (var q = new ThreadPriorityRegion(new_task_priority))
					{
						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 (m_status == Status.Pause)
			//    run.WaitOne();

			if (c_tasks_max == int.MaxValue)
				return tf.StartNew(() =>
					{
						using (var q = new ThreadPriorityRegion(new_task_priority))
						{
							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(() =>
				{
					using (var q = new ThreadPriorityRegion(new_task_priority))
					{
						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; } }
	};
}