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

using BeWo.ServiceProxy;

using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;

namespace BeWo.Core.Service
{
    public class Cache
    {
        private static Cache mInstance;

        private List<CompactSupportConceptDC> mActiveAndApprovedSupportConceptCostbearerList;
        private List<CompactSupportConceptDC> mActiveCompactSupportConceptList;
        private List<CompactSupportConceptDC> mActiveSupportConceptCostbearerList;

        private List<AdditionalServiceGroupOfPeopleDC> AdditionalServiceGroupOfPeopleList;

        private Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>> mServiceCategoryDescriptionDict;

        private List<SupportConceptTreeNodeDC> mSupportConceptTree;
        private List<SupportConceptTreeNodeDC> mSupportConceptTreeAllActiveWithCostbearer;

        private Dictionary<ValueListEntryType, List<ValueListEntryDC>> mValueListEntryDict;

        private List<CompactEmployeeDC> mAllCompactEmployees;

		private List<CompactCustomerDC> mAllCompactCustomers;

        private List<CompactWohnheimDC> mAllCompactWohnheims;

        private List<CompactCustomerDC> mAllActiveCompactCustomers;

        private List<CompactEmployeeDC> mTeamMembers;

		private Dictionary<ValueListEntryDC, List<ResourceDC>> mCats2ResInDic;

        private Cache()
        {
        }

        public static Cache GetInstance()
        {
            if (mInstance == null)
            {
                mInstance = new Cache();
            }

            return mInstance;
        }

        public void ClearAll()
        {
            this.ClearSupportConceptTree();
            this.ClearServiceCategoryDescriptions();
            this.ClearAllValueListEntries();
            this.ClearEmployees();
			this.ClearCustomers();
            this.ClearWohnheims();
			ClearResources();
        }

        public void ClearAllValueListEntries()
        {
            this.mValueListEntryDict = null;
        }

        public void ClearServiceCategoryDescriptions()
        {
            this.mServiceCategoryDescriptionDict = null;
        }

        public void ClearSupportConceptTree()
        {
            this.mSupportConceptTree = null;
            this.mSupportConceptTreeAllActiveWithCostbearer = null;
            this.mActiveAndApprovedSupportConceptCostbearerList = null;
            this.mActiveSupportConceptCostbearerList = null;
            this.mActiveCompactSupportConceptList = null;
        }

        public void ClearValueListEntries(ValueListEntryType type)
        {
            if (this.mValueListEntryDict != null && this.mValueListEntryDict.ContainsKey(type))
            {
                this.mValueListEntryDict.Remove(type);
            }
        }

        public void ClearEmployees()
        {
            this.mAllCompactEmployees = null;
            this.mTeamMembers = null;

        }

        public void ClearWohnheims()
        {
            mAllCompactWohnheims = null;
        }
        
		public void ClearCustomers()
		{
			mAllCompactCustomers = null;
			mAllActiveCompactCustomers = null;
		}

	    public void ClearResources()
	    {
		    mCats2ResInDic = null;
	    }

		public void GetActiveSupportConceptCostbearer(Action<List<CompactSupportConceptDC>> callback)
        {
            if (this.mActiveSupportConceptCostbearerList == null)
            {
                ServiceFacade.DoOperationsServiceAsync(
                    s => s.GetAllActiveSupportConceptCostbearer(false, true, BeWoApp.LoggedOnEmployee.EmployeeOid.Value),
                    r =>
                    {
                        r.Sort((x, y) => { return (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName); });
                        this.mActiveSupportConceptCostbearerList = r;

                        callback(r);
                    });
            }
            else
            {
                callback(this.mActiveSupportConceptCostbearerList);
            }
        }

        //public void GetActiveSupportConceptCostbearer(Action<List<CompactSupportConceptDC>> callback)
        //{
        //    if (this.mActiveSupportConceptCostbearerList == null)
        //    {
                
        //        var list = ServiceFacade.DoOperationsServiceSync(
        //            s => s.GetAllActiveSupportConceptCostbearer(false, true, BeWoApp.LoggedOnEmployee.EmployeeOid.Value));

        //        list.Sort((x, y) => { return (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName); });
        //        this.mActiveSupportConceptCostbearerList = list;
                            
        //    }
        //    else
        //    {
        //        callback(this.mActiveSupportConceptCostbearerList);
        //    }
        //}

        public void GetAllActiveAndApprovedSupportConceptCostbearer(Action<List<CompactSupportConceptDC>> callback)
        {
            if (this.mActiveAndApprovedSupportConceptCostbearerList == null)
            {
                ServiceFacade.DoOperationsServiceAsync(
                    s => s.GetAllActiveSupportConceptCostbearer(true, true, BeWoApp.LoggedOnEmployee.EmployeeOid.Value), 
                    r =>
                        {
                            r.Sort((x, y) => { return (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName); });
                            this.mActiveAndApprovedSupportConceptCostbearerList = r;
                            callback(r);
                        });
            }
            else
            {
                callback(this.mActiveAndApprovedSupportConceptCostbearerList);
            }
        }


        public void GetAllAdditionalServiceGroupOfPeople(Action<List<AdditionalServiceGroupOfPeopleDC>> callback)
        {
            ServiceFacade.DoOperationsServiceAsync(
                    s => s.GetAllAdditionalServiceGroupOfPeople(),
                    r =>
                    {
                        r.Sort((x, y) => x.Name.CompareTo(y.Name));
                        AdditionalServiceGroupOfPeopleList = r;
                        callback(r);
                    }
                );
        }

        public void GetAllActiveSupportConceptsCompact(Action<List<CompactSupportConceptDC>> callback)
        {
            if (this.mActiveCompactSupportConceptList == null)
            {
                ServiceFacade.DoCustomerServiceAsync(
                    s => s.GetAllActiveSupportConceptsCompact(), 
                    r =>
                        {
                            r.Sort((x, y) => { return (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName); });
                            this.mActiveCompactSupportConceptList = r;
                            callback(r);
                        });
            }
            else
            {
                callback(this.mActiveCompactSupportConceptList);
            }
        }

        public void GetAllValueListEntrysByTypeAsync(ValueListEntryType type, Action<List<ValueListEntryDC>> callback)
        {
            if (this.mValueListEntryDict == null)
            {
                this.mValueListEntryDict = new Dictionary<ValueListEntryType, List<ValueListEntryDC>>();
            }

            if (this.mValueListEntryDict.ContainsKey(type))
            {
                callback(this.mValueListEntryDict[type]);
            }
            else
            {
                ServiceFacade.DoValueListServiceAsync(
					s1 => s1.GetAllValueListEntrysByType(type), 
                    list =>
                        {
                            this.mValueListEntryDict[type] = list;
                            callback(list);
                        });
            }
        }

		public List<ValueListEntryDC> GetAllValueListEntrysByTypeSync(ValueListEntryType type)
		{
			if (this.mValueListEntryDict == null)
			{
				this.mValueListEntryDict = new Dictionary<ValueListEntryType, List<ValueListEntryDC>>();
			}

			if (this.mValueListEntryDict.ContainsKey(type))
			{
				return this.mValueListEntryDict[type];
			}
			else
			{
				var list = ServiceFacade.DoValueListServiceSync(s1 => s1.GetAllValueListEntrysByType(type));
				this.mValueListEntryDict[type] = list;
				return list;
			}
		}

        public void GetServiceCategoryDescriptionDict(Action<Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>>> callback)
        {
            if (this.mServiceCategoryDescriptionDict == null)
            {
                this.mServiceCategoryDescriptionDict = new Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>>();
                ServiceFacade.DoOperationsServiceAsync(
                    s => s.GetAllServiceDescriptions(), 
                    lDescriptons => ServiceFacade.DoOperationsServiceAsync(
                        s => s.GetAllServiceCategories(), 
                        lCategories =>
                            {
                                foreach (var iCat in lCategories)
                                {
                                    this.mServiceCategoryDescriptionDict.Add(iCat, lDescriptons.Where(d => d.Category.ServiceCategoryOid == iCat.ServiceCategoryOid).ToList());
                                }

                                callback(this.mServiceCategoryDescriptionDict);
                            }));
            }
            else
            {
                callback(this.mServiceCategoryDescriptionDict);
            }
        }

        public void GetSupportConceptTree(Action<List<SupportConceptTreeNodeDC>> callback)
        {
            if (this.mSupportConceptTree == null)
            {
                ServiceFacade.DoOperationsServiceAsync(
                    s => s.GetSupportConceptTreeByEmployee(BeWoApp.LoggedOnUser.Employee.EmployeeOid), 
                    lTree =>
                        {
                            lTree.DoForEach(n => n.RecursivelySetParentOnChilds());

                            this.mSupportConceptTree = lTree;
                            callback(this.mSupportConceptTree);
                        });
            }
            else
            {
                callback(this.mSupportConceptTree);
            }
        }

        public void GetSupportConceptTreeAllActiveWithCostbearer(Action<List<SupportConceptTreeNodeDC>> callback)
        {
            if (this.mSupportConceptTreeAllActiveWithCostbearer == null)
            {
                ServiceFacade.DoOperationsServiceAsync(
                    s => s.GetSupportConceptTreeAllActiveWithCostbearer(), 
                    lTree =>
                        {
                            lTree.DoForEach(n => n.RecursivelySetParentOnChilds());

                            this.mSupportConceptTreeAllActiveWithCostbearer = lTree;
                            callback(lTree);
                        });
            }
            else
            {
                callback(this.mSupportConceptTreeAllActiveWithCostbearer);
            }
        }

        public ValueListEntryDC GetValueListEntry(long oid)
        {
	        if (mValueListEntryDict == null)
	        {
		        var liste = ServiceFacade.DoValueListServiceSync(s => s.GetAllValueListEntriesByOidForType(oid));
				mValueListEntryDict = new Dictionary<ValueListEntryType, List<ValueListEntryDC>> { { liste[0].Type , liste} };
	        }

            foreach (var list in mValueListEntryDict.Values)
            {
                var result = list.Where(obj => obj.ValueListEntryOid == oid).ToList();
                if (result.Any())
                {
                    return result.First();
                }
            }

            return null;
        }

        public ValueListEntryDC GetValueListEntry(ValueListEntryType type, long oid)
        {
            if (this.mValueListEntryDict.ContainsKey(type))
            {
                List<ValueListEntryDC> list = this.mValueListEntryDict[type];

                var result = list.Where(obj => obj.ValueListEntryOid == oid);
                if (result.Count() > 0)
                {
                    return result.First();
                }
            }

            return null;
        }

        public void GetAllActiveEmployeesCompact(Action<List<CompactEmployeeDC>> pCallBack)
        {
            if (mAllCompactEmployees == null)
            {
                ServiceFacade.DoEmployeeServiceAsync(
                    s => s.GetAllActiveEmployeesCompact(),
                   r =>
                   {
                       r.Sort((x, y) => (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName));

                       mAllCompactEmployees = r;
                       pCallBack(r);
                   });
            }
            else
            {
                pCallBack(mAllCompactEmployees);
            }
        }

	    public List<CompactEmployeeDC> GetAllActiveEmployeesCompactSync()
	    {
		    if (mAllCompactEmployees == null)
		    {
			    ServiceFacade.DoEmployeeServiceSync(s => mAllCompactEmployees = s.GetAllActiveEmployeesCompact());
				mAllCompactEmployees.Sort((x, y) => (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName));
		    }

		    return mAllCompactEmployees;
	    }

        public void GetAllTeamMemberForEmployee(CompactEmployeeDC employee, Action<List<CompactEmployeeDC>> pCallBack)
        {
            if (this.mTeamMembers == null)
            {
                ServiceFacade.DoEmployeeServiceAsync(
                    s => s.GetAllTeamMember(employee),
                   r =>
                   {
                       r.Sort((x, y) => { return (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName); });

                       mTeamMembers = r;
                       pCallBack(r);
                   });
            }
            else
            {
                pCallBack(this.mTeamMembers);
            }


        }

		public void GetAllActiveAndArchivedCustomerCompact(Action<List<CompactCustomerDC>> pCallBack)
		{
			if (mAllCompactCustomers == null)
			{
				ServiceFacade.DoCustomerServiceAsync(
					s => s.GetAllActiveAndArchivedCustomersCompact(BeWoApp.LoggedOnEmployee.EmployeeOid.Value),
				   r =>
				   {
					   r.Sort((x, y) => (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName));

					   mAllCompactCustomers = r;
					   pCallBack(r);
				   });
			}
			else
			{
				pCallBack(mAllCompactCustomers);
			}
		}

	    public List<CompactCustomerDC> GetAllActiveAndArchivedCustomerCompactSync()
	    {
		    if (mAllCompactCustomers == null)
		    {
			    ServiceFacade.DoCustomerServiceSync(cs => mAllCompactCustomers = cs.GetAllActiveAndArchivedCustomersCompact(BeWoApp.LoggedOnEmployee.EmployeeOid.Value));
				mAllCompactCustomers.Sort((x, y) => (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName));
		    }
		    
			return mAllCompactCustomers;
	    }

	    public void GetCategories2ResourcesDictionary(Action<Dictionary<ValueListEntryDC, List<ResourceDC>>> pCallBack)
	    {
		    if (mCats2ResInDic == null)
		    {
				ServiceFacade.DoResourceServiceAsync(rs => rs.GetAllCategories2ResourcesInDictionary(), 
					r =>
					{
						mCats2ResInDic = r;
						pCallBack(r);
					});
		    }
		    else
		    {
			    pCallBack(mCats2ResInDic);
		    }
	    }

		public Dictionary<ValueListEntryDC, List<ResourceDC>> GetCategories2ResourcesDictionarySync()
		{
			if (mCats2ResInDic == null)
			{
				ServiceFacade.DoResourceServiceSync(rs => mCats2ResInDic = rs.GetAllCategories2ResourcesInDictionary());
			}

			return mCats2ResInDic;
		}

		public void GetAllActiveCustomersCompact(Action<List<CompactCustomerDC>> pCallBack)
		{
			if (mAllActiveCompactCustomers == null)
			{
				ServiceFacade.DoCustomerServiceAsync(
					s => s.GetAllActiveCompactCustomers(),
				   r =>
				   {
					   r.Sort((x, y) => (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName));

					   mAllActiveCompactCustomers = r;
					   pCallBack(r);
				   });
			}
			else
			{
				pCallBack(mAllActiveCompactCustomers);
			}
		}

		public List<CompactCustomerDC> GetAllActiveCustomersCompactSync()
		{
			if (mAllActiveCompactCustomers == null)
			{
				ServiceFacade.DoCustomerServiceSync(cs => mAllActiveCompactCustomers = cs.GetAllActiveCompactCustomers());
				mAllActiveCompactCustomers.Sort((x, y) => (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName));
			}

			return mAllActiveCompactCustomers;
		}

	    public List<CompactCustomerDC> GetAllCustomersCompact(Action<List<CompactCustomerDC>> pCallBack)
	    {
		    if (mAllCompactCustomers == null)
		    {
			    ServiceFacade.DoCustomerServiceAsync(cs=>cs.GetAllCompactCustomers(), r =>
			    {
					r.Sort((x, y) => (x.LastName + ", " + x.FirstName).CompareTo(y.LastName + ", " + y.FirstName));
				    mAllCompactCustomers = r;
				    pCallBack(r);
			    });
		    }

		    return mAllCompactCustomers;
	    }
    }
}