//==============================================================
//  版权所有：深圳杰文科技
//  文件名：WorkQueue.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

using System;
using System.Collections;
using System.Threading;

namespace Infrastructure.TaskQueue
{
	public delegate void TaskExecutedHandler(Guid taskId);

	public delegate void TaskExecuteErrorHandler(Guid taskId, object data, Exception exception);

	/// <summary>
	/// 任务的工作队列，负责任务的执行。
	/// </summary>
	internal class WorkQueue : IDisposable
	{
		private readonly Guid _WorkId = Guid.NewGuid();
		private string _WorkName = "";

		private Queue _Queue = Queue.Synchronized(new Queue()); //线程安全的任务队列。
		private Action<object> _Command; //任务的执行委托。
		private Thread _WorkThread = null; //任务执行线程。

		private bool _Exit = false; //退出线程的标记。

		private AutoResetEvent _WorkEvent = new AutoResetEvent(false);

		/// <summary>
		/// 任务的工作队列。
		/// </summary>
		/// <param name="command">执行任务的委托。</param>
		/// <param name="ignoreExceptionList">忽略执行任务时发生的指定异常。</param>
		public WorkQueue(Action<object> command, string workName)
		{
			_WorkName = workName;
			if (command == null)
			{
				throw new ArgumentNullException("command");
			}
			_Command = command;

			//构造任务的工作线程。
			_WorkThread = new Thread(delegate()
			{
				_Exit = false;
				Work();
			});
			_WorkThread.Start();
			//Console.WriteLine("Create Thead：{0}，{1}", _WorkName, _WorkId);
		}

		internal event TaskExecutedHandler TaskExecuted; //任务已执行事件。
		private void RaiseTaskExecuted(Task task)
		{
			if (task.Status == TaskStatus.Executed && TaskExecuted != null)
			{
				TaskExecuted(task.Id);
			}
		}

		internal event TaskExecuteErrorHandler TaskExecuteError; //任务执行时发生错误的事件。
		private void RaiseTaskExecuteError(Task task, Exception ex)
		{
			if (TaskExecuteError == null)
			{
				return;
			}

			try
			{
				TaskExecuteError(task.Id, task.Data, ex);
			}
			catch (Exception ex1) //如果外部处理异常时发生了错误，那么忽略，这么做了为了保证任务队列不被外部的错误打断。
			{
				//throw;
				Console.WriteLine(ex1);
			}
		}

		private void Work()
		{
			while (!_Exit)
			{
				Task task = Dequeue();
				if (task == null) //如果没有任务，那么工作队列暂停，一直等到有任务进来才启动。
				{
					_WorkEvent.WaitOne();
					continue;
				}

				ExecuteTask(task);
			}
		}

		private Task Dequeue()
		{
			Task task = null;
			if (_Queue.Count > 0)
			{
				task = (Task)_Queue.Dequeue();
			}
			return task;
		}

		private bool ExecuteTask(Task task)
		{
			if (task.Status == TaskStatus.Cancelled) //如果任务已经被取消，那么不执行此任务。
			{
				return true;
			}

			bool success = false;

			while (!success)
			{
				try
				{
					_Command(task.Data);
					success = true;
				}
				catch (Exception ex)
				{
					RaiseTaskExecuteError(task, ex);
					success = false;
					break; //如果发生了不可预料的异常，那么当前任务中止执行。
				}
			}

			task.Status = success ? TaskStatus.Executed : TaskStatus.Error;
			RaiseTaskExecuted(task);
			return success;
		}

		public void Enqueue(Task task)
		{
			_WorkEvent.Set();
			_Queue.Enqueue(task);
		}

		public void Dispose()
		{
			_Exit = true;
			_WorkEvent.Set();
			if (_WorkThread != null)
			{
				_WorkThread.Abort();
				_WorkThread = null;
				//Console.WriteLine("Dispose Thead：{0}，{1}", _WorkName, _WorkId);
			}
		}

	}
}
