using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Telerik.Web.UI;

namespace Telerik.Web.Examples.Scheduler.AdvancedFormTemplate
{
	public partial class SchedulerDefaultForm : UserControl
	{
		#region Private members

		private static readonly string[] DayOrdinalValues = { "1", "2", "3", "4", "-1" };

		private static readonly string[] DayMaskValues = { 
            ((int) RecurrenceDay.EveryDay).ToString(),
            ((int) RecurrenceDay.WeekDays).ToString(),
            ((int) RecurrenceDay.WeekendDays).ToString(),
            ((int) RecurrenceDay.Sunday).ToString(),
            ((int) RecurrenceDay.Monday).ToString(),
            ((int) RecurrenceDay.Tuesday).ToString(),
            ((int) RecurrenceDay.Wednesday).ToString(),
            ((int) RecurrenceDay.Thursday).ToString(),
            ((int) RecurrenceDay.Friday).ToString(),
            ((int) RecurrenceDay.Saturday).ToString() };

		private string[] DayOrdinalDescriptions;

		private string[] DayMaskDescriptions;

		#endregion


		#region Protected properties

		protected RadScheduler Owner
		{
			get
			{
				return Appointment.Owner;
			}
		}

		protected Appointment Appointment
		{
			get
			{
				SchedulerFormContainer container = (SchedulerFormContainer) BindingContainer;
				return container.Appointment;
			}
		}

		protected RecurrenceFrequency Frequency
		{
			get
			{
				if (RecurrentAppointment != null && RecurrentAppointment.Checked)
				{
					if (RepeatFrequencyHourly != null && RepeatFrequencyHourly.Checked)
					{
						return RecurrenceFrequency.Hourly;
					}

					if (RepeatFrequencyDaily != null && RepeatFrequencyDaily.Checked)
					{
						return RecurrenceFrequency.Daily;
					}

					if (RepeatFrequencyWeekly != null && RepeatFrequencyWeekly.Checked)
					{
						return RecurrenceFrequency.Weekly;
					}

					if (RepeatFrequencyMonthly != null && RepeatFrequencyMonthly.Checked)
					{
						return RecurrenceFrequency.Monthly;
					}

					if (RepeatFrequencyYearly != null && RepeatFrequencyYearly.Checked)
					{
						return RecurrenceFrequency.Yearly;
					}
				}

				return RecurrenceFrequency.None;
			}
		}

		protected int Interval
		{
			get
			{
				switch (Frequency)
				{
					case RecurrenceFrequency.Hourly:
						return int.Parse(HourlyRepeatInterval.Text);

					case RecurrenceFrequency.Daily:
						if (RepeatEveryNthDay.Checked)
						{
							return int.Parse(DailyRepeatInterval.Text);
						}
						break;

					case RecurrenceFrequency.Weekly:
						return int.Parse(WeeklyRepeatInterval.Text);

					case RecurrenceFrequency.Monthly:
						if (RepeatEveryNthMonthOnDate.Checked)
						{
							return int.Parse(MonthlyRepeatIntervalForDate.Text);
						}
						else
						{
							return int.Parse(MonthlyRepeatIntervalForGivenDay.Text);
						}
				}

				return 0;
			}
		}

		protected RecurrenceDay DaysOfWeekMask
		{
			get
			{
				switch (Frequency)
				{
					case RecurrenceFrequency.Daily:
						return (RepeatEveryWeekday.Checked) ? RecurrenceDay.WeekDays : RecurrenceDay.EveryDay;

					case RecurrenceFrequency.Weekly:
						RecurrenceDay finalMask = RecurrenceDay.None;
						finalMask |= WeeklyWeekDayMonday.Checked ? RecurrenceDay.Monday : finalMask;
						finalMask |= WeeklyWeekDayTuesday.Checked ? RecurrenceDay.Tuesday : finalMask;
						finalMask |= WeeklyWeekDayWednesday.Checked ? RecurrenceDay.Wednesday : finalMask;
						finalMask |= WeeklyWeekDayThursday.Checked ? RecurrenceDay.Thursday : finalMask;
						finalMask |= WeeklyWeekDayFriday.Checked ? RecurrenceDay.Friday : finalMask;
						finalMask |= WeeklyWeekDaySaturday.Checked ? RecurrenceDay.Saturday : finalMask;
						finalMask |= WeeklyWeekDaySunday.Checked ? RecurrenceDay.Sunday : finalMask;

						return finalMask;

					case RecurrenceFrequency.Monthly:
						if (RepeatEveryNthMonthOnGivenDay.Checked)
						{
							return (RecurrenceDay) Enum.Parse(typeof(RecurrenceDay), MonthlyDayMaskDropDown.SelectedValue);
						}
						break;

					case RecurrenceFrequency.Yearly:
						if (RepeatEveryYearOnGivenDay.Checked)
						{
							return (RecurrenceDay) Enum.Parse(typeof(RecurrenceDay), YearlyDayMaskDropDown.SelectedValue);
						}
						break;
				}

				return RecurrenceDay.None;
			}
		}

		protected int DayOfMonth
		{
			get
			{
				switch (Frequency)
				{
					case RecurrenceFrequency.Monthly:
						return (RepeatEveryNthMonthOnDate.Checked ? int.Parse(MonthlyRepeatDate.Text) : 0);

					case RecurrenceFrequency.Yearly:
						return (RepeatEveryYearOnDate.Checked ? int.Parse(YearlyRepeatDate.Text) : 0);
				}

				return 0;
			}
		}

		protected int DayOrdinal
		{
			get
			{
				switch (Frequency)
				{
					case RecurrenceFrequency.Monthly:
						if (RepeatEveryNthMonthOnGivenDay.Checked)
						{
							return int.Parse(MonthlyDayOrdinalDropDown.SelectedValue);
						}
						break;

					case RecurrenceFrequency.Yearly:
						if (RepeatEveryYearOnGivenDay.Checked)
						{
							return int.Parse(YearlyDayOrdinalDropDown.SelectedValue);
						}
						break;
				}

				return 0;
			}
		}

		protected RecurrenceMonth Month
		{
			get
			{
				if (Frequency == RecurrenceFrequency.Yearly)
				{
					string selectedMonth;

					if (RepeatEveryYearOnDate.Checked)
					{
						selectedMonth = YearlyRepeatMonthForDate.SelectedValue;
					}
					else
					{
						selectedMonth = YearlyRepeatMonthForGivenDay.SelectedValue;
					}

					return (RecurrenceMonth) Enum.Parse(typeof(RecurrenceMonth), selectedMonth);
				}
				else
				{
					return RecurrenceMonth.None;
				}
			}
		}

		private RecurrencePattern Pattern
		{
			get
			{
				if (!RecurrentAppointment.Checked)
				{
					return null;
				}

				RecurrencePattern submittedPattern = new RecurrencePattern();
				submittedPattern.Frequency = Frequency;
				submittedPattern.Interval = Interval;
				submittedPattern.DaysOfWeekMask = DaysOfWeekMask;
				submittedPattern.DayOfMonth = DayOfMonth;
				submittedPattern.DayOrdinal = DayOrdinal;
				submittedPattern.Month = Month;

				if (submittedPattern.Frequency == RecurrenceFrequency.Weekly)
				{
					submittedPattern.FirstDayOfWeek = Owner.FirstDayOfWeek;
				}

				return submittedPattern;
			}
		}

		private RecurrenceRange Range
		{
			get
			{
				DateTime startDate = StartDate.SelectedDate.Value.Date;
				DateTime endDate = EndDate.SelectedDate.Value.Date;

				if (AllDayEvent.Checked)
				{
					startDate = startDate.Date;

					if (!IsAllDayAppointment(Appointment))
					{
						// This correction is only needed if the appointment was not all-day already.
						endDate = endDate.Date.AddDays(1);
					}
				}
				else
				{
					TimeSpan startTime;
					startTime = StartTime.SelectedDate.Value.TimeOfDay;
					startDate = startDate.Add(startTime);

					TimeSpan endTime;
					endTime = EndTime.SelectedDate.Value.TimeOfDay;
					endDate = endDate.Add(endTime);
				}

				startDate = Owner.DisplayToUtc(startDate);
				endDate = Owner.DisplayToUtc(endDate);

				if (endDate < startDate)
				{
					throw new InvalidOperationException("Start time must be before the End time.");
				}

				RecurrenceRange range = new RecurrenceRange();
				range.Start = startDate;
				range.EventDuration = endDate - startDate;
				range.MaxOccurrences = 0;
				range.RecursUntil = DateTime.MaxValue;

				if (Owner.RecurrenceSupport)
				{
					if (RepeatGivenOccurrences.Checked)
					{
						int maxOccurrences;
						int.TryParse(RangeOccurrences.Text, out maxOccurrences);
						range.MaxOccurrences = maxOccurrences;
					}

					if (RepeatUntilGivenDate.Checked && RangeEndDate.SelectedDate.HasValue)
					{
						range.RecursUntil = Owner.DisplayToUtc(RangeEndDate.SelectedDate.Value);

						if (!AllDayEvent.Checked)
						{
							range.RecursUntil = range.RecursUntil.AddDays(1);
						}
					}
				}

				return range;
			}
		}

		#endregion


		#region Public properties

		[Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
		public string Subject
		{
			get
			{
				return SubjectText.Text;
			}

			set
			{
				SubjectText.Text = value;
			}
		}

		[Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
		public string Description
		{
			get
			{
				return DescriptionText.Text;
			}

			set
			{
				DescriptionText.Text = value;
			}
		}

		[Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
		public DateTime Start
		{
			get
			{
				DateTime start = StartDate.SelectedDate.Value.Date;
				start = start.Add(StartTime.SelectedDate.Value.TimeOfDay);

				return Owner.DisplayToUtc(start);
			}

			set
			{
				StartDate.SelectedDate = Owner.UtcToDisplay(value);
				StartTime.SelectedDate = Owner.UtcToDisplay(value);
			}
		}

		[Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
		public DateTime End
		{
			get
			{
				DateTime end = EndDate.SelectedDate.Value.Date;
				end = end.Add(EndTime.SelectedDate.Value.TimeOfDay);

				return Owner.DisplayToUtc(end);
			}

			set
			{
				EndDate.SelectedDate = Owner.UtcToDisplay(value);
				EndTime.SelectedDate = Owner.UtcToDisplay(value);
			}
		}

		[Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
		public string RecurrenceRuleText
		{
			get
			{
				if (Owner.RecurrenceSupport)
				{
					RecurrenceRule rrule = RecurrenceRule.FromPatternAndRange(Pattern, Range);

					if (rrule == null)
					{
						return string.Empty;
					}

					RecurrenceRule originalRule;
					if (RecurrenceRule.TryParse(OriginalRecurrenceRule.Value, out originalRule))
					{
						rrule.Exceptions = originalRule.Exceptions;
					}

					return rrule.ToString();
				}

				return string.Empty;
			}

			set
			{
				OriginalRecurrenceRule.Value = value;
			}
		}

		#endregion


		protected void Page_Load(object sender, EventArgs e)
		{
			PopulateDescriptions();
			InitializeMonthlyRecurrenceControls();
			InitializeYearlyRecurrenceControls();
			InitializeClientHandlers();
		}

		protected void BasicControlsPanel_DataBinding(object sender, EventArgs e)
		{
			if (IsAllDayAppointment(Appointment))
			{
				AllDayEvent.Checked = true;
				StartTime.Enabled = false;
				EndTime.Enabled = false;
			}
			else
			{
				AllDayEvent.Checked = false;
				StartTime.Enabled = true;
				EndTime.Enabled = true;
			}
		}

		protected void RecurrencePatternPanel_DataBinding(object sender, EventArgs e)
		{
			RecurrenceRule rrule;
			if (!RecurrenceRule.TryParse(OriginalRecurrenceRule.Value, out rrule))
			{
				RecurrentAppointment.Checked = false;
				HideControl(ResetExceptionsPanel);
				HideControl(RecurrencePatternPanel);
				return;
			}

			RecurrentAppointment.Checked = true;
			ShowControl(ResetExceptionsPanel);
			ShowControl(RecurrencePatternPanel);

			string interval = rrule.Pattern.Interval.ToString();
			int mask = (int) rrule.Pattern.DaysOfWeekMask;

			switch (rrule.Pattern.Frequency)
			{
				case RecurrenceFrequency.Hourly:
					RepeatFrequencyHourly.Checked = true;
					ShowControl(RecurrencePatternHourlyPanel);
					HourlyRepeatInterval.Text = interval;
					break;

				case RecurrenceFrequency.Daily:
					RepeatFrequencyDaily.Checked = true;
					ShowControl(RecurrencePatternDailyPanel);

					if (rrule.Pattern.DaysOfWeekMask == RecurrenceDay.WeekDays)
					{
						RepeatEveryWeekday.Checked = true;
						RepeatEveryNthDay.Checked = false;
					}
					else
					{
						RepeatEveryWeekday.Checked = false;
						RepeatEveryNthDay.Checked = true;
						DailyRepeatInterval.Text = interval;
					}
					break;

				case RecurrenceFrequency.Weekly:
					RepeatFrequencyWeekly.Checked = true;
					ShowControl(RecurrencePatternWeeklyPanel);

					WeeklyRepeatInterval.Text = interval;

					WeeklyWeekDayMonday.Checked = (RecurrenceDay.Monday & rrule.Pattern.DaysOfWeekMask) == RecurrenceDay.Monday;
					WeeklyWeekDayTuesday.Checked = (RecurrenceDay.Tuesday & rrule.Pattern.DaysOfWeekMask) == RecurrenceDay.Tuesday;
					WeeklyWeekDayWednesday.Checked = (RecurrenceDay.Wednesday & rrule.Pattern.DaysOfWeekMask) == RecurrenceDay.Wednesday;
					WeeklyWeekDayThursday.Checked = (RecurrenceDay.Thursday & rrule.Pattern.DaysOfWeekMask) == RecurrenceDay.Thursday;
					WeeklyWeekDayFriday.Checked = (RecurrenceDay.Friday & rrule.Pattern.DaysOfWeekMask) == RecurrenceDay.Friday;
					WeeklyWeekDaySaturday.Checked = (RecurrenceDay.Saturday & rrule.Pattern.DaysOfWeekMask) == RecurrenceDay.Saturday;
					WeeklyWeekDaySunday.Checked = (RecurrenceDay.Sunday & rrule.Pattern.DaysOfWeekMask) == RecurrenceDay.Sunday;
					break;

				case RecurrenceFrequency.Monthly:
					RepeatFrequencyMonthly.Checked = true;
					ShowControl(RecurrencePatternMonthlyPanel);

					if (0 < rrule.Pattern.DayOfMonth)
					{
						RepeatEveryNthMonthOnDate.Checked = true;
						RepeatEveryNthMonthOnGivenDay.Checked = false;
						MonthlyRepeatDate.Text = rrule.Pattern.DayOfMonth.ToString();
						MonthlyRepeatIntervalForDate.Text = interval;
					}
					else
					{
						RepeatEveryNthMonthOnDate.Checked = false;
						RepeatEveryNthMonthOnGivenDay.Checked = true;
						MonthlyDayOrdinalDropDown.SelectedValue = rrule.Pattern.DayOrdinal.ToString();
						MonthlyDayMaskDropDown.SelectedIndex = Array.IndexOf(DayMaskValues, (mask).ToString());
						MonthlyRepeatIntervalForGivenDay.Text = interval;
					}
					break;

				case RecurrenceFrequency.Yearly:
					RepeatFrequencyYearly.Checked = true;
					ShowControl(RecurrencePatternYearlyPanel);

					if (0 < rrule.Pattern.DayOfMonth)
					{
						RepeatEveryYearOnDate.Checked = true;
						RepeatEveryYearOnGivenDay.Checked = false;
						YearlyRepeatDate.Text = rrule.Pattern.DayOfMonth.ToString();
						YearlyRepeatMonthForDate.SelectedIndex = ((int) rrule.Pattern.Month) - 1;
					}
					else
					{
						RepeatEveryYearOnDate.Checked = false;
						RepeatEveryYearOnGivenDay.Checked = true;
						YearlyDayOrdinalDropDown.SelectedValue = rrule.Pattern.DayOrdinal.ToString();
						YearlyDayMaskDropDown.SelectedIndex = Array.IndexOf(DayMaskValues, (mask).ToString());
						YearlyRepeatMonthForGivenDay.SelectedIndex = ((int) rrule.Pattern.Month) - 1;
					}
					break;
			}
		}

		protected void RecurrenceRangePanel_DataBinding(object sender, EventArgs e)
		{
			RecurrenceRule rrule;
			if (!RecurrenceRule.TryParse(OriginalRecurrenceRule.Value, out rrule))
			{
				HideControl(RecurrenceRangePanel);
				return;
			}

			ShowControl(RecurrenceRangePanel);

			bool occurrencesLimit = (rrule.Range.MaxOccurrences != int.MaxValue);
			bool timeLimit = (rrule.Range.RecursUntil != DateTime.MaxValue);

			if (!occurrencesLimit && !timeLimit)
			{
				RepeatIndefinitely.Checked = true;
				RepeatGivenOccurrences.Checked = false;
				RepeatUntilGivenDate.Checked = false;
			}
			else
				if (occurrencesLimit)
				{
					RepeatIndefinitely.Checked = false;
					RepeatGivenOccurrences.Checked = true;
					RepeatUntilGivenDate.Checked = false;

					RangeOccurrences.Text = rrule.Range.MaxOccurrences.ToString();
				}
				else
				{
					RepeatIndefinitely.Checked = false;
					RepeatGivenOccurrences.Checked = false;
					RepeatUntilGivenDate.Checked = true;

					RangeEndDate.SelectedDate = Owner.UtcToDisplay(rrule.Range.RecursUntil).AddDays(-1);
				}
		}


		private void PopulateDescriptions()
		{
			DayOrdinalDescriptions = new string[5];
			DayOrdinalDescriptions[0] = Owner.Localization.AdvancedFirst;
			DayOrdinalDescriptions[1] = Owner.Localization.AdvancedSecond;
			DayOrdinalDescriptions[2] = Owner.Localization.AdvancedThird;
			DayOrdinalDescriptions[3] = Owner.Localization.AdvancedFourth;
			DayOrdinalDescriptions[4] = Owner.Localization.AdvancedLast;

			DayMaskDescriptions = new string[10];
			DayMaskDescriptions[0] = Owner.Localization.AdvancedMaskDay;
			DayMaskDescriptions[1] = Owner.Localization.AdvancedMaskWeekday;
			DayMaskDescriptions[2] = Owner.Localization.AdvancedMaskWeekendDay;
			Array.Copy(Owner.Culture.DateTimeFormat.DayNames, 0, DayMaskDescriptions, 3, 7);
		}

		private void InitializeMonthlyRecurrenceControls()
		{
			MonthlyDayOrdinalDropDown.Items.AddRange(CreateListItemArray(DayOrdinalDescriptions, DayOrdinalValues));
			MonthlyDayMaskDropDown.Items.AddRange(CreateListItemArray(DayMaskDescriptions, DayMaskValues));
		}

		private void InitializeYearlyRecurrenceControls()
		{
			string[] monthNames = new string[12];
			Array.Copy(Owner.Culture.DateTimeFormat.MonthNames, monthNames, 12);

			string[] invariantMonthNames = new string[12];
			Array.Copy(Enum.GetNames(typeof(RecurrenceMonth)), 1, invariantMonthNames, 0, 12);

			YearlyRepeatMonthForDate.Items.AddRange(CreateListItemArray(monthNames, invariantMonthNames));

			YearlyDayOrdinalDropDown.Items.AddRange(CreateListItemArray(DayOrdinalDescriptions, DayOrdinalValues));
			YearlyDayMaskDropDown.Items.AddRange(CreateListItemArray(DayMaskDescriptions, DayMaskValues));

			YearlyRepeatMonthForGivenDay.Items.AddRange(CreateListItemArray(monthNames, invariantMonthNames));
		}

		private void InitializeClientHandlers()
		{
			RecurrentAppointment.Attributes["onclick"] = Owner.ClientID + "_onRecurrentAppointmentClicked(this);";

			AllDayEvent.Attributes["onclick"] = Owner.ClientID + "_onAllDayEventClicked(this);";

			RepeatFrequencyHourly.Attributes["onclick"] = Owner.ClientID + "_onRecurrenceFrequencyClicked(this);";
			RepeatFrequencyDaily.Attributes["onclick"] = Owner.ClientID + "_onRecurrenceFrequencyClicked(this);";
			RepeatFrequencyWeekly.Attributes["onclick"] = Owner.ClientID + "_onRecurrenceFrequencyClicked(this);";
			RepeatFrequencyMonthly.Attributes["onclick"] = Owner.ClientID + "_onRecurrenceFrequencyClicked(this);";
			RepeatFrequencyYearly.Attributes["onclick"] = Owner.ClientID + "_onRecurrenceFrequencyClicked(this);";

			GlueControlWithRadio(DailyRepeatInterval, RepeatEveryNthDay, true);

			GlueControlWithRadio(MonthlyRepeatDate, RepeatEveryNthMonthOnDate, true);
			GlueControlWithRadio(MonthlyRepeatIntervalForDate, RepeatEveryNthMonthOnDate, false);

			GlueControlWithRadio(MonthlyDayOrdinalDropDown, RepeatEveryNthMonthOnGivenDay, true);
			GlueControlWithRadio(MonthlyDayMaskDropDown, RepeatEveryNthMonthOnGivenDay, false);
			GlueControlWithRadio(MonthlyRepeatIntervalForGivenDay, RepeatEveryNthMonthOnGivenDay, false);

			GlueControlWithRadio(YearlyRepeatMonthForDate, RepeatEveryYearOnDate, true);
			GlueControlWithRadio(YearlyRepeatDate, RepeatEveryYearOnDate, false);

			GlueControlWithRadio(YearlyDayOrdinalDropDown, RepeatEveryYearOnGivenDay, true);
			GlueControlWithRadio(YearlyDayMaskDropDown, RepeatEveryYearOnGivenDay, false);
			GlueControlWithRadio(YearlyRepeatMonthForGivenDay, RepeatEveryYearOnGivenDay, false);

			GlueControlWithRadio(RangeOccurrences, RepeatGivenOccurrences, true);

			GlueControlWithRadio(RangeEndDate.DateInput, RepeatUntilGivenDate, true);
		}

		private void GlueControlWithRadio(WebControl control, RadioButton radio, bool twoWay)
		{
			control.Attributes["onclick"] = string.Format("{0}_onGluedControlClick('{1}', '{2}');",
				Owner.ClientID, control.ClientID, radio.ClientID);

			if (twoWay)
			{
				radio.Attributes["onclick"] = string.Format("{0}_onGluedRadioClick('{1}', '{2}');",
					Owner.ClientID, control.ClientID, radio.ClientID);
			}
		}

		private static ListItem[] CreateListItemArray(string[] descriptions)
		{
			ListItem[] listItems = new ListItem[descriptions.Length];

			for (int i = 0; i < descriptions.Length; i++)
			{
				listItems[i] = new ListItem(descriptions[i]);
			}

			return listItems;
		}

		private static ListItem[] CreateListItemArray(string[] descriptions, string[] values)
		{
			if (descriptions.Length != values.Length)
			{
				throw new InvalidOperationException("There must be equal number of values and descriptions.");
			}

			ListItem[] listItems = CreateListItemArray(descriptions);

			for (int i = 0; i < values.Length; i++)
			{
				listItems[i].Value = values[i];
			}

			return listItems;
		}

		private static void HideControl(WebControl control)
		{
			control.Style[HtmlTextWriterStyle.Display] = "none";
		}

		private static void ShowControl(WebControl control)
		{
			ShowControl(control, true);
		}

		private static void ShowControl(WebControl control, bool block)
		{
			control.Style[HtmlTextWriterStyle.Display] = block ? "block" : "inline";
		}

		private bool IsAllDayAppointment(Appointment appointment)
		{
			DateTime displayStart = Owner.UtcToDisplay(appointment.Start);
			DateTime displayEnd = Owner.UtcToDisplay(appointment.End);
			return displayStart.CompareTo(displayStart.Date) == 0 && displayEnd.CompareTo(displayEnd.Date) == 0;
		}
	}
}