using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Xml;

using BeWo.Scheduler.View;
using BeWo.ServiceProxy;
using BeWo.ViewModel.ListViewModel;

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

using DevExpress.Data.Linq;
using DevExpress.Xpf.Scheduler;
using DevExpress.XtraScheduler;
using DevExpress.XtraScheduler.Native;

using SchedulerControl = DevExpress.Xpf.Scheduler.SchedulerControl;
using SchedulerStorage = DevExpress.Xpf.Scheduler.SchedulerStorage;

namespace BeWo.Scheduler.ViewModel
{
	public class SchedulerAppointmentListVM : AbstractDCListMapperVM<SchedulerAppointmentDC, SchedulerAppointmentVM>, ISchedulerViewModel
	{
		private const string CF_EMPLOYEELIST = "EmployeeList";
		private const string CF_CUSTOMERLIST = "CustomerList";
		private const string CF_RESOURCELIST = "ResourceList";
		private const string CF_ORIGINATOR   = "Originator";
		private const string CF_ISPRIVATE    = "IsPrivate";

		public bool ShouldLockOverlappingAppointmentCheck { get; set; }

		public SchedulerSettings GetDefaultSchedulerSettings()
		{
			var settings = new SchedulerSettings(AppointmentKind.General, AppointmentViewType.WorkWeek);
			return settings;
		}

		private BindingList<IBeWoAppointment> mAppointmentList;
		public BindingList<IBeWoAppointment> Appointments
		{
			get
			{
				if (mAppointmentList != null) return mAppointmentList;

				mAppointmentList = new BindingList<IBeWoAppointment>();
				mAppointmentList.AddingNew += mAppointmentList_AddingNew;

				foreach (var item in VMList)
					mAppointmentList.Add(item);
				
				return mAppointmentList;
			}
		}

		private readonly List<CompactCustomerDC> mAllCustomers;
		private readonly List<CompactEmployeeDC> mAllEmployees;
		private readonly Dictionary<ValueListEntryDC, List<ResourceDC>> mCategories2Resources;

		static void mAppointmentList_AddingNew(object sender, AddingNewEventArgs e)
		{
			var dc = new SchedulerAppointmentDC
			{
				EmployeeList = new List<Employee2SchedulerAppointmentDC>(),
				CustomerList = new List<CompactCustomerDC>(),
				ResourceList = new List<ResourceDC>(),
				//Originator   = ServiceFacade.DoEmployeeServiceSync(),
				Status       = 0
			};
			
			var neu = new SchedulerAppointmentVM(dc);
			e.NewObject = neu;
		}

        private Dictionary<Guid, Dictionary<String, Dictionary<String, Object>>> changedOccurencyCustomFields;
        public Dictionary<Guid, Dictionary<String, Dictionary<String, Object>>> ChangedOccurencyCustomFields { get; private set; }

		public List<CompactCustomerDC> AllCustomers
		{
			get { return mAllCustomers; }
		}

		public List<CompactEmployeeDC> AllEmployees
		{
			get { return mAllEmployees; }
		}

		public Dictionary<ValueListEntryDC, List<ResourceDC>> Categories2Resources
		{
			get { return mCategories2Resources; }
		}

		private Appointment geoeffneterTermin;

		public SchedulerAppointmentListVM(List<SchedulerAppointmentDC> appList, List<CompactCustomerDC> allCustomers, List<CompactEmployeeDC> allEmployees, Dictionary<ValueListEntryDC, List<ResourceDC>> lCategoriesToResources) : base(appList)
		{
			mCategories2Resources = lCategoriesToResources;
			mAllCustomers         = allCustomers;
			mAllEmployees         = allEmployees;

			InitChangedOccurrencyCustomFields(appList.Where(t => t.Type == 3).ToList());

			InitViewModel();
		}

		private void InitViewModel()
		{
			foreach (var item in VMList)
			{
				item.CustomFields.Add(CF_EMPLOYEELIST, item.EmployeeList);
				item.CustomFields.Add(CF_CUSTOMERLIST, item.CustomerList);
				item.CustomFields.Add(CF_RESOURCELIST, item.ResourceList);
				item.CustomFields.Add(CF_ORIGINATOR, item.Originator);
				item.CustomFields.Add(CF_ISPRIVATE, item.IsPrivate);

				item.Id = item.DataContract.SchedulerAppointmentOid;

                if (!item.IsPrivate || item.Originator.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid))
                {
                    continue;
                }

				item.Description = "Privater Termin";
				item.Subject = string.Format("Privat ({0})", item.Originator);
			}
		}

		private void UpdateViewModel(IEnumerable<SchedulerAppointmentDC> updatedDcList)
		{
			foreach (var dc in updatedDcList)
			{
				SchedulerAppointmentVM found = null;

				foreach (var vm in Appointments.OfType<SchedulerAppointmentVM>().Where(vm => vm.DataContract.Equals(dc)))
				{
				    found = vm;
				}

				if (found != null)
				{
				    found.DataContract = dc;
				}
			}
		}

		public void SaveAppointments(SchedulerControl control, IEnumerable<Appointment> list)
		{
			var sindGleich = false;
			var dcList = new List<SchedulerAppointmentDC>();

			foreach (var item in list)
			{
				var vm = item.GetSourceObject(control.GetCoreStorage()) as SchedulerAppointmentVM;
				if (vm == null)
				{
				    continue;
				}

				UpdateSchedulerAppointment(item, vm);

				if (!ShouldLockOverlappingAppointmentCheck && vm.EventType != 3)
				{
					var isOverlapping = false;

                    ServiceFacade.DoResourceServiceSync(s => isOverlapping = s.OverlappingAppointmentsExist(
                        vm.Start,
                        vm.End,
                        vm.EmployeeList.Select(emp => emp.Employee.EmployeeOid).ToList(),
                        vm.CustomerList.Select(cc => cc.CustomerOid).ToList(),
                        vm.ResourceList.Select(r => r.ResourceOid.Value).ToList(),
                        vm.Originator.EmployeeOid,
                        vm.DataContract.SchedulerAppointmentOid,
                        item.RecurrenceInfo != null ? item.RecurrenceInfo.Id.ToString() : string.Empty, item.RecurrenceIndex));

					if (isOverlapping)
					{
                        var erg = MessageBox.Show("Dieser Termin überschneidet sich mit einem anderen bereits existierenden Termin.\n Möchten Sie ihn wirklich speichern?", "Überschneidung", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);

						if (erg.Equals(MessageBoxResult.No))
						{
						    return;
						}
					}
				}

				if (item.Type.Equals(AppointmentType.ChangedOccurrence) && geoeffneterTermin != null)
				{
				    sindGleich = geoeffneterTermin.Equals(item);
				}

				if(!sindGleich)
				{
				    dcList.Add(vm.CommitToDataContract());
				}
			}

			if (dcList.Count <= 0)
			{
			    return;
			}

			NewSchedulerView.IgnoreChangeEvents = true;
			var mostRecentAppointments = new List<SchedulerAppointmentDC>();
			ServiceFacade.DoResourceServiceSync(sync => mostRecentAppointments = sync.UpdateSchedulerAppointments(dcList));
			UpdateViewModel(mostRecentAppointments);
			control.ActiveView.LayoutChanged();
			NewSchedulerView.IgnoreChangeEvents = false;
		}

		public void DeleteAppointments(SchedulerControl control, IEnumerable<Appointment> list)
		{
			var dcList = list.Select(item => item.GetSourceObject(control.GetCoreStorage())).OfType<SchedulerAppointmentVM>().Select(vm => vm.CommitToDataContract()).Where(dc => dc.SchedulerAppointmentOid.HasValue).ToList();
			var idList = (from item in dcList where item.SchedulerAppointmentOid.HasValue select item.SchedulerAppointmentOid.Value).ToList();

			NewSchedulerView.IgnoreChangeEvents = true;
			var mostRecentAppointments = new List<SchedulerAppointmentDC>();
			ServiceFacade.DoResourceServiceSync(s => mostRecentAppointments = s.GetSchedulerAppointmentsById(idList));
			ServiceFacade.DoResourceServiceSync(s2 => mostRecentAppointments = s2.DeactivateSchedulerAppointmentsForSync(mostRecentAppointments.ToDictionary(dc => dc.SchedulerAppointmentOid != null ? dc.SchedulerAppointmentOid.Value : 0, dc => dc.NewSchedulerAppointmentVersion.HasValue ? dc.NewSchedulerAppointmentVersion.Value : 0)));
			UpdateViewModel(mostRecentAppointments);
			control.ActiveView.LayoutChanged();
			NewSchedulerView.IgnoreChangeEvents = false;
		}

		public void InsertAppointments(SchedulerControl control, IEnumerable<Appointment> list)
		{
            var dcList = new List<SchedulerAppointmentDC>();
			foreach (var item in list)
			{
				var vm = item.GetSourceObject(control.GetCoreStorage()) as SchedulerAppointmentVM;
				if (vm == null)
				{
				    continue;
				}

				UpdateSchedulerAppointment(item, vm);

				if (!ShouldLockOverlappingAppointmentCheck)
				{
					var isOverlapping = false;
                    ServiceFacade.DoResourceServiceSync(s => isOverlapping = s.OverlappingAppointmentsExist(
                        vm.Start,
                        vm.End,
                        vm.EmployeeList.Select(emp => emp.Employee.EmployeeOid).ToList(),
                        vm.CustomerList.Select(cc => cc.CustomerOid).ToList(),
                        vm.ResourceList.Select(r => r.ResourceOid.Value).ToList(),
                        vm.Originator.EmployeeOid,
                        vm.DataContract.SchedulerAppointmentOid,
                        item.RecurrenceInfo != null ? item.RecurrenceInfo.Id.ToString() : string.Empty, item.RecurrenceIndex));

					if (isOverlapping)
					{
                        var erg = MessageBox.Show("Dieser Termin überschneidet sich mit einem anderen bereits existierenden Termin.\n Möchten Sie ihn wirklich speichern?", "Überschneidung", MessageBoxButton.YesNo, MessageBoxImage.Exclamation);

						if (erg.Equals(MessageBoxResult.No))
						{
						    return;
						}
					}
				}

				dcList.Add(vm.CommitToDataContract());
			}

			if (dcList.Count <= 0)
			{
			    return;
			}

			NewSchedulerView.IgnoreChangeEvents = true;
			var mostRecentAppointments = new List<SchedulerAppointmentDC>();
			ServiceFacade.DoResourceServiceSync(sync => mostRecentAppointments = sync.InsertSchedulerAppointments(dcList));
			UpdateViewModel(mostRecentAppointments);
			control.ActiveView.LayoutChanged();
			NewSchedulerView.IgnoreChangeEvents = false;
		}

		private void UpdateSchedulerAppointment(Appointment app, SchedulerAppointmentVM vm)
		{
			vm.EmployeeList = app.CustomFields[CF_EMPLOYEELIST] as List<Employee2SchedulerAppointmentDC> ?? new List<Employee2SchedulerAppointmentDC>();
			vm.CustomerList = app.CustomFields[CF_CUSTOMERLIST] as List<CompactCustomerDC>;
			vm.ResourceList = app.CustomFields[CF_RESOURCELIST] as List<ResourceDC>;
			vm.Originator   = app.CustomFields[CF_ORIGINATOR] as CompactEmployeeDC;
			vm.IsPrivate    = app.CustomFields[CF_ISPRIVATE] != null && (bool) app.CustomFields[CF_ISPRIVATE];

			// Soll nicht mehr geschehen
			//if (!vm.EmployeeList.Select(s => s.Employee).Contains(vm.Originator))
			//	vm.EmployeeList.Add(new Employee2SchedulerAppointmentDC {Employee = vm.Originator, ParticipationAnswer = ParticipationAnswer.Zusage});

			if (!vm.CustomFields.ContainsKey("EmployeeList"))
			{
			    vm.CustomFields.Add("EmployeeList", vm.EmployeeList);
			}

			if (!vm.CustomFields.ContainsKey("CustomerList"))
			{
			    vm.CustomFields.Add("CustomerList", vm.CustomerList);
			}

			if (!vm.CustomFields.ContainsKey("ResourceList"))
			{
			    vm.CustomFields.Add("ResourceList", vm.ResourceList);
			}

			if (!vm.CustomFields.ContainsKey("Originator"))
			{
			    vm.CustomFields.Add("Originator", vm.Originator);
			}

			if (!vm.CustomFields.ContainsKey("IsPrivate"))
			{
			    vm.CustomFields.Add("IsPrivate", vm.IsPrivate);
			}

			if (vm.CommitToDataContract() != null && vm.CommitToDataContract().SchedulerAppointmentOid.HasValue && vm.EmployeeList != null && vm.EmployeeList.Count > 0)
			{
				var alt = new SchedulerAppointmentDC();
				ServiceFacade.DoResourceServiceSync(s => alt = s.GetSchedulerAppointmentsById(new List<long> {vm.CommitToDataContract().SchedulerAppointmentOid.Value}).First());
				var alts  = alt.StartDate;
				var alte = alt.EndDate;
				if(alts != vm.Start || alte != vm.End)
				{
					var neu = vm.EmployeeList;
					vm.EmployeeList = neu.DoForEach(f =>
					{
						if (!f.Employee.Equals(vm.Originator))
						{
						    f.ParticipationAnswer = ParticipationAnswer.Offen;
						}
					}).ToList();
				}
			}
			
			if (vm.ResourceList == null || vm.ResourceList.Count <= 0) return;

			if (app.RecurrenceInfo != null)
			{
				var index = app.RecurrenceIndex.ToString();
				var id = app.RecurrenceInfo.Id;

				if (changedOccurencyCustomFields.ContainsKey(app.RecurrenceInfo.Id) && changedOccurencyCustomFields[id].ContainsKey(index))
				{
					if (app.Type.Equals(AppointmentType.ChangedOccurrence))
					{
						app.CustomFields["EmployeeList"] = changedOccurencyCustomFields[id][index]["EmployeeList"];
						app.CustomFields["CustomerList"] = changedOccurencyCustomFields[id][index]["CustomerList"];
						app.CustomFields["ResourceList"] = changedOccurencyCustomFields[id][index]["ResourceList"];
						app.CustomFields["Originator"]   = changedOccurencyCustomFields[id][index]["Originator"];
						app.CustomFields["IsPrivate"]    = changedOccurencyCustomFields[id][index]["IsPrivate"];
					}
				}
			}

			app.LabelId = vm.LabelId;
		}

		AbstractAppointmentEditForm ISchedulerViewModel.GetEditAppointmentForm(SchedulerControl control, Appointment appointment)
		{
			geoeffneterTermin             = control.Storage.CreateAppointment(AppointmentType.Normal);
			geoeffneterTermin.AllDay      = appointment.AllDay;
			geoeffneterTermin.Start       = appointment.Start;
			geoeffneterTermin.End         = appointment.End;
			geoeffneterTermin.Description = appointment.Description;

			foreach (CustomField cf in appointment.CustomFields)
			{
			    geoeffneterTermin.CustomFields[cf.Name] = cf.Value;
			}

			if (!appointment.Type.Equals(AppointmentType.ChangedOccurrence))
			{
			    return new SchedulerAppointmentEditForm(this, control, appointment, mAllEmployees, mAllCustomers, mCategories2Resources);
			}

			var index = appointment.RecurrenceIndex;
			var id    = appointment.RecurrenceInfo.Id;

			if (changedOccurencyCustomFields.ContainsKey(id) && changedOccurencyCustomFields[id].ContainsKey(index.ToString()))
			{
				var specialCustomFields = changedOccurencyCustomFields[id][index.ToString()];

				foreach (var cf in specialCustomFields)
				{
					appointment.CustomFields[cf.Key]       = cf.Value;
					geoeffneterTermin.CustomFields[cf.Key] = cf.Value;
				}
			}

			return new SchedulerAppointmentEditForm(this, control, appointment, mAllEmployees, mAllCustomers, mCategories2Resources);
		}

		public void ApplyChangesToChangedOccurencyCustomFields(List<Employee2SchedulerAppointmentDC> employees, List<CompactCustomerDC> customers, List<ResourceDC> resources, CompactEmployeeDC originator, bool isPrivate, string index, Guid id)
		{
			if (!changedOccurencyCustomFields.ContainsKey(id) || !changedOccurencyCustomFields[id].ContainsKey(index))
			{
			    return;
			}

			changedOccurencyCustomFields[id][index][CF_EMPLOYEELIST] = employees;
			changedOccurencyCustomFields[id][index][CF_CUSTOMERLIST] = customers;
			changedOccurencyCustomFields[id][index][CF_RESOURCELIST] = resources;
			changedOccurencyCustomFields[id][index][CF_ORIGINATOR]   = originator;
			changedOccurencyCustomFields[id][index][CF_ISPRIVATE]    = isPrivate;
		}

		public void AddCustomFieldsMapping(SchedulerStorage schedulerStorage)
		{
			var employeeMapping   = new SchedulerCustomFieldMapping(CF_EMPLOYEELIST, CF_EMPLOYEELIST);
			var customerMapping   = new SchedulerCustomFieldMapping(CF_CUSTOMERLIST, CF_CUSTOMERLIST);
			var resourceMapping   = new SchedulerCustomFieldMapping(CF_RESOURCELIST, CF_RESOURCELIST);
			var originatorMapping = new SchedulerCustomFieldMapping(CF_ORIGINATOR, CF_ORIGINATOR);
			var isPrivateMapping  = new SchedulerCustomFieldMapping(CF_ISPRIVATE, CF_ISPRIVATE);

			schedulerStorage.AppointmentStorage.CustomFieldMappings.Add(employeeMapping);
			schedulerStorage.AppointmentStorage.CustomFieldMappings.Add(customerMapping);
			schedulerStorage.AppointmentStorage.CustomFieldMappings.Add(resourceMapping);
			schedulerStorage.AppointmentStorage.CustomFieldMappings.Add(originatorMapping);
			schedulerStorage.AppointmentStorage.CustomFieldMappings.Add(isPrivateMapping);
		}

		public void InitNewAppointment(Appointment appointment)
		{
			appointment.CustomFields[CF_CUSTOMERLIST] = new List<CompactCustomerDC>();
			appointment.CustomFields[CF_EMPLOYEELIST] = new List<Employee2SchedulerAppointmentDC>();
			appointment.CustomFields[CF_RESOURCELIST] = new List<ResourceDC>();
            ServiceFacade.DoEmployeeServiceSync(s => appointment.CustomFields[CF_ORIGINATOR] = s.LoadCompactEmployee(BeWoApp.LoggedOnEmployee.EmployeeOid.Value));
			appointment.CustomFields[CF_ISPRIVATE]    = false;
			appointment.StatusId                      = 0;
		}

		public bool FilterAppointment(string filterCategory, object selectedObject, Appointment appointment, bool showPrivateAppointments)
		{
			var wirdAngezeigt = true; // -> wird standardmäßig angezeigt

			if(showPrivateAppointments)
				if (appointment.CustomFields["IsPrivate"] != null)
				{
					var isPrivate = Convert.ToBoolean(appointment.CustomFields["IsPrivate"]);
					if(!isPrivate)
						return true;
				}

			switch (filterCategory)
			{
				case "NurEigene":
					var resourceList = (List<ResourceDC>) appointment.CustomFields["ResourceList"];
					if (resourceList != null && resourceList.Any())
					{
						break;
					}

					var emps              = (List<Employee2SchedulerAppointmentDC>)appointment.CustomFields["EmployeeList"];
					var orig              = (CompactEmployeeDC) appointment.CustomFields["Originator"];
					var cus               = (List<CompactCustomerDC>) appointment.CustomFields["CustomerList"];
					var hatEigeneKlienten = false;
					var teams             = (List<CompactTeamDC>)((Dictionary<string, object>)selectedObject)["Teams"];

					if (cus != null)
					{
					    hatEigeneKlienten = cus.Select(sel => sel.CustomerOid).Intersect(BeWoApp.LoggedOnEmployee.RelatedCustomers.Select(se => se.Customer.CustomerOid)).Any() ||
					                        cus.Any(c => c.RelatedTeamOids != null && c.RelatedTeamOids.Intersect(teams.Select(t => t.TeamOid)).Any());
					}


                    // Ursprünglich: var isOriginatorWithoutParticipants = (orig != null && orig.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && (emps != null && (emps.Count == 0 || emps.Count == 1 && emps.Any(a => a.Employee.Equals(orig)))));

                    var isOriginatorWithoutParticipants = (orig != null && orig.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && ((emps != null && emps.Count == 1 && emps.Any(a => a.Employee.Equals(orig)))) || emps != null && emps.Count == 0);

			        var istEigenerTermin = (orig != null && orig.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && emps != null && emps.Count == 0) ||
			                               (emps != null && emps.Any(a => a.Employee.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid)));

                    var empsContainsEmployeesExceptOriginator = emps != null && emps.Count > 0 && orig != null && (orig.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && false == emps.Any(a => a.Employee.Equals(orig)));
					// Eingeloggter muss Originator oder in der Liste sein oder er darf Termine anderer ansehen
			        wirdAngezeigt = istEigenerTermin;//isOriginatorWithoutParticipants || false == empsContainsEmployeesExceptOriginator;// orig != null && (orig.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && (emps != null && emps.Count == 0))
			                            //|| emps != null && emps.Any(a => a.Employee.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid)) && emps.Count == 1
			                            //|| hatEigeneKlienten;
										//|| BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAnsehen);
					// false -> wird ignoriert (herausgefiltert)

                    //wirdAngezeigt = isOriginatorWithoutParticipants || empsContainsEmployeesExceptOriginator == false || BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAnsehen);

					break;
				case "NachAuswahl":
					var dictionary  = (Dictionary<string, object>) selectedObject;
					var ressourcen  = (List<ResourceDC>)           dictionary["Ressourcen"];
					var mitarbeiter = (List<CompactEmployeeDC>)    dictionary["Mitarbeiter"];
					var klienten    = (List<CompactCustomerDC>)    dictionary["Klienten"];

                    var originator = appointment.CustomFields["Originator"] as CompactEmployeeDC;
					var appEL      = (List<Employee2SchedulerAppointmentDC>) appointment.CustomFields["EmployeeList"];
					var appRL      = (List<ResourceDC>) appointment.CustomFields["ResourceList"];
					var appCL      = (List<CompactCustomerDC>) appointment.CustomFields["CustomerList"];

					var cfe = (appEL == null ? new List<CompactEmployeeDC>() : appEL.Select(s=>s.Employee).ToList());
					var cfr = appRL ?? new List<ResourceDC>();
					var cfc = appCL ?? new List<CompactCustomerDC>();

                    var hasOnlyOriginatorInCommon = appEL!=null && originator != null && appEL.Any() == false && mitarbeiter.Contains(originator);

					var m = cfe.Intersect(mitarbeiter).ToList();
					var r = cfr.Intersect(ressourcen).ToList();
					var k = cfc.Intersect(klienten).ToList();

					wirdAngezeigt = (m.Any() || k.Any() || r.Any()) || hasOnlyOriginatorInCommon;
					break;
				case "Ebenen":
					var liste         = (List<bool>) selectedObject; // mkr
					var appEList      = ((List<Employee2SchedulerAppointmentDC>) appointment.CustomFields["EmployeeList"]).Where(w => !w.Employee.Equals(appointment.CustomFields["Originator"])).ToList();
					var appRList      = (List<ResourceDC>) appointment.CustomFields["ResourceList"];
					var appCList      = (List<CompactCustomerDC>) appointment.CustomFields["CustomerList"];

					// Ersteller und Rechte beachten
					var o = (CompactEmployeeDC) appointment.CustomFields["Originator"];
                    var istEigen = o.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid);

					var mVorhanden = appEList.Any(a2app => mAllEmployees.Contains(a2app.Employee));
					var kVorhanden = appCList.Any(mAllCustomers.Contains);

					wirdAngezeigt = liste[0] && mVorhanden || liste[1] && appRList.Any() || liste[2] && kVorhanden;

					// Nur Ansehen
                    if (!istEigen && !BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAnsehen) && liste[0] && mVorhanden && !appEList.Select(e2sa => e2sa.Employee).Any(a => a.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid)))
                    {
                        wirdAngezeigt = false;
                    }

					if (!istEigen && !BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderKliententermineAlleAnsehen) && liste[2] && kVorhanden)
					{
					    wirdAngezeigt = false;
					}
					
					if (!istEigen && !BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderRessourcentermineAnsehen) && liste[1] && appRList.Any())
					{
					    wirdAngezeigt = false;
					}

					break;
			}

			return !wirdAngezeigt;
		}

		public void InitChangedOccurrencyCustomFields(IEnumerable<SchedulerAppointmentDC> appList)
		{
			changedOccurencyCustomFields = new Dictionary<Guid, Dictionary<string, Dictionary<string, object>>>();
			foreach (var termin in appList)
			{
				var ri = new RecurrenceInfo();
				ri.FromXml(termin.RecurrenceInfo);
				string index;
				using (var reader = XmlReader.Create(new StringReader(termin.RecurrenceInfo)))
				{
					reader.ReadToFollowing("RecurrenceInfo");
					reader.MoveToAttribute("Index");
					index = reader.Value;
				}

				if (index.Equals(""))
					index = "0";

				var customFieldCollection              = new Dictionary<string, object>();
				customFieldCollection[CF_CUSTOMERLIST] = termin.CustomerList;
				customFieldCollection[CF_EMPLOYEELIST] = termin.EmployeeList;
				customFieldCollection[CF_RESOURCELIST] = termin.ResourceList;
				customFieldCollection[CF_ORIGINATOR]   = termin.Originator;
				customFieldCollection[CF_ISPRIVATE]    = termin.IsPrivate;

				if (!changedOccurencyCustomFields.ContainsKey(ri.Id))
					changedOccurencyCustomFields.Add(ri.Id, new Dictionary<string, Dictionary<string, object>> { { index, customFieldCollection } });
				else if (!changedOccurencyCustomFields[ri.Id].ContainsKey(index))
					changedOccurencyCustomFields[ri.Id].Add(index, customFieldCollection);
				else
					changedOccurencyCustomFields[ri.Id][index] = customFieldCollection;
			}
		}

        //TODO: alle relevanten Eigenschaften beachten und eigene AreEqual Extension schreiben (erledigt) (https://www.devexpress.com/Support/Center/Question/Details/T270666)
        public override bool Equals(object pObj)
        {
            var obj = (SchedulerAppointmentListVM)pObj;
            if (obj == null)
            {
                return false;
            }

            var appointmentsAreEqual = Appointments == null && obj.Appointments == null || Appointments != null && Appointments.AreEqual(obj.Appointments);
            
            var allCustomersAreEqual = AllCustomers == null && obj.AllCustomers == null || 
                                AllCustomers != null && obj.AllCustomers != null && AllCustomers.Count == obj.AllCustomers.Count &&
                                !AllCustomers
                                .Where(
                                        (t, i) =>
                                            !(
                                                t.CustomerOid.Equals(obj.AllCustomers[i].CustomerOid) &&
                                                t.CustomerVersion.Equals(obj.AllCustomers[i].CustomerVersion)
                                             )
                                      ).Any();

            var allEmployeesAreEqual = AllEmployees == null && obj.AllEmployees == null ||
                                   AllEmployees != null && obj.AllEmployees != null && AllEmployees.Count == obj.AllEmployees.Count &&
                                   !AllEmployees
                                   .Where(
                                        (t, i) => 
                                            !(
                                                t.EmployeeOid.Equals(obj.AllEmployees[i].EmployeeOid) && 
                                                t.EmployeeVersion.Equals(obj.AllEmployees[i].EmployeeVersion)
                                             )
                                         ).Any();

            var areEqual =
                VMList.AreEqual(obj.VMList) &&
                IsDirty == obj.IsDirty &&
                allCustomersAreEqual &&
                allEmployeesAreEqual &&
                appointmentsAreEqual &&
                Equals(Categories2Resources, obj.Categories2Resources) &&
                Equals(ChangedOccurencyCustomFields, obj.ChangedOccurencyCustomFields);

            return areEqual;
        }
	}
}

