using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Web.UI;
using System.Web.UI.WebControls;

using BeWo.Data;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.ServiceImplementations;

using BS.Shared;

using NHibernate.Impl;

using ServiceDescription = BeWo.Data.Entities.ServiceDescription;

namespace Host
{
	public partial class ServiceRecordEditPage : Page
	{
		private List<UserRightType> rights;

		protected void Page_Load(object sender, EventArgs e)
		{
			var serviceRecord2Edit = (ServiceRecord) Session["ServiceRecord2Edit"];

			if (serviceRecord2Edit == null)
				return;

			try
			{
				if (!SessionFacade.IsUserLoggedIn())
					throw new SecurityException("Anmeldung erforderlich!");

				if (IsPostBack)
					return;
				
				Session["SelectedSupportConcept"] = serviceRecord2Edit.CostBearer2SupportConceptOid;

				var blk = DAOFactory.GenericDAO.GetByID<ServiceRecord>(serviceRecord2Edit.Oid.Value);
				Session["EintragsZiele"] = (List<ValueListEntry2Object>) blk.ValueList.ToList();

				var operationsService = new OperationsServiceImp();
				var serviceCategories = operationsService.GetAllServiceCategories();

				combo_serviceCategories.Items.AddRange(serviceCategories.Select(c => new ListItem(c.Name, c.ServiceCategoryOid.ToString())).ToArray());

				combo_serviceDescriptions.Items.AddRange(operationsService.GetAllServiceDescriptions()
					.Where(sd => sd.Category.ServiceCategoryOid.Equals(serviceCategories[0].ServiceCategoryOid))
					.Select(sd => new ListItem(sd.Name, sd.ServiceDescriptionOid.ToString())).ToArray());

				long? sdOid = serviceRecord2Edit.ServiceDescription.Oid;
				if (sdOid.HasValue)
				{
					var sdesc = DAOFactory.GenericDAO.GetByID<ServiceDescription>(sdOid.Value);

					long? cOid = sdesc.ServiceCategory.Oid;
					if (cOid.HasValue)
					{
						var cat = DAOFactory.GenericDAO.GetByID<ServiceCategory>(cOid.Value);
						ListItem catListItem = combo_serviceCategories.Items.FindByText(cat.Name);
						if (catListItem != null)
							combo_serviceCategories.SelectedIndex = combo_serviceCategories.Items.IndexOf(catListItem);
					}

					combo_serviceDescriptions.Items.Clear();
					combo_serviceDescriptions.Items.AddRange(operationsService.GetAllServiceDescriptions()
						.Where(sd => sd.Category.ServiceCategoryOid.ToString().Equals(combo_serviceCategories.SelectedValue))
						.Select(sd => new ListItem(sd.Name, sd.ServiceDescriptionOid.ToString())).ToArray());

					ListItem listItem = combo_serviceDescriptions.Items.FindByText(sdesc.Name);
					if (listItem != null)
						combo_serviceDescriptions.SelectedIndex = combo_serviceDescriptions.Items.IndexOf(listItem);
				}

				label_serviceRecord.Text = serviceRecord2Edit.Title;
				tb_date.Text = serviceRecord2Edit.Start.Value.ToShortDateString();
				tb_duration.Value = ((int) serviceRecord2Edit.DurationMinutes).ToString();
				tb_notice.Text = serviceRecord2Edit.Notice;
				tb_start.Value = string.Format("{0}{1}", serviceRecord2Edit.Start.Value.Hour.ToString("00"), serviceRecord2Edit.Start.Value.Minute.ToString("00"));
				tb_stop.Value = string.Format("{0}{1}", serviceRecord2Edit.End.Value.Hour.ToString("00"), serviceRecord2Edit.End.Value.Minute.ToString("00"));
			}
			catch (Exception ex)
			{
				lbl_error.Text = "Es ist leider ein Fehler aufgetreten: " + ex.Message;
			}
		}

		protected void combo_serviceCategories_SelectedIndexChanged(object sender, EventArgs e)
		{
			lbl_success.Text = string.Empty;
			var operationsService = new OperationsServiceImp();

			combo_serviceDescriptions.Items.Clear();
			combo_serviceDescriptions.Items.AddRange(operationsService.GetAllServiceDescriptions()
				.Where(sd => sd.Category.ServiceCategoryOid.ToString().Equals(combo_serviceCategories.SelectedValue))
				.Select(sd => new ListItem(sd.Name, sd.ServiceDescriptionOid.ToString())).ToArray());
		}

		protected void bt_save_Click(object sender, EventArgs e)
		{

			if (rights != null && !rights.Contains(UserRightType.ServiceRecordView_Edit)) return;

			decimal actualMinuteIntervall = Convert.ToDecimal(Session["actualMinuteIntervall"]);

			long? oid = ((ServiceRecord) Session["ServiceRecord2Edit"]).Oid;
			if (oid == null) return;
			var serviceRecord = DAOFactory.GenericDAO.GetByID<ServiceRecord>(oid.Value);

			long categoryId;
			long descriptionId;

			long.TryParse(combo_serviceCategories.SelectedItem.Value, out categoryId);
			long.TryParse(combo_serviceDescriptions.SelectedItem.Value, out descriptionId);

			var newServiceDescription = DAOFactory.GenericDAO.GetByID<ServiceDescription>(descriptionId);
			var newServiceCategory = DAOFactory.GenericDAO.GetByID<ServiceCategory>(categoryId);


			// Neue Werte
			int startHours, startMinutes, endHours, endMinutes, durationMinutes;
			DateTime datum;

			// Änderungen
			if (!DateTime.TryParse(tb_date.Text, out datum))
			{
				lbl_error.Text = "Bitte geben Sie ein gültiges Datum an";
				return;
			}

			bool startParsedSuccessfully = TryParseTime(tb_start.Value, out startHours, out startMinutes);
			bool endParsedSuccessfully = TryParseTime(tb_stop.Value, out endHours, out endMinutes);
			bool durationParsedSuccessfully = Int32.TryParse(tb_duration.Value, out durationMinutes);


			if (!durationParsedSuccessfully || durationMinutes == 0)
			{
				// keine Dauer angegeben... start & stop
				if (startParsedSuccessfully && endParsedSuccessfully)
				{
					DateTime start = datum.AddHours(startHours).AddMinutes(startMinutes);
					DateTime stop = datum.AddHours(endHours).AddMinutes(endMinutes);

					if (start > stop)
					{
						lbl_error.Text = "Die Startzeit muss vor der Endzeit liegen";
						return;
					}

					serviceRecord.Start = start;
					serviceRecord.End = stop;
					var duration = (int) (stop - start).TotalMinutes;
					if (actualMinuteIntervall > 0)
					{
						decimal roudedDuration = duration%actualMinuteIntervall != 0
							? duration + (actualMinuteIntervall - (duration%actualMinuteIntervall))
							: duration;

						serviceRecord.RoundedDuration = roudedDuration;
					}
					else
					{
						serviceRecord.RoundedDuration = duration;
					}
				}
				else
				{
					lbl_error.Text = "Bitte geben Sie eine gültige Dauer (in Minuten) oder Start- und Endzeit an (HH:MM oder HHMM).";
					return;
				}
			}
			else
			{
				// Dauer angegeben
				int istAlt = Convert.ToInt32(((ServiceRecord) Session["ServiceRecord2Edit"]).DurationMinutes);
				if (startParsedSuccessfully && endParsedSuccessfully)
				{
					DateTime start = datum.AddHours(startHours).AddMinutes(startMinutes);
					DateTime stop = datum.AddHours(endHours).AddMinutes(endMinutes);

					if (start >= stop)
					{
						lbl_error.Text = "Die Startzeit muss vor der Stopzeit liegen";
						return;
					}

					if (durationMinutes == istAlt)
						durationMinutes = (int) (stop - start).TotalMinutes;
				}

				if (actualMinuteIntervall > 0)
				{
					decimal roundedDuration = durationMinutes%actualMinuteIntervall != 0
						? durationMinutes + (actualMinuteIntervall - (durationMinutes%actualMinuteIntervall))
						: durationMinutes;

					serviceRecord.RoundedDuration = roundedDuration;
				}
				else
				{
					serviceRecord.RoundedDuration = durationMinutes;
				}

				if (startParsedSuccessfully && (startHours > 0 || startMinutes > 0))
				{
					// Dauer und Start angegeben
					serviceRecord.Start = datum.AddHours(startHours).AddMinutes(startMinutes);
				}
				else
				{
					// nur Dauer, kein Start angegeben
					serviceRecord.Start = datum.AddSeconds(1);
				}

				serviceRecord.End = serviceRecord.Start.Value.AddMinutes(durationMinutes);
			}

			serviceRecord.Notice = tb_notice.Text;

			if (!newServiceDescription.Equals(serviceRecord.ServiceDescription))
				serviceRecord.ServiceDescription = newServiceDescription;

			if (!newServiceCategory.Equals(serviceRecord.ServiceDescription.ServiceCategory))
				serviceRecord.ServiceDescription.ServiceCategory = newServiceCategory;

			var ak = (SessionImpl) Context.ApplicationInstance.Context.Items["hibernateSession"];
			ak.Evict(serviceRecord);
			
			try
			{
				DAOFactory.GenericDAO.Update(serviceRecord);
			}
			catch (Exception exception)
			{
				lbl_error.Text = string.Format("Es ist leider ein Fehler aufgetreten: {0}", exception.Message);
			}
			UpdateGUI(DAOFactory.GenericDAO.GetByID<ServiceRecord>(Convert.ToInt64(((ServiceRecord) Session["ServiceRecord2Edit"]).Oid)));

			lbl_success.Text = "Die &Auml;nderungen wurden erfolgreich gespeichert";

			Button1.Text = "Zurück";
		}

		protected void bt_cancel_Click(object sender, EventArgs e)
		{
			Response.Redirect("~/ServiceRecordPage.aspx?tenant=" + SessionFacade.Tenant);
		}

		private static bool TryParseTime(string text, out int hours, out int minutes)
		{
			try
			{
				String[] hnm = null;

				if (text.IndexOf(":") >= 0)
				{
					hnm = text.Split(':');
				}
				else
				{
					if (text.Length <= 2)
					{
						hnm = new[] {text, "00"};
					}
					else if (text.Length == 4)
					{
						hnm = new[] {text.Substring(0, 2), text.Substring(2)};
					}
					else if (text.Length == 3)
					{
						hnm = new[] {text.Substring(0, 1), text.Substring(1)};
					}
				}

				hours = int.Parse(hnm[0]);
				minutes = int.Parse(hnm[1]);

				return (hours >= 0 && hours <= 23) && (minutes >= 0 && minutes <= 59);
			}
			catch
			{
				hours = 0;
				minutes = 0;
				return false;
			}
		}

		private void UpdateGUI(ServiceRecord record)
		{
			tb_duration.Value = record.DurationMinutes.ToString();
			tb_start.Value = record.Start.Value.ToString("t");
			tb_stop.Value = record.End.Value.ToString("t");
		}
	}
}