//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Threading;
using System.Xml;
using CommunityServer.Configuration;

namespace CommunityServer.Components
{
	/// <summary>
	/// Summary description for Jobs.
	/// </summary>
	public class Jobs
	{
		//Holds single instance of Jobs
		private static readonly Jobs _jobs = null;

		//Internal job container
		private Hashtable jobList = new Hashtable();
		private int Interval = 15 * 60000;
		private Timer singleTimer = null;
		private DateTime _created;
		private DateTime _started;
		private DateTime _completed;
		private bool _isRunning;

		//Create single instance of Jobs 
		static Jobs()
		{
			_jobs = new Jobs();
		}

		/// <summary>
		/// Returns a reference to the current instance of Jobs
		/// </summary>
		/// <returns></returns>
		public static Jobs Instance()
		{
			return _jobs;
		}

		/// <summary>
		/// Do not allow direct creation
		/// </summary>
		private Jobs()
		{
			_created = DateTime.Now;
		}

		public Hashtable CurrentJobs
		{
			get { return jobList; }
		}

		public override string ToString()
		{
			return string.Format("Created: {0}, LastStart: {1}, LastStop: {2}, IsRunning: {3}, Minutes: {4}", _created, _started, _completed, _isRunning, Interval / 60000);
		}

		public System.Collections.Specialized.ListDictionary CurrentStats
		{
			get
			{
				System.Collections.Specialized.ListDictionary stats = new System.Collections.Specialized.ListDictionary();
				stats.Add("Created", _created);
				stats.Add("LastStart", _started);
				stats.Add("LastStop", _completed);
				stats.Add("IsRunning", _isRunning);
				stats.Add("Minutes", Interval / 60000);
				return stats;
			}
		}

		/// <summary>
		/// Finds and Starts all jobs. Any existing jobs are shutdown first
		/// </summary>
		public void Start()
		{
			if (jobList.Count != 0)
				return;

			CSConfiguration csConfig = CSConfiguration.GetConfig();
			if (!csConfig.IsBackgroundThreadingDisabled)
			{
				XmlNode node = csConfig.GetConfigSection("CommunityServer/Jobs");

				bool isSingleThread = true;
				XmlAttribute singleThreadAttribute = node.Attributes["singleThread"];

				//figure out global thread status
				if (singleThreadAttribute != null && !Globals.IsNullorEmpty(singleThreadAttribute.Value) && string.Compare(singleThreadAttribute.Value, "false", true) == 0)
					isSingleThread = false;
				else
				{
					isSingleThread = true;

					XmlAttribute minutes = node.Attributes["minutes"];
					if (minutes != null && !Globals.IsNullorEmpty(minutes.Value))
					{
						try
						{
							Interval = Int32.Parse(minutes.Value) * 60000;
						}
						catch
						{
							Interval = 15 * 60000;
						}
					}
				}

				//Create Jobs
				foreach (XmlNode jnode in node.ChildNodes)
				{
					if (jnode.NodeType != XmlNodeType.Comment)
					{
						XmlAttribute typeAttribute = jnode.Attributes["type"];
						XmlAttribute nameAttribute = jnode.Attributes["name"];

						Type type = Type.GetType(typeAttribute.Value);
						if (type != null)
						{
							if (!jobList.Contains(nameAttribute.Value))
							{
								Job j = new Job(type, jnode);
								jobList[nameAttribute.Value] = j;

								if (!isSingleThread || !j.SingleThreaded)
									j.InitializeTimer();
							}
						}
					}
				}

				if (isSingleThread)
				{
					//Create a new timer to iterate over each job
					singleTimer = new Timer(new TimerCallback(call_back), null, Interval, Interval);
				}
			}
		}

		/// <summary>
		/// Callback used to iterate over jobs when they are not excuted on their own Timer
		/// </summary>
		/// <param name="state"></param>
		private void call_back(object state)
		{
			_isRunning = true;
			_started = DateTime.Now;
			singleTimer.Change(Timeout.Infinite, Timeout.Infinite);

			foreach (Job job in jobList.Values)
				if (job.Enabled && job.SingleThreaded)
					job.ExecuteJob();

			singleTimer.Change(Interval, Interval);
			_isRunning = false;
			_completed = DateTime.Now;
		}

		/// <summary>
		/// Calls displose on all current jobs and clears the job list
		/// </summary>
		public void Stop()
		{
			if (jobList != null)
			{
				foreach (Job job in jobList.Values)
					job.Dispose();

				jobList.Clear();

				if (singleTimer != null)
				{
					singleTimer.Dispose();
					singleTimer = null;
				}
			}
		}

		/// <summary>
		/// Checks to see whether the specified job is currently enabled or disabled.
		/// </summary>
		/// <param name="jobName">The name of the job</param>
		/// <returns>bool</returns>
		public bool IsJobEnabled(string jobName)
		{
			if (!jobList.Contains(jobName))
				return false;
			return ((Job)jobList[jobName]).Enabled;
		}
	}
}