////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Moves a job to the completed list. </summary>
		///
		/// <param name="completedJob">	The completed job. </param>
		private void JobCompleted(IExtractionJob completedJob)
		{
			// Remove the job from the queued job list
			lock (mJobList)
			{
				mJobList.Remove(completedJob);
			}

			// Move the job to the completed list
			List<IExtractionJob> removedJobs = new List<IExtractionJob>();
			lock (mCompletedJobList)
			{
				mCompletedJobList.Add(completedJob);

				// Delete jobs if there are too many in the completed list
				while (mCompletedJobList.Count > kMaxCompletedJobs)
				{
					removedJobs.Add(mCompletedJobList[0]);
					mCompletedJobList.RemoveAt(0);
				}
			}

			foreach (var job in removedJobs)
			{
				job.PropertyChanged -= JobPropertyChanged;
				OnJobRemoved(job.JobID);
			}
		}
		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>   Adds an extraction job to the manager. </summary>
		///
		/// <param name="job">  The job to add. </param>
		public void Add(IExtractionJob job)
		{
			// Check the job has not been run recently and is not queued before adding it
			lock (mCompletedJobList)
			{
				if (mCompletedJobList.Exists((extractionJob) => extractionJob.JobID == job.JobID))
				{
					mMessageHandler.SendMessage("A completed job already exists for {0}, clear the completed jobs before re-extracting", job.JobName);
					return;
				}
			}

			lock (mJobList)
			{
				if (mJobList.Exists((extractionJob) => extractionJob.JobID == job.JobID))
				{
					mMessageHandler.SendMessage("A job already exists for {0}", job.JobName);
					return;
				}

				job.PropertyChanged += JobPropertyChanged;

				mJobList.Add(job);
			}

			OnJobAdded(job.JobID, job.JobName, job.JobState);

			// Trigger the extraction thread so that it starts the job
			mRestartEvent.Set();
		}