using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Medivators.Common.Enums;
using Medivators.Common.Logging;

namespace Medivators.Parser
{

	#region abstract base

	public abstract class Cache : SortedList<string, ICacheItem>
	{
		internal SearchResult Search(ICacheItem Item)
		{
			SearchResult rtnVal = new SearchResult(-1, SearchResult.Results.New);
			string key = Item.Key;
			if (this.ContainsKey(key))
			{
				if (this[Item.Key].PendingOperationID > 0)
					rtnVal.Result = SearchResult.Results.DbOperationPending;
				else if (this[Item.Key].Equals(Item))
					rtnVal.Result = SearchResult.Results.Exists;
				else
					rtnVal.Result = SearchResult.Results.Changed;
				rtnVal.Index = this.IndexOfKey(Item.Key);
			}
			return rtnVal;
		}
		internal List<ICacheItem> GetByPendingOperationID(long OperationID)
		{
			lock (this)
			{
				List<ICacheItem> list = null;
				foreach (KeyValuePair<string, ICacheItem> item in this)
				{
					if (item.Value.PendingOperationID == OperationID)
					{
						if (list == null)
							list = new List<ICacheItem>();
						list.Add(item.Value);
					}
				}
				return list;
			}
		}
		internal void RemoveByPendingOperationID(long OperationID)
		{
			lock (this)
			{
				List<ICacheItem> remove = this.GetByPendingOperationID(OperationID);
				if ( remove == null )
					Log.GetInstance().WriteLog(
						LogEntryType.DebugTrace,
						"Parser.Cache.RemoveByPendingOperationID reports no cached items with operation ID " + OperationID.ToString(),
						System.Diagnostics.EventLogEntryType.Warning);
				else
					foreach (ICacheItem item in remove)
						this.Remove(item.Key);
			}
		}
		internal void ResetPendingOperationID(long OperationID, bool DBVerified)
		{
			lock (this)
			{
				List<ICacheItem> reset = this.GetByPendingOperationID(OperationID);
				if (reset != null)
					foreach (ICacheItem item in reset)
					{
						this[item.Key].PendingOperationID = 0;
						this[item.Key].DBVerified = DBVerified;
					}
				else
					Log.GetInstance().WriteLog(
						LogEntryType.DebugTrace,
						"ResetPendingOperationID reports no items match Operation ID " + OperationID.ToString(),
						System.Diagnostics.EventLogEntryType.Warning);
			}
		}
		internal void ResetPendingOperationID(long OperationID)
		{
			ResetPendingOperationID(OperationID, false);
		}
		internal void VerifiedByOperationID(long OperationID)
		{
			lock (this)
			{
				List<ICacheItem> reset = this.GetByPendingOperationID(OperationID);
				foreach (ICacheItem item in reset)
				{
					this[item.Key].PendingOperationID = 0;
					this[item.Key].DBVerified = true;
				}
			}
		}
		internal List<ICacheItem> GetHeadItems(int Quantity)
		{
			List<ICacheItem> rtn = new List<ICacheItem>();
			lock (this)
			{
				while (this.Count > 0 && rtn.Count < Quantity)
				{
					ICacheItem obj = this.Values[0];
					rtn.Add(this.Values[0]);
					this.RemoveAt(0);
				}
			}
			return rtn;
		}
		internal List<ICacheItem> GetUnverifiedItems(int Quantity)
		{
			List<ICacheItem> rtn = new List<ICacheItem>();
			lock (this)
			{
				int idx = 0;
				while ( idx < this.Values.Count )
				{
					ICacheItem item = this.Values[idx++];

					//	return only items that are not verified and do not
					//	have a pending db operation
					if (!item.DBVerified && item.PendingOperationID == 0)
						rtn.Add(item);
					if (rtn.Count >= Quantity)
						break;
				}
			}
			return rtn;
		}
	}

	#endregion

	#region custom Search method return class

	internal class SearchResult
	{
		private int _index = -1;
		private Results _result = Results.New;

		internal enum Results
		{
			New,
			Changed, 
			Exists, 
			DbOperationPending
		}

		internal SearchResult(int Index, Results Result)
		{
			_index = Index;
			_result = Result;
		}
		internal int Index
		{
			get { return _index; }
			set { _index = value; }

		}
		internal Results Result
		{
			get { return _result; }
			set { _result = value; }
		}

	}

	#endregion

	public class UncommittedLogRecordCache : Cache
	{
		#region singleton constructor & instance

		private static UncommittedLogRecordCache _instance = null;

		private UncommittedLogRecordCache ()
		{
		}

		public static UncommittedLogRecordCache GetInstance()
		{
			if ( _instance == null )
				_instance = new UncommittedLogRecordCache() ;
			return _instance;
		}

		#endregion
	}
	public class CommittedLogRecordCache : Cache
	{
		#region singleton constructor & instance

		private static CommittedLogRecordCache _instance = null;

		private CommittedLogRecordCache()
		{
		}

		public static CommittedLogRecordCache GetInstance()
		{
			if (_instance == null)
				_instance = new CommittedLogRecordCache();
			return _instance;
		}

		#endregion
	}
	public class UncommittedCycleReportCache : Cache
	{
		#region singleton constructor & instance

		private static UncommittedCycleReportCache _instance = null;

		private UncommittedCycleReportCache()
		{
		}

		public static UncommittedCycleReportCache GetInstance()
		{
			if (_instance == null)
				_instance = new UncommittedCycleReportCache();
			return _instance;
		}

		#endregion
	}
	public class CommittedCycleReportCache : Cache
	{
		#region singleton constructor & instance

		private static CommittedCycleReportCache _instance = null;

		private CommittedCycleReportCache()
		{
		}

		public static CommittedCycleReportCache GetInstance()
		{
			if (_instance == null)
				_instance = new CommittedCycleReportCache();
			return _instance;
		}

		#endregion
	}
}
