using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

using BeWo.Annotations;
using BeWo.Scheduler.ViewModel;
using BeWo.ServiceProxy;
using BeWo.View.Search;

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

using DevExpress.Xpf.Editors;
using DevExpress.Xpf.Scheduler.UI;
using DevExpress.XtraScheduler;
using SchedulerControl = DevExpress.Xpf.Scheduler.SchedulerControl;

namespace BeWo.Scheduler.View
{
	public partial class SchedulerAppointmentEditForm : INotifyPropertyChanged
	{
		public bool IsInCustomerViewMode { get; set; }

		private List<ValueListEntryDC> _Categories;
		public List<ValueListEntryDC> Categories
		{
			get { return _Categories; }
			set { _Categories = value; OnPropertyChanged("Categories"); }
		}

		private List<ResourceDC> _ResourceList;
		public List<ResourceDC> ResourceList
		{
			get { return _ResourceList; }
			set { _ResourceList = value; OnPropertyChanged("ResourceList"); }
		}

		public SchedulerAppointmentListVM ViewModel { get; set; }

		static void recurrenceControl_Loaded(object sender, RoutedEventArgs e)
		{
			LocalizeVisualChild(sender as DependencyObject);
		}

		public NewSchedulerAppointmentFormController NewSchedulerAppointmentFormController { get { return Controller as NewSchedulerAppointmentFormController; } }

		private ObservableCollection<ResourceDC> selectedResources;
		public ObservableCollection<ResourceDC> SelectedResources
		{
			get { return selectedResources ?? (selectedResources = new ObservableCollection<ResourceDC>(NewSchedulerAppointmentFormController.ResourceList ?? new List<ResourceDC>())); }
			set
			{
				selectedResources = value;
				SelectedResources.CollectionChanged += SelectedResourcesCollectionChanged;
				NewSchedulerAppointmentFormController.ResourceList = value.ToList();
				OnPropertyChanged("SelectedResources");
			}
		}

		private ObservableCollection<Employee2SchedulerAppointmentDC> selectedEmployees;
		public ObservableCollection<Employee2SchedulerAppointmentDC> SelectedEmployees
		{
			get { return selectedEmployees ?? (selectedEmployees = new ObservableCollection<Employee2SchedulerAppointmentDC>(NewSchedulerAppointmentFormController.EmployeeList ?? new List<Employee2SchedulerAppointmentDC>())); }
			set
			{
				if (selectedEmployees.Equals(value)) return;

				selectedEmployees = value;
				SelectedEmployees.CollectionChanged += SelectedEmployeesCollectionChanged;
				NewSchedulerAppointmentFormController.EmployeeList = value.ToList();
				OnPropertyChanged("SelectedEmployees");
			}
		}

		private ObservableCollection<CompactCustomerDC> selectedCustomers;
		public ObservableCollection<CompactCustomerDC> SelectedCustomers
		{
			get
			{
				var newList = new ObservableCollection<CompactCustomerDC>(NewSchedulerAppointmentFormController.CustomerList ?? new List<CompactCustomerDC>());
				return selectedCustomers ?? (selectedCustomers = newList);
			}
			set
			{
				if (selectedCustomers.Equals(value)) return;

				selectedCustomers = value;
				SelectedCustomers.CollectionChanged += SelectedCustomersCollectionChanged;
				NewSchedulerAppointmentFormController.CustomerList = value.ToList();
				OnPropertyChanged("SelectedCustomers");
			}
		}

		public SchedulerAppointmentEditForm(SchedulerAppointmentListVM vm, SchedulerControl schedulerControl, Appointment appointment, 
											IEnumerable<CompactEmployeeDC> employees, IEnumerable<CompactCustomerDC> customers, Dictionary<ValueListEntryDC, List<ResourceDC>> categoriesToResources)
			: base(schedulerControl, appointment)
		{
			ViewModel = vm;

			InitializeComponent();

			EdtRecurrenceType.Visibility = ShouldShowRecurrence ? Visibility.Visible : Visibility.Collapsed;

			SelectedResources.CollectionChanged += SelectedResourcesCollectionChanged;
			SelectedCustomers.CollectionChanged += SelectedCustomersCollectionChanged;
			SelectedEmployees.CollectionChanged += SelectedEmployeesCollectionChanged;

			DataContext = this;
			
			Categories = categoriesToResources.Keys.ToList();
			if (categoriesToResources.Count > 0)
			{
				ResourceList = categoriesToResources.First().Value;
			}
			MonthlyRecurrenceControl.Loaded += recurrenceControl_Loaded;
			YearlyRecurrenceControl.Loaded += recurrenceControl_Loaded;

			ResourcesTreeSearchView.Sauce = categoriesToResources;
			ResourcesTreeSearchView.AusgewaehlteRessourcen = SelectedResources.ToList();
			ResourcesTreeSearchView.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (s, e) => this.Dispatch(() => { PopupResource.IsOpen = false; })));

			MultiEmployeeSearch.Sauce = employees.ToObservableCollection();
			MultiEmployeeSearch.AusgewaehlteMitarbeiter = SelectedEmployees.Select(e=>e.Employee).ToList();
			MultiEmployeeSearch.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (s, e) => this.Dispatch(() => { PopupEmployee.IsOpen = false; })));

			MultiCustomerSearch.Sauce = customers.ToObservableCollection();
			MultiCustomerSearch.AusgewaehlteKlienten = SelectedCustomers.ToList();
			MultiCustomerSearch.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (s, e) => this.Dispatch(() => { PopupCustomer.IsOpen = false; })));

			EdtRecurrenceType.CustomDisplayText += edtRecurrenceType_CustomDisplayText;

			InitRights();
		}

		private void InitRights()
		{
			if (!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAnlegen))
				MitarbeiterPopUpOeffnenBtn.Visibility = Visibility.Collapsed;

			if (!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderKliententermineAnlegen))
				KlientenPopUpOeffnenBtn.Visibility = Visibility.Collapsed;

			if (!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderRessourcentermineAnlegen))
				RessourcenPopUpOeffnenBtn.Visibility = Visibility.Collapsed;

			var m = SelectedEmployees;
			var k = SelectedCustomers;
			var r = SelectedResources;

			var allowedToChange = true;

            if (!NewSchedulerAppointmentFormController.Originator.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid))
			{
				if (m.Count > 0 && !BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAendern))
					allowedToChange = false;
				if (k.Count > 0 && !BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderKliententermineAendern))
					allowedToChange = false;
				if (r.Count > 0 && !BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderRessourcentermineAendern))
					allowedToChange = false;
			}

			if (allowedToChange) 
				return;

			OKButton.Visibility = Visibility.Hidden;
			DeleteButton.Visibility = Visibility.Hidden;
		}

		static void edtRecurrenceType_CustomDisplayText(object sender, CustomDisplayTextEventArgs e)
		{
			var conv = new Converter.Recurrence2GermanConverter();

			e.DisplayText = (string) conv.Convert(e.EditValue, typeof (string), null, null);
			e.Handled = true;
		}

		public string CountSelectedEmployees
		{
			get { return string.Format("{0} Mitarbeiter ausgewählt", SelectedEmployees.Count); }
		}
		public string CountSelectedResources
		{
			get { return string.Format("{0} Resourcen ausgewählt", SelectedResources.Count); }
		}
		public string CountSelectedCustomers
		{
			get { return string.Format("{0} Klienten ausgewählt", SelectedCustomers.Count); }
		}

		public override AppointmentFormController CreateFormController(SchedulerControl schedulerControl, Appointment appointment)
		{
			return new NewSchedulerAppointmentFormController(schedulerControl, appointment);
		}

		void SelectedCustomersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			NewSchedulerAppointmentFormController.CustomerList = SelectedCustomers.ToList();
			MultiCustomerSearch.AusgewaehlteKlienten = SelectedCustomers.ToList();
		}

		void SelectedResourcesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			NewSchedulerAppointmentFormController.ResourceList = SelectedResources.ToList();
			ResourcesTreeSearchView.AusgewaehlteRessourcen = SelectedResources.ToList();
		}
		void SelectedEmployeesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			NewSchedulerAppointmentFormController.EmployeeList = SelectedEmployees.ToList();
			MultiEmployeeSearch.AusgewaehlteMitarbeiter = SelectedEmployees.Select(em => em.Employee).ToList();
		}

		public event PropertyChangedEventHandler PropertyChanged;
		[NotifyPropertyChangedInvocator]
		protected void OnPropertyChanged(string propertyName)
		{
			var handler = PropertyChanged;
			if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
		}

		private void popupedit_employee_PopUpClick(object sender, RoutedEventArgs e)
		{
			PopupEmployee.IsOpen = true;
		}

		private void popupedit_customer_PopUpClick(object sender, RoutedEventArgs e)
		{
			ResourcesTreeSearchView.AusgewaehlteRessourcen = selectedResources.ToList();
			PopupCustomer.IsOpen = true;
		}

		private void popupedit_resource_PopUpClick(object sender, RoutedEventArgs e)
		{
			PopupResource.IsOpen = true;
		}

		private void button_ok_Click(object sender, RoutedEventArgs e)
		{
			try
			{
				ViewModel.NewVM.EmployeeList = NewSchedulerAppointmentFormController.EmployeeList;

				var employees  = NewSchedulerAppointmentFormController.EmployeeList;
				var customers  = NewSchedulerAppointmentFormController.CustomerList;
				var resources  = NewSchedulerAppointmentFormController.ResourceList;
				var originator = NewSchedulerAppointmentFormController.Originator;
				var isPrivate  = NewSchedulerAppointmentFormController.IsPrivate;

				ViewModel.NewVM.AllDay       = !Appointment.AllDay;
				ViewModel.NewVM.IsPrivate    = isPrivate;
				ViewModel.NewVM.ResourceList = resources;
				ViewModel.NewVM.CustomerList = customers;
				ViewModel.NewVM.Originator   = originator;

			    NewSchedulerView.IgnoreChangeEvents = true;
				Appointment.CustomFields["IsPrivate"]    = isPrivate;
				Appointment.CustomFields["ResourceList"] = resources;
				Appointment.CustomFields["CustomerList"] = customers;
				Appointment.CustomFields["Originator"]   = originator;
				Appointment.CustomFields["EmployeeList"] = employees;
                NewSchedulerView.IgnoreChangeEvents = false;

                // Änderung an den CustomFields lösen das NewSchedulerStorage_AppointmentsChanged-Event aus

				var employeeOids = new List<long>();
				var customerOids = new List<long>();
				var overlaps     = false;

				foreach (var emp in employees)
				{
					employeeOids.AddIfNotIn(emp.Employee.EmployeeOid);
				}

				foreach (var customer in customers)
				{
					customerOids.AddIfNotIn(customer.CustomerOid);
				}

			    var item = (SchedulerAppointmentVM) Appointment.GetSourceObject(Control.GetCoreStorage());

				ServiceFacade.DoResourceServiceSync(definedBelow => overlaps = definedBelow.OverlappingAppointmentsExist(Appointment.Start, Appointment.End, employeeOids, customerOids, resources.Select(res => res.ResourceOid.Value).ToList(), ViewModel.NewVM.Originator.EmployeeOid, (item != null ? item.CommitToDataContract().SchedulerAppointmentOid : null), String.Empty, Appointment.RecurrenceIndex));
				if (overlaps)
				{
                    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;
					}
				}

				ViewModel.ShouldLockOverlappingAppointmentCheck = true;

				if (Appointment.RecurrenceInfo != null)
				{
				    ViewModel.ApplyChangesToChangedOccurencyCustomFields(employees, customers, resources, originator, isPrivate, Appointment.RecurrenceIndex.ToString(), Appointment.RecurrenceInfo.Id);
				}

				if (Appointment.IsOccurrence && item == null)
				{
					((List<Employee2SchedulerAppointmentDC>)Appointment.CustomFields["EmployeeList"]).ForEach(each =>
					{
						each.Employee2SchedulerAppointmentOid = null;
						each.Employee2SchedulerAppointmentVersion = null;
						each.SchedulerAppointmentOid = null;
						each.IsPChanged = false;
						each.IsPC_CheckedTs = null;
					});
				}

				ApplyChanges();
				ViewModel.ShouldLockOverlappingAppointmentCheck = false;
			}
			catch (Exception exception)
			{
				MessageBox.Show(exception.Message + "\n" + exception.StackTrace);
			}
		}

		private void button_cancel_Click(object sender, RoutedEventArgs e)
		{
			Cancel();
		}

		private void button_delete_Click(object sender, RoutedEventArgs e)
		{
			DeleteAppointment();
		}

		private void btnRemoveElement_Click(object sender, RoutedEventArgs e)
		{
			var obj = ((Button) sender).Tag;

			var res = obj as ResourceDC;
			if (res != null)
			{
				SelectedResources.Remove(res);
				OnPropertyChanged("CountSelectedResources");
			}

			var cus = obj as CompactCustomerDC;
			if (cus != null)
			{
				SelectedCustomers.Remove(cus);
				OnPropertyChanged("CountSelectedCustomers");
			}

			if (!(obj is Employee2SchedulerAppointmentDC)) return;

			var emp = (Employee2SchedulerAppointmentDC) obj;
			SelectedEmployees.Remove(emp);
			OnPropertyChanged("CountSelectedEmployees");
		}

		private void ResourcesTreeSearchView_OnSelectionChanged(object sender, RoutedEventArgs e)
		{
			var resourcesTreeSearchView = (ResourcesTreeSearchView) e.Source;

			var resOC = resourcesTreeSearchView.SelectedResources.ToObservableCollection();
			foreach (var res in resOC.Where(res => !SelectedResources.Contains(res)))
				SelectedResources.Add(res);

			SelectedResources = SelectedResources.Except(SelectedResources.Where(sr => !resOC.Contains(sr)).ToList()).ToObservableCollection();

			OnPropertyChanged("CountSelectedResources");
		}

		private void MultiEmployeeSearch_OnSelectionChanged(object sender, RoutedEventArgs e)
		{
			var multiEmployeeSearch = (MultiEmployeeSearch)e.Source;

			var empOC = multiEmployeeSearch.SelectedEmployees.ToObservableCollection();
			foreach (var emp in empOC.Where(emp => !SelectedEmployees.Any(se => se.Employee.Equals(emp))))
				SelectedEmployees.Add(new Employee2SchedulerAppointmentDC { Employee = emp, ParticipationAnswer = ParticipationAnswer.Offen });

			var ex = SelectedEmployees.Where(se => !empOC.Contains(se.Employee));
			var ab = SelectedEmployees.Except(ex);
			var cd = ab.ToObservableCollection();
			SelectedEmployees = cd;

			OnPropertyChanged("CountSelectedEmployees");
		}

		private void MultiCustomerSearch_OnSelectionChanged(object sender, RoutedEventArgs e)
		{
			var multiCustomerSearchView = (MultiCustomerSearchView)e.Source;
			SelectedCustomers = multiCustomerSearchView.SelectedCustomers.ToObservableCollection();

			OnPropertyChanged("CountSelectedCustomers");
		}
	}
	
	public class NewSchedulerAppointmentFormController : AppointmentFormController
	{
		List<ResourceDC> SourceResourceList
		{
			get { return (List<ResourceDC>)SourceAppointment.CustomFields["ResourceList"]; }
			set { SourceAppointment.CustomFields["ResourceList"] = value; }
		}
		public List<ResourceDC> ResourceList
		{
			get { return (List<ResourceDC>)EditedAppointmentCopy.CustomFields["ResourceList"]; }
			set { EditedAppointmentCopy.CustomFields["ResourceList"] = value; }
		}

		List<Employee2SchedulerAppointmentDC> SourceEmployeeList
		{
			get { return (List<Employee2SchedulerAppointmentDC>)SourceAppointment.CustomFields["EmployeeList"]; }
			set { SourceAppointment.CustomFields["EmployeeList"] = value; }
		}
		public List<Employee2SchedulerAppointmentDC> EmployeeList
		{
			get { return (List<Employee2SchedulerAppointmentDC>)EditedAppointmentCopy.CustomFields["EmployeeList"]; }
			set { EditedAppointmentCopy.CustomFields["EmployeeList"] = value; }
		}

		List<CompactCustomerDC> SourceCustomerList
		{
			get { return (List<CompactCustomerDC>)SourceAppointment.CustomFields["CustomerList"]; }
			set { SourceAppointment.CustomFields["CustomerList"] = value; }
		}
		public List<CompactCustomerDC> CustomerList
		{
			get { return (List<CompactCustomerDC>)EditedAppointmentCopy.CustomFields["CustomerList"]; }
			set { EditedAppointmentCopy.CustomFields["CustomerList"] = value; }
		}

		CompactEmployeeDC SourceOriginator
		{
			get { return (CompactEmployeeDC)SourceAppointment.CustomFields["Originator"]; }
			set { SourceAppointment.CustomFields["Originator"] = value; }
		}
		public CompactEmployeeDC Originator
		{
			get { return (CompactEmployeeDC)EditedAppointmentCopy.CustomFields["Originator"]; }
			set { EditedAppointmentCopy.CustomFields["Originator"] = value; }
		}

		bool SourceIsPrivate
		{
			get { return (bool)SourceAppointment.CustomFields["IsPrivate"]; }
			set { SourceAppointment.CustomFields["IsPrivate"] = value; }
		}
		public bool IsPrivate
		{
			get { return (bool)EditedAppointmentCopy.CustomFields["IsPrivate"]; }
			set { EditedAppointmentCopy.CustomFields["IsPrivate"] = value; }
		}

		public override bool IsAppointmentChanged()
		{
			if (base.IsAppointmentChanged())
				return true;

			if (SourceResourceList != null && ResourceList != null ||
				SourceEmployeeList != null && EmployeeList != null ||
				SourceCustomerList != null && CustomerList != null ||
				SourceOriginator != null && Originator != null)
				return false;

			var resourceListsAreEqual = SourceResourceList == null || ResourceList == null || !Equals(SourceResourceList, ResourceList);
			var employeeListsAreEqual = SourceEmployeeList == null || EmployeeList == null || !Equals(SourceEmployeeList, EmployeeList);
			var customerListsAreEqual = SourceCustomerList == null || CustomerList == null || !Equals(SourceCustomerList, CustomerList);
			var originatorsAreEqual = SourceOriginator == null || Originator == null || !Equals(SourceOriginator, Originator);
			var isPrivatesAreEqual = !Equals(SourceIsPrivate, IsPrivate);

			return resourceListsAreEqual || employeeListsAreEqual || customerListsAreEqual || originatorsAreEqual || isPrivatesAreEqual;
		}

		public NewSchedulerAppointmentFormController(SchedulerControl control, Appointment apt) : base(control, apt) { }

		protected override void ApplyCustomFieldsValues()
		{
			SourceResourceList = ResourceList;
			SourceEmployeeList = EmployeeList;
			SourceCustomerList = CustomerList;
			SourceOriginator = Originator;
			SourceIsPrivate = IsPrivate;
		}
	}
}
