using System.Collections.Generic;
using System.Linq;

using BeWo.ServiceProxy;
using BeWo.ViewModel;

using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.ClientPartials;

namespace BeWo.Core.Service
{
    public class GoalService
    {
        public static List<SupportConceptGoalDC> GetGoalTree(IEnumerable<ValueListEntryDC> goalCategories, List<ValueListEntryDC> indGoalCategories, List<ValueListEntryDC> pAllGoals, bool removeEmptyGoalCategories)
        {
			List<ValueListEntryDC> allCategories = new List<ValueListEntryDC>();
	        if (goalCategories != null && pAllGoals != null && pAllGoals.Count > 0)
	        {
		        foreach (var goalCat in goalCategories)
		        {
			        if (!pAllGoals.Contains(goalCat))
			        {
						allCategories.Add(goalCat);        
			        }
		        }
		        
	        }

	        if (indGoalCategories != null && pAllGoals != null)
	        {
		        if (ContainsAnyGoal(indGoalCategories, pAllGoals))
		        {
					foreach (var igoalCat in indGoalCategories)
					{
						if (!pAllGoals.Contains(igoalCat))
						{
							allCategories.Add(igoalCat);
						}
					}
		        }
	        }



			var sortedCategories = allCategories.OrderBy(s => s.TypeDescription).ToList();
            var sortedGoals      = pAllGoals.OrderBy(s => s.TypeDescription).ToList();

            var allCatList      = new List<SupportConceptGoalDC>();
			var allGoalList = new List<SupportConceptGoalDC>();
			var rootGoalList = new List<SupportConceptGoalDC>();
            var goalCategoryDict = new Dictionary<long, SupportConceptGoalDC>();

			//foreach (var goal in sortedGoals)
			//{
			//	var childItem = new SupportConceptGoalDC { GoalEntryDC = goal };

			//	if (goal.ParentOid != null && goalCategoryDict.ContainsKey(goal.ParentOid.Value))
			//	{
			//		var parentItem = goalCategoryDict[goal.ParentOid.Value];
			//		childItem.ParentGoal = parentItem;

			//		parentItem.Children.Add(childItem);
			//	}
			//}

			
            foreach (var goalCat in sortedCategories)
            {
                var treeItem = new SupportConceptGoalDC {GoalEntryDC = goalCat, IsExpanded = true};
	            goalCategoryDict.Add(goalCat.ValueListEntryOid.Value, treeItem);
				allCatList.Add(treeItem);
            }

			foreach (var goalCat in allCatList)
			{
				if (goalCat.GoalEntryDC.ParentOid.HasValue &&
					goalCategoryDict.ContainsKey(goalCat.GoalEntryDC.ParentOid.Value))
				{
					var parent = goalCategoryDict[goalCat.GoalEntryDC.ParentOid.Value];
					goalCat.ParentGoal = parent;
					parent.Children.Add(goalCat);
				}
			}

			foreach (var goalCat in allCatList)
			{
				if (goalCat.ParentGoal == null)
				{
					rootGoalList.Add(goalCat);
				}
			}


            foreach (var goal in sortedGoals)
            {
				var childItem = new SupportConceptGoalDC { GoalEntryDC = goal, IsExpanded = true };
				if (!goalCategoryDict.ContainsKey(goal.ValueListEntryOid.Value))
					goalCategoryDict.Add(goal.ValueListEntryOid.Value, childItem);
				allGoalList.Add(childItem);
            }

			foreach (var goal in allGoalList)
			{
				if (goal.GoalEntryDC.ParentOid != null && goalCategoryDict.ContainsKey(goal.GoalEntryDC.ParentOid.Value))
				{
					var parentItem = goalCategoryDict[goal.GoalEntryDC.ParentOid.Value];
					goal.ParentGoal = parentItem;

					parentItem.Children.Add(goal);
				}
			}

            if (removeEmptyGoalCategories)
            {
				RemoveCategoriesWithoutSelectedGoals(rootGoalList, sortedGoals);
                
            }
			return rootGoalList;
        }

		private static void RemoveCategoriesWithoutSelectedGoals(ICollection<SupportConceptGoalDC> goalList, List<ValueListEntryDC> sortedGoals)
		{
			var cats2Remove = new List<SupportConceptGoalDC>();
			foreach (var cat in goalList)
			{
				RemoveCategoriesWithoutSelectedGoals(cat.Children, sortedGoals);
				
				if (!ContainsAnyGoal(cat, sortedGoals))
					cats2Remove.Add(cat);
			}

			foreach (var cat in cats2Remove)
			{
				goalList.Remove(cat);
			}
		}


		private static bool ContainsAnyGoal(SupportConceptGoalDC cat, IEnumerable<ValueListEntryDC> goals)
		{
			foreach (var goal in goals)
			{
				if (GoalIsPartOfCategory(cat, goal))
				{
					return true;
				}
			}
			return false;
		}

		private static bool GoalIsPartOfCategory(SupportConceptGoalDC cat, ValueListEntryDC goal)
		{
			if (cat.GoalEntryDC.ValueListEntryOid == goal.ValueListEntryOid)
			{
				return true;
			}

			if (goal.ParentOid.HasValue)
			{
				if (cat.GoalEntryDC.ValueListEntryOid.Value == goal.ParentOid.Value)
				{
					return true;
				}

				foreach (var child in cat.Children)
				{
					bool ispart = GoalIsPartOfCategory(child, goal);
					if (ispart)
					{
						return true;
					}
				}
			}
			
			return false;
		}

		private static bool ContainsAnyGoal(IEnumerable<ValueListEntryDC> indGoalCategories, IEnumerable<ValueListEntryDC> goals)
		{
			var dict = indGoalCategories.ToDictionary((g => g.ValueListEntryOid.Value));

			foreach (var goal in goals)
			{
				if (goal.ParentOid.HasValue && dict.ContainsKey(goal.ParentOid.Value))
				{
					return true;
				}
			}
			return false;
		}

	    public static IEnumerable<SupportConceptGoalDC> GetZieleMassnahmenTree(List<ValueListEntryVM> goalsAndCategories, bool removeEmptyGoalCategories)
	    {
            var sortedCategories = goalsAndCategories.Where(w => w.Type.Equals(ValueListEntryType.SupportConceptGoalCategoryType) || w.Type.Equals(ValueListEntryType.SupportConceptIndividualGoalCategoryType)).OrderBy(s => s.Description).ToList();
            var sortedGoals      = goalsAndCategories.Where(w => w.Type.Equals(ValueListEntryType.SupportConceptGoalType) || w.Type.Equals(ValueListEntryType.SupportConceptIndividualGoalType)).OrderBy(s => s.Description).ToList();
			var goalCategoryDict = new Dictionary<long, SupportConceptGoalDC>();
			var goalList         = new List<SupportConceptGoalDC>();

		    foreach (var goalCategory in sortedCategories)
		    {
				var treeItem = new SupportConceptGoalDC
				{
					GoalEntryDC = goalCategory.DataContract,
					IsExpanded = true
				};

                goalCategoryDict.Add(goalCategory.DataContract.ValueListEntryOid.Value, treeItem);

				goalList.Add(treeItem);
		    }

            foreach (var goalCategory in sortedCategories.Where(w => w.DataContract.ParentOid != null))
		    {
			    if (goalCategoryDict.ContainsKey(goalCategory.DataContract.ParentOid.Value))
			    {
				    goalCategoryDict[goalCategory.DataContract.ValueListEntryOid.Value].ParentGoal =
					    goalCategoryDict[goalCategory.DataContract.ParentOid.Value];
			    }
		    }

			var categoriesWithParents = goalCategoryDict.Values.Where(w => w.GoalEntryDC.ParentOid != null).ToList();
			foreach (var goalCategory in categoriesWithParents)
		    {
			    if (goalCategoryDict.ContainsKey(goalCategory.GoalEntryDC.ParentOid.Value))
			    {
				    goalCategoryDict[goalCategory.GoalEntryDC.ParentOid.Value].Children.Add(goalCategory);
			    }
		    }

			foreach (var goal in sortedGoals)
			{
                var childItem = new SupportConceptGoalDC { GoalEntryDC = goal.DataContract };

                if (goal.DataContract.ParentOid != null && goalCategoryDict.ContainsKey(goal.DataContract.ParentOid.Value))
				{
                    var parentItem = goalCategoryDict[goal.DataContract.ParentOid.Value];
					childItem.ParentGoal = parentItem;

					parentItem.Children.Add(childItem);
				}
			}

			if (removeEmptyGoalCategories)
			{
				var cats2Remove = goalList.Where(cat => cat.Children.Count == 0).ToList();

				foreach (var cat in cats2Remove)
				{
					goalList.Remove(cat);
				}
			}

		    return goalList;
	    }

        public static void RecursiveSynchronousValueListEntrySave(SupportConceptGoalTreeItem treeItem)
        {
            var neuerDC = ServiceFacade.DoValueListServiceSync(s => s.InsertNewValueListEntry(treeItem.GoalEntryVM.CommitToDataContract()));
            treeItem.GoalEntryVM = new ValueListEntryVM(neuerDC);
            treeItem.GoalEntryDC = neuerDC;

            foreach (var child in treeItem.Items)
            {
                child.ParentGoal = treeItem;
                child.GoalEntryVM.ParentEntry = neuerDC;
                child.GoalEntryDC.Parent = neuerDC;

                RecursiveSynchronousValueListEntrySave(child);
            }
        }

        private static List<ValueListEntryDC> InsertedGoals;
        public static IEnumerable<ValueListEntryDC> SaveIndividualGoalsAndMassnahmenRecursively(SupportConceptGoalTreeItem treeItem)
        {
            InsertedGoals = new List<ValueListEntryDC>();

            RecursiveSynchronousSCValueListEntrySave(treeItem);

            return InsertedGoals;
        }

        public static void RecursiveSynchronousSCValueListEntrySave(SupportConceptGoalTreeItem treeItem)
        {
            var neuerDC = ServiceFacade.DoValueListServiceSync(s => s.InsertNewValueListEntry(treeItem.GoalEntryVM.CommitToDataContract()));
            InsertedGoals.Add(neuerDC);
            treeItem.GoalEntryVM = new ValueListEntryVM(neuerDC);
            treeItem.GoalEntryDC = neuerDC;

            foreach (var child in treeItem.Items)
            {
                child.ParentGoal = treeItem;
                child.GoalEntryVM.ParentEntry = neuerDC;
                child.GoalEntryDC.Parent = neuerDC;

                RecursiveSynchronousSCValueListEntrySave(child);
            }
        }
    }
}