using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using Csla;
using Csla.Data;

namespace VEPROMS.CSLA.Library
{
	public partial class ItemInfo
	{
		#region Old Insert
		//public ItemInfo InsertSiblingBeforeOld(string text)
		//{
		//  return InsertSiblingBefore(text, null);
		//}
		//public ItemInfo InsertSiblingBeforeOld(string text, string number)
		//{
		//  ItemInfo prevItemInfo = MyPrevious;
		//  ItemInfo newItemInfo = null;
		//  PartInfoList partInfoList = null;
		//  if (MyParent != null && MyParent.MyContent != null)
		//  {
		//    MyParent.MyContent.RefreshContentParts();
		//    partInfoList = MyParent.MyContent.ContentParts;
		//  }
		//  using (Item prevItem = prevItemInfo == null ? null : prevItemInfo.Get()) // Get the previous Item
		//  {
		//    using (Item newItem = Item.MakeItem(prevItem, Content.MakeContent(number, text, MyContent.Type, null, null))) // Create the new Item
		//    {
		//      using (Item thisItem = Get()) // Get the next item in the list
		//      {
		//        thisItem.MyPrevious = newItem; // Point to the new item
		//        thisItem.Save(); // Save Changes
		//        if (prevItem == null)
		//        {
		//          PartInfo partInfo = partInfoList.Find(this);
		//          using (Part part = partInfo.Get())
		//          {
		//            part.MyItem = newItem;
		//            part.Save();
		//          }
		//        }
		//      }
		//      // ToDo:  Need change PartInfo in PartInfoList 
		//      newItemInfo = ItemInfo.Get(newItem.ItemID);
		//      newItemInfo.ResetOrdinal();
		//    }
		//  }
		//  return newItemInfo;
		//}
		//public ItemInfo InsertSiblingAfterOld(string text)
		//{
		//  return InsertSiblingAfter(text, null);
		//}
		//public ItemInfo InsertSiblingAfterOld(string text, string number)
		//{
		//  return InsertSiblingAfter(text, number, MyContent.Type);
		//}
		//public ItemInfo InsertSiblingAfterOld(string text, string number, int? type)
		//{
		//  ItemInfo nextItemInfo = NextItem;
		//  ItemInfo newItemInfo = null;
		//  using (Item thisItem = Get()) // Get the Current Item
		//  {
		//    using (Item newItem = Item.MakeItem(thisItem, Content.MakeContent(number, text, type, null, null))) // Create the new Item
		//    {
		//      if (nextItemInfo != null) // Simple case, adding to end of list:
		//        using (Item nextItem = nextItemInfo.Get()) // Get the next item in the list
		//        {
		//          nextItem.MyPrevious = newItem; // Point to the new item
		//          nextItem.Save(); // Save Changes
		//        }
		//      // ToDo:  Need change PartInfo in PartInfoList 
		//      newItemInfo = ItemInfo.Get(newItem.ItemID);
		//      newItemInfo.ResetOrdinal();
		//    }
		//  }
		//  return newItemInfo;
		//}
		//public ItemInfo InsertChildOld(E_FromType fromType, int type, string text)
		//{
		//  return InsertChild(fromType, type, text, null);
		//}
		//public ItemInfo InsertChildOld(E_FromType fromType, int type, string text, string number)
		//{
		//  ItemInfo newItemInfo = null;
		//  using (Item thisItem = Get()) // Get the Current Item
		//  {
		//    using (Item newItem = Item.MakeItem(null, Content.MakeContent(number, text, type, null, null))) // Create the new Item
		//    {
		//      PartInfo partInfo = MyContent.ContentParts == null ? null : MyContent.ContentParts.Find(fromType);
		//      if (partInfo != null)
		//      {
		//        //this could be equivalent to adding a sibling with a specific type
		//        using (Part part = partInfo.Get())
		//        {
		//          part.MyItem.MyPrevious = newItem;
		//          part.MyItem.Save();
		//          part.MyItem = newItem;
		//          part.Save();
		//        }
		//      }
		//      else
		//      {
		//        // This means that a part needs to be added to point to the new item
		//        //using (Part part = Part.MakePart(thisItem.MyContent, ))
		//        //{ ;}
		//        thisItem.MyContent.ContentParts.Add((int)fromType, newItem);
		//        thisItem.Save();
		//      }
		//      newItemInfo = ItemInfo.Get(newItem.ItemID);
		//    }
		//  }
		//  ResetParts();
		//  return newItemInfo;
		//}
		#endregion
		#region Insert Before
		public ItemInfo InsertSiblingBefore(string text)
		{
			return InsertSiblingBefore(text, null);
		}
		public ItemInfo InsertSiblingBefore(string text, string number)
		{
			ItemInfo tmp = NewItemInfoFetch(ItemID, EAddpingPart.Before, number, text, null, null, null, null, DateTime.Now, Environment.UserName);
			// this item is updated in SQL so we have to manually force the iteminfo updates
			// Refresh ItemInfo to update Previous
			using (Item item = Get()) ItemInfo.Refresh(item);
			// Update all of the content records that have transitions that point to the Siblings or Sibling Children of the new item 
			tmp.UpdateTransitionText();
			return tmp;
		}
		#endregion
		#region Insert After
		public ItemInfo InsertSiblingAfter(string text)
		{
			return InsertSiblingAfter(text, null);
		}
		public ItemInfo InsertSiblingAfter(string text, string number)
		{
			return InsertSiblingAfter(text, number, MyContent.Type);
		}
		public ItemInfo InsertSiblingAfter(string text, string number, int? type)
		{
			ItemInfo tmp = NewItemInfoFetch(ItemID, EAddpingPart.After, number, text, type, null, null, null, DateTime.Now, Environment.UserName);
			//tmp = DataPortal.Fetch<StepInfo>(new AddingPartCriteria(ItemID, EAddpingPart.After, number, text, type, null, null, null, DateTime.Now, Environment.UserName));
			// if next exists, it is updated in SQL so we have to manually force the iteminfo updates
			// Refresh ItemInfo to update PreviousID field
			if (tmp.NextItem != null) using (Item item = tmp.NextItem.Get()) ItemInfo.Refresh(item);
			// Update all of the content records that have transitions that point to the Siblings or Sibling Children of the new item 
			tmp.UpdateTransitionText();
			return tmp;
		}
		private ItemInfo NewItemInfoFetch(int itemID, EAddpingPart addType, string number, string text, int? type, int? fromType, int? formatID, string config, DateTime dts, string userID)
		{
			ItemInfo tmp;
			if (addType == EAddpingPart.Child)
			{
				// adding children.  Type is based on 'fromType'
				switch ((E_FromType)fromType)
				{
					case E_FromType.Procedure:
						tmp = DataPortal.Fetch<ProcedureInfo>(new AddingPartCriteria(itemID, addType, number, text, type, fromType, formatID, config, dts, userID));
						break;
					case E_FromType.Section:
						tmp = DataPortal.Fetch<SectionInfo>(new AddingPartCriteria(itemID, addType, number, text, type, fromType, formatID, config, dts, userID));
						break;
					default:
						tmp = DataPortal.Fetch<StepInfo>(new AddingPartCriteria(itemID, addType, number, text, type, fromType, formatID, config, dts, userID));
						break;
				}
			}
			else
			{
				if (GetType() == typeof(ProcedureInfo))
					tmp = DataPortal.Fetch<ProcedureInfo>(new AddingPartCriteria(itemID, addType, number, text, type, fromType, formatID, config, dts, userID));
				else if (GetType() == typeof(SectionInfo))
					tmp = DataPortal.Fetch<SectionInfo>(new AddingPartCriteria(itemID, addType, number, text, type, fromType, formatID, config, dts, userID));
				else
					tmp = DataPortal.Fetch<StepInfo>(new AddingPartCriteria(itemID, addType, number, text, type, fromType, formatID, config, dts, userID));
			}
			return tmp;
		}
		public void UpdateTransitionText()
		{
			// Update Ordinals from here down
			ResetOrdinal();
			// This returns a list of all of the transitions that may have been affected
			using(TransitionInfoList trans = TransitionInfoList.GetAffected(this.ItemID))
			{
				foreach (TransitionInfo tran in trans)
				{
					using (Content content = tran.MyContent.Get())
					{
						content.FixTransitionText(tran);
						if (content.IsDirty)
							content.Save();
					}
				}
			}
		}
		#endregion
		#region Insert Child
		public ItemInfo InsertChild(E_FromType fromType, int type, string text)
		{
			return InsertChild(fromType, type, text, null);
		}
		public ItemInfo InsertChild(E_FromType fromType, int type, string text, string number)
		{
			ItemInfo tmp = NewItemInfoFetch(ItemID, EAddpingPart.Child, number, text, type, (int?) fromType, null, null, DateTime.Now, Environment.UserName);
			// if next exists, it is updated in SQL so we have to manually force the iteminfo updates
			// Refresh ItemInfo to update PreviousID field
			if (tmp.NextItem != null) using (Item item = tmp.NextItem.Get()) ItemInfo.Refresh(item);
			// Update all of the content records that have transitions that point to the Siblings or Sibling Children of the new item 
			tmp.UpdateTransitionText();
			return tmp;
		}
		#endregion
		#region DataPortal
		private void DataPortal_Fetch(AddingPartCriteria criteria)
		{
			if (_MyLog.IsDebugEnabled) _MyLog.DebugFormat("[{0}] ItemInfo.DataPortal_Fetch", GetHashCode());
			try
			{
				using (SqlConnection cn = Database.VEPROMS_SqlConnection)
				{
					ApplicationContext.LocalContext["cn"] = cn;
					using (SqlCommand cm = cn.CreateCommand())
					{
						cm.CommandType = CommandType.StoredProcedure;
						cm.Parameters.AddWithValue("@ItemID", criteria.ItemID);			//ABC After Before Child
						cm.Parameters.AddWithValue("@Number", criteria.Number);			//ABC
						cm.Parameters.AddWithValue("@Text", criteria.Text);					//ABC
						cm.Parameters.AddWithValue("@FormatID", criteria.FormatID);	//ABC
						cm.Parameters.AddWithValue("@Config", criteria.Config);			//ABC
						cm.Parameters.AddWithValue("@Type", criteria.Type);					//ABC
						cm.Parameters.AddWithValue("@DTS", criteria.DTS);						//ABC
						cm.Parameters.AddWithValue("@UserID", criteria.UserID);			//ABC
						SqlParameter param_ContentID = new SqlParameter("@newItemID", SqlDbType.Int);
						param_ContentID.Direction = ParameterDirection.Output;
						cm.Parameters.Add(param_ContentID);
						switch (criteria.AddType)
						{
							case EAddpingPart.Child:
								cm.CommandText = "addItemChild";
								cm.Parameters.AddWithValue("@FromType", criteria.FromType);	//--C
								break;
							case EAddpingPart.Before:
								cm.CommandText = "addItemSiblingBefore";
								break;
							case EAddpingPart.After:
								cm.CommandText = "addItemSiblingAfter";
								break;
						}
						using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader()))
						{
							//newItemID = (int)cm.Parameters["@newContentID"].Value;
							if (!dr.Read())
							{
								_ErrorMessage = "No Record Found";
								return;
							}
							ReadData(dr);
						}
					}
					// removing of item only needed for local data portal
					if (ApplicationContext.ExecutionLocation == ApplicationContext.ExecutionLocations.Client)
						ApplicationContext.LocalContext.Remove("cn");
				}
			}
			catch (Exception ex)
			{
				if (_MyLog.IsErrorEnabled) _MyLog.Error("ItemInfo.DataPortal_Fetch", ex);
				_ErrorMessage = ex.Message;
				throw new DbCslaException("ItemInfo.DataPortal_Fetch", ex);
			}
		}
		#endregion
		[Serializable()]
		protected class AddingPartCriteria
		{
			#region Properties
			private int _ItemID;
			public int ItemID
			{
				get { return _ItemID; }
				set { _ItemID = value; }
			}
			private EAddpingPart _AddType;
			public EAddpingPart AddType
			{
				get { return _AddType; }
				set { _AddType = value; }
			}
			private string _Number=null;
			public string Number
			{
				get { return _Number; }
				set { _Number = value; }
			}
			private string _Text=null;
			public string Text
			{
				get { return _Text; }
				set { _Text = value; }
			}
			private int? _FromType = null;
			public int? FromType
			{
				get { return _FromType; }
				set { _FromType = value; }
			}
			private int? _Type=null;
			public int? Type
			{
				get { return _Type; }
				set { _Type = value; }
			}
			private int? _FormatID=null;
			public int? FormatID
			{
				get { return _FormatID; }
				set { _FormatID = value; }
			}
			private string _Config=null;
			public string Config
			{
				get { return _Config; }
				set { _Config = value; }
			}
			private DateTime _DTS;
			public DateTime DTS
			{
				get { return _DTS; }
				set { _DTS = value; }
			}
			private string _UserID;
			public string UserID
			{
				get { return _UserID; }
				set { _UserID = value; }
			}
			#endregion
			#region Constructor
			public AddingPartCriteria(int itemID, EAddpingPart addType, string number, string text, int? type, int? fromType, int? formatID, string config, DateTime dts, string userID)
			{
				_ItemID = itemID;
				_AddType = addType;
				_Number = number;
				_Text = text;
				_Type = type;
				_FromType = fromType;
				_FormatID = formatID;
				_Config = config;
				_DTS = dts;
				_UserID = userID;
			}
			#endregion
		}
		public enum EAddpingPart
		{
			Child=0,
			Before=1,
			After=2
		}
		public ItemInfo NextItem
		{
			get
			{
				if (NextItemCount > 0 && NextItems.Count > 0)
					return NextItems[0];
				return null;
			}
		}
		private static void ResetOrdinal(int itemID)
		{
			ConvertListToDictionary();
			string key = itemID.ToString();
			while (key != null && _CacheByPrimaryKey.ContainsKey(key))
			{
				ItemInfo[] items = _CacheByPrimaryKey[key].ToArray();
				key = null;
				foreach (ItemInfo item in items)
				{
					//Console.WriteLine("item = {0}, ordinal = {1}",item,item.Ordinal);
					item._Ordinal = null;
					item._TagsSetup = false;
					if (key == null && item.NextItem != null)
						key = item.NextItem.ItemID.ToString();
				}
			}
		}
		private void ResetOrdinal()
		{
			ResetOrdinal(ItemID);
		}
	}
}
