using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using System.Text.RegularExpressions;

namespace OPlanner {

	public partial class CoursesPanel : UserControl {

		public CoursesPanel() {
			InitializeComponent();
			ClearCoursesCombo();
		}

		private OCurrentInfo info;

		public void SetInfo(OCurrentInfo newInfo) {
			info = newInfo;
			info.DataLoaded += new BasicEventHandler(DataLoadedHandler);
			info.ObjectsSelected += new SenderEventHandler(ObjectsSelectedHandler);
			info.ObjectsDeselected += new SenderEventHandler(ObjectsSelectedHandler);
			info.ObjectsCreated += new SenderEventHandler(ObjectsCreatedHandler);
			info.ObjectsDeleted += new SenderEventHandler(ObjectsCreatedHandler);
			info.CourseSelected += new SenderEventHandler(UpdateCoursesHandler);
			info.CourseCreated += new SenderEventHandler(UpdateCoursesHandler);
			info.CourseDeleted += new SenderEventHandler(UpdateCoursesHandler);
			info.ObjectsUpdated += new UpdateEventHandler(UpdateInfoHandler);
			info.MapUpdated += new SenderEventHandler(MapUpdatedHandler);
		}

		private void DataLoadedHandler() {
			LoadData();
		}

		private void ObjectsSelectedHandler(object sender) {
			UpdateSelectedObjects();
		}

		private void ObjectsCreatedHandler(object sender) {
			UpdateCourseObjects(info.SelectedCourse);
			UpdateCourseInfo();
		}

		private void MapUpdatedHandler(object sender) {
			UpdateCourseInfo();
		}

		private void UpdateInfoHandler(object sender, UpdateType updateType, List<OBaseObject> objects, bool updatePropertiesPanel) {
			if (updatePropertiesPanel == false) {
				return;
			}
			if (updateType == UpdateType.Code || updateType == UpdateType.Description) {
				UpdateCourseObjects(info.SelectedCourse);
			}
			UpdateCourseInfo();
		}

		private void UpdateCoursesHandler(object sender) {
			Update();
		}

		private void LoadData() {
			Clear();
			if (info.CourseViewType == CourseViewType.Preview) {
				previewCheckBox.IsChecked = true;
			} else {
				previewCheckBox.IsChecked = false;
			}
			if (info.Data == null) {
				return;
			}
			Update();
		}

		private void Update() {
			UpdateCourses();
			UpdateCourseObjects(info.SelectedCourse);
			UpdateCourseInfo();
		}

		private void UpdateCourseInfo() {
			if (info.SelectedCourse != null) {
				lengthLabel.Content = "Length: " + Convert.ToString(info.SelectedCourse.GetLength()) + " km";
				climbLabel.Content = "Climb: " + info.SelectedCourse.Climb.ToString() + " m";
			} else {
				lengthLabel.Content = "Length: 0 km";
				climbLabel.Content = "Climb: 0 m";
			}
		}

		private void coursesCombo_SelectionChanged(object sender, SelectionChangedEventArgs e) {
			if (coursesCombo.SelectedIndex <= 0) {
				info.SelectedCourse = null;
			} else {
				info.SelectedCourse = (Course)(((CustomComboBoxItem)coursesCombo.SelectedItem).ObjectData);
			}
			info.SelectedObjects.Clear();
			info.InvokeObjectsDeselected(this);
			info.InvokeCourseSelected(this);
		}

		private void ClearCoursesCombo() {
			coursesCombo.SelectionChanged -= new SelectionChangedEventHandler(coursesCombo_SelectionChanged);
			coursesCombo.Items.Clear();
			coursesCombo.Items.Add(new CustomComboBoxItem("All Controls", null));
			coursesCombo.SelectedIndex = 0;
			coursesCombo.SelectionChanged += new SelectionChangedEventHandler(coursesCombo_SelectionChanged);
		}

		private void UpdateCourses() {
			ClearCoursesCombo();
			coursesCombo.SelectionChanged -= new SelectionChangedEventHandler(coursesCombo_SelectionChanged);
			List<Course> courses = info.Data.Courses;
			for (int i = 0; i < courses.Count; i++) {
				coursesCombo.Items.Add(new CustomComboBoxItem(courses[i].Name, courses[i]));
				if (courses[i] == info.SelectedCourse) {
					coursesCombo.SelectedIndex = i+1;
				}
			}
			coursesCombo.SelectionChanged += new SelectionChangedEventHandler(coursesCombo_SelectionChanged);
		}

		private void ClearCourseObjects() {
			orderedObjectsBox.SelectionChanged -= new SelectionChangedEventHandler(objectsBox_SelectionChanged);
			orderedObjectsBox.Items.Clear();
			orderedObjectsBox.SelectedIndex = -1;
			orderedObjectsBox.SelectionChanged += new SelectionChangedEventHandler(objectsBox_SelectionChanged);
			fixedObjectsBox.SelectionChanged -= new SelectionChangedEventHandler(objectsBox_SelectionChanged);
			fixedObjectsBox.Items.Clear();
			fixedObjectsBox.SelectedIndex = -1;
			fixedObjectsBox.SelectionChanged += new SelectionChangedEventHandler(objectsBox_SelectionChanged);
		}

		private void UpdateCourseObjects(Course course) {
			ClearCourseObjects();
			if (course == null) {
				return;
			}
			for (int i = 0; i < course.OrderedObjects.Count; i++) {
				orderedObjectsBox.Items.Add(new CustomListBoxItem(course.OrderedObjects[i].GetRepresentation(), course.OrderedObjects[i]));
			}
			for (int i = 0; i < course.FixedObjects.Count; i++) {
				fixedObjectsBox.Items.Add(new CustomListBoxItem(course.FixedObjects[i].GetRepresentation(), course.FixedObjects[i]));
			}
			UpdateSelectedObjects();
		}

		private void UpdateSelectedObjects() {
			orderedObjectsBox.SelectionChanged -= new SelectionChangedEventHandler(objectsBox_SelectionChanged);
			orderedObjectsBox.SelectedItems.Clear();
			for (int i = 0; i < info.SelectedObjects.Count; i++) {
				for (int j = 0; j < orderedObjectsBox.Items.Count; j++) {
					OBaseObject obj = (OBaseObject)((CustomListBoxItem)orderedObjectsBox.Items[j]).ObjectData;
					if (obj.MatchesObject(info.SelectedObjects[i])) {
						orderedObjectsBox.SelectedItems.Add(orderedObjectsBox.Items[j]);
					}
				}
			}
			orderedObjectsBox.SelectionChanged += new SelectionChangedEventHandler(objectsBox_SelectionChanged);
			fixedObjectsBox.SelectionChanged -= new SelectionChangedEventHandler(objectsBox_SelectionChanged);
			fixedObjectsBox.SelectedItems.Clear();
			for (int i = 0; i < info.SelectedObjects.Count; i++) {
				for (int j = 0; j < fixedObjectsBox.Items.Count; j++) {
					OBaseObject obj = (OBaseObject)((CustomListBoxItem)fixedObjectsBox.Items[j]).ObjectData;
					if (obj.MatchesObject(info.SelectedObjects[i])) {
						fixedObjectsBox.SelectedItems.Add(fixedObjectsBox.Items[j]);
					}
				}
			}
			fixedObjectsBox.SelectionChanged += new SelectionChangedEventHandler(objectsBox_SelectionChanged);
		}

		private void RemoveObjects(List<OBaseObject> objects) {
			if (objects.Count == 0) {
				return;
			}
			info.SelectedObjects.Clear();
			info.InvokeObjectsDeselected(this);
			info.InvokeDataChanging(this, "Delete Objects");
			info.Data.RemoveObjects(objects);
			info.InvokeDataChanged(this, "Delete Objects");
			info.InvokeObjectsDeleted(this);
		}

		private List<OBaseObject> GetSelectedObjects(ListBox listBox) {
			List<OBaseObject> list = new List<OBaseObject>();
			IList objects;
			objects = listBox.SelectedItems;
			for (int i = 0; i < objects.Count; i++) {
				OBaseObject obj = (OBaseObject)((CustomListBoxItem)objects[i]).ObjectData;
				if (obj != null) {
					list.Add(obj);
				}
			}
			return list;
		}

		private List<OBaseObject> GetSelectedObjects() {
			List<OBaseObject> list = new List<OBaseObject>();
			list.AddRange(GetSelectedObjects(orderedObjectsBox));
			list.AddRange(GetSelectedObjects(fixedObjectsBox));
			return list;
		}

		private void Clear() {
			ClearCoursesCombo();
			ClearCourseObjects();
		}

		private void newButton_Click(object sender, RoutedEventArgs e) {
			if (info.Data == null) {
				return;
			}
			CourseProperties wnd = new CourseProperties();
			wnd.Owner = App.Current.MainWindow;
			wnd.SetInfo(info);
			wnd.SetCourse(null);
			wnd.ShowDialog();
			Course course = wnd.GetCourse();
			if (course != null) {
				info.SelectedCourse = course;
				info.InvokeCourseSelected(this);
			}
		}

		private void previewCheckBox_Checked(object sender, RoutedEventArgs e) {
			info.CourseViewType = CourseViewType.Preview;
			info.InvokeCourseViewModeChanged(this);
		}

		private void previewCheckBox_Unchecked(object sender, RoutedEventArgs e) {
			info.CourseViewType = CourseViewType.Outline;
			info.InvokeCourseViewModeChanged(this);
		}

		private void objectsBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
			info.SelectedObjects = GetSelectedObjects((ListBox)sender);
			info.InvokeObjectsSelected(this);
		}

		private void fixedObjectsBox_KeyDown(object sender, KeyEventArgs e) {
			if (e.Key == Key.Delete) {
				RemoveObjects(GetSelectedObjects(fixedObjectsBox));
			}
		}

		private void orderedObjectsBox_KeyDown(object sender, KeyEventArgs e) {
			if (e.Key == Key.Delete) {
				RemoveObjects(GetSelectedObjects(orderedObjectsBox));
			}
		}

		private void removeFixedButton_Click(object sender, RoutedEventArgs e) {
			RemoveObjects(GetSelectedObjects(fixedObjectsBox));
		}

		private void removeOrderedButton_Click(object sender, RoutedEventArgs e) {
			RemoveObjects(GetSelectedObjects(orderedObjectsBox));
		}

		private void orderedObjectsBox_CustomDropPreview(DragListBox sender, CustomDragData dragData) {
			if (info.SelectedCourse == null) {
				return;
			}
			if (dragData.InsertIndex == -1 || dragData.DropAction == CustomDropAction.None) {
				UpdateCourseObjects(info.SelectedCourse);
				return;
			}
			if (dragData.InsertIndex > dragData.OldInsertIndex && dragData.OldInsertIndex != -1) {
				dragData.InsertIndex--;
			}
			if (dragData.InsertIndex == dragData.OldInsertIndex) {
				return;
			}
			CustomListBoxItem itemSource = dragData.ItemSource as CustomListBoxItem;
			if (itemSource == null) {
				return;
			}
			OBaseObject objectSource = itemSource.ObjectData as OBaseObject;
			if (objectSource == null) {
				return;
			}
			Course course = info.SelectedCourse.Clone(info.Data);
			OBaseObject dummyObject;
			if (objectSource.Parent == info.SelectedCourse) {
				dummyObject = course.GetObjectByCode(objectSource.ObjectCode);
				if (dummyObject == null) {
					return;
				}
				course.RemoveObject(dummyObject);
			} else {
				dummyObject = course.GetObjectRef(objectSource);
			}
			if (dragData.InsertIndex > course.OrderedObjects.Count) {
				dragData.InsertIndex = course.OrderedObjects.Count;
			}
			course.InsertOrderedObject(dragData.InsertIndex, dummyObject);
			UpdateCourseObjects(course);
			if (orderedObjectsBox.Items.Count <= dragData.InsertIndex) {
				orderedObjectsBox.SelectedIndex = -1;
				return;
			}
			orderedObjectsBox.SelectedIndex = dragData.InsertIndex;
			((CustomListBoxItem)orderedObjectsBox.Items[dragData.InsertIndex]).Opacity = 0.5;
		}

		private void orderedObjectsBox_CustomDrop(DragListBox sender, CustomDragData dragData) {
			if (info.SelectedCourse == null) {
				return;
			}
			if (dragData.InsertIndex == -1 || dragData.DropAction == CustomDropAction.None) {
				return;
			}
			CustomListBoxItem itemSource = dragData.ItemSource as CustomListBoxItem;
			if (itemSource == null) {
				return;
			}
			OBaseObject objectSource = itemSource.ObjectData as OBaseObject;
			if (objectSource == null) {
				return;
			}
			bool allow;
			orderedObjectsBox_AllowDropCheck(dragData, out allow);
			if (!allow) {
				return;
			}
			info.InvokeDataChanging(this, "Update Course");
			Course course = info.SelectedCourse;
			if (objectSource.Parent == info.SelectedCourse) {
				course.RemoveObject(objectSource);
			} else {
				objectSource = course.GetObjectRef(objectSource);
			}
			if (dragData.InsertIndex > course.OrderedObjects.Count) {
				dragData.InsertIndex = course.OrderedObjects.Count;
			}
			course.InsertOrderedObject(dragData.InsertIndex, objectSource);
			info.InvokeDataChanged(this, "Update Course");
			info.InvokeObjectsCreated(this);
		}

		private void orderedObjectsBox_AllowDropCheck(CustomDragData dragData, out bool allow) {
			allow = false;
			if (info.SelectedCourse == null) {
				return;
			}
			CustomListBoxItem itemSource = dragData.ItemSource as CustomListBoxItem;
			if (itemSource == null) {
				return;
			}
			OBaseObject objectSource = itemSource.ObjectData as OBaseObject;
			if (objectSource == null) {
				return;
			}
			if (objectSource.Parent.GetObject(typeof(OPlannerData)) != info.Data) {
				return;
			}
			ICourseObject courseObject = (ICourseObject)objectSource.GetObject(typeof(ICourseObject));
			if (courseObject == null) {
				return;
			}
			if (courseObject.IsOrderedObject == false) {
				return;
			}
			allow = true;
			return;
		}

		private void fixedObjectsBox_CustomDropPreview(DragListBox sender, CustomDragData dragData) {
			if (info.SelectedCourse == null) {
				return;
			}
			if (dragData.InsertIndex == -1 || dragData.DropAction == CustomDropAction.None) {
				UpdateCourseObjects(info.SelectedCourse);
				return;
			}
			CustomListBoxItem itemSource = dragData.ItemSource as CustomListBoxItem;
			if (itemSource == null) {
				return;
			}
			OBaseObject objectSource = itemSource.ObjectData as OBaseObject;
			if (objectSource == null) {
				return;
			}
			Course course = info.SelectedCourse.Clone(info.Data);
			OBaseObject dummyObject;
			if (objectSource.Parent == info.SelectedCourse) {
				dummyObject = course.GetObjectByCode(objectSource.ObjectCode);
				if (dummyObject == null) {
					return;
				}
				course.RemoveObject(dummyObject);
			} else {
				dummyObject = course.GetObjectRef(objectSource);
			}
			course.AddFixedObject(objectSource);
			UpdateCourseObjects(course);
			if (fixedObjectsBox.Items.Count == 0) {
				return;
			}
			fixedObjectsBox.SelectedIndex = fixedObjectsBox.Items.Count - 1;
			((CustomListBoxItem)fixedObjectsBox.Items[fixedObjectsBox.Items.Count - 1]).Opacity = 0.5;
		}

		private void fixedObjectsBox_CustomDrop(DragListBox sender, CustomDragData dragData) {
			if (info.SelectedCourse == null) {
				return;
			}
			if (dragData.InsertIndex == -1 || dragData.DropAction == CustomDropAction.None) {
				return;
			}
			CustomListBoxItem itemSource = dragData.ItemSource as CustomListBoxItem;
			if (itemSource == null) {
				return;
			}
			OBaseObject objectSource = itemSource.ObjectData as OBaseObject;
			if (objectSource == null) {
				return;
			}
			bool allow;
			fixedObjectsBox_AllowDropCheck(dragData, out allow);
			if (!allow) {
				return;
			}
			info.InvokeDataChanging(this, "Update Course");
			Course course = info.SelectedCourse;
			if (objectSource.Parent == info.SelectedCourse) {
				course.RemoveObject(objectSource);
			} else {
				objectSource = course.GetObjectRef(objectSource);
			}
			course.AddFixedObject(objectSource);
			info.InvokeDataChanged(this, "Update Course");
			info.InvokeObjectsCreated(this);
		}

		private void fixedObjectsBox_AllowDropCheck(CustomDragData dragData, out bool allow) {
			allow = false;
			if (info.SelectedCourse == null) {
				return;
			}
			CustomListBoxItem itemSource = dragData.ItemSource as CustomListBoxItem;
			if (itemSource == null) {
				return;
			}
			OBaseObject objectSource = itemSource.ObjectData as OBaseObject;
			if (objectSource == null) {
				return;
			}
			if (objectSource.Parent.GetObject(typeof(OPlannerData)) != info.Data) {
				return;
			}
			ICourseObject courseObject = (ICourseObject)objectSource.GetObject(typeof(ICourseObject));
			if (courseObject == null) {
				return;
			}
			if (courseObject.IsFixedObject == false) {
				return;
			}
			allow = true;
			return;
		}

		private void propertiesButton_Click(object sender, RoutedEventArgs e) {
			if (info.Data == null) {
				return;
			}
			if (info.SelectedCourse == null) {
				return;
			}
			CourseProperties wnd = new CourseProperties();
			wnd.Owner = App.Current.MainWindow;
			wnd.SetInfo(info);
			wnd.SetCourse(info.SelectedCourse);
			wnd.ShowDialog();
			Update();
		}

		private void deleteCourseButton_Click(object sender, RoutedEventArgs e) {
			if (info.Data == null) {
				return;
			}
			if (info.SelectedCourse == null) {
				return;
			}
			MessageBoxResult result;
			result = MessageBox.Show(OPlannerHelper.MainWindow, "Are you sure?", "Delete Course", MessageBoxButton.OKCancel, MessageBoxImage.Question);
			if (result == MessageBoxResult.Cancel) {
				return;
			}
			info.InvokeDataChanging(this, "Delete Course");
			info.Data.Courses.Remove(info.SelectedCourse);
			info.SelectedCourse = null;
			info.InvokeDataChanged(this, "Delete Course");
			info.InvokeCourseDeleted(this);
			info.InvokeCourseSelected(this);
		}

		private void duplicateCourseButton_Click(object sender, RoutedEventArgs e) {
			if (info.Data == null) {
				return;
			}
			if (info.SelectedCourse == null) {
				return;
			}
			info.InvokeDataChanging(this, "Duplicate Course");
			Course newCourse = info.SelectedCourse.Clone(info.Data);
			string newName = "Copy of " + newCourse.Name;
			string baseName = newName;
			int startNum = 1;
			if (newCourse.Name.StartsWith("Copy of ", StringComparison.OrdinalIgnoreCase)) {
				baseName = newCourse.Name;
				MatchCollection matches = Regex.Matches(baseName, " [0-9][1-9]*");
				if (matches.Count > 0) {
					if (matches[matches.Count - 1].Index + matches[matches.Count - 1].Length == baseName.Length) {
						startNum = Convert.ToInt32(matches[matches.Count - 1].Value) + 1;
						baseName = baseName.Substring(0, matches[matches.Count - 1].Index);
					}
				}
				if (baseName.EndsWith(" ")) {
					baseName = baseName.Substring(0, baseName.Length - 1);
				}
			}
			if (newCourse.Name.StartsWith("Copy of ", StringComparison.OrdinalIgnoreCase) || info.Data.CourseExists(newName)) {
				int i = startNum;
				while (true) {
					newName = baseName + " " + i.ToString();
					if (!info.Data.CourseExists(newName)) {
						break;
					}
					i++;
				}
			}
			newCourse.Name = newName;
			info.Data.Courses.Add(newCourse);
			info.SelectedCourse = newCourse;
			info.InvokeDataChanged(this, "Duplicate Course");
			info.InvokeCourseCreated(this);
			info.InvokeCourseSelected(this);
		}

		private void orderedUpButton_Click(object sender, RoutedEventArgs e) {
			if (info.SelectedCourse == null) {
				return;
			}
			if (orderedObjectsBox.SelectedIndex < 1 || orderedObjectsBox.SelectedItems.Count != 1) {
				return;
			}
			info.InvokeDataChanging(this, "Update Course");
			info.SelectedCourse.MoveOrderedObject(orderedObjectsBox.SelectedIndex, orderedObjectsBox.SelectedIndex - 1);
			info.InvokeDataChanged(this, "Update Course");
			info.InvokeObjectsCreated(this);
		}

		private void orderedDownButton_Click(object sender, RoutedEventArgs e) {
			if (info.SelectedCourse == null) {
				return;
			}
			if (orderedObjectsBox.SelectedIndex > orderedObjectsBox.Items.Count - 2 || orderedObjectsBox.SelectedItems.Count != 1) {
				return;
			}
			info.InvokeDataChanging(this, "Update Course");
			info.SelectedCourse.MoveOrderedObject(orderedObjectsBox.SelectedIndex, orderedObjectsBox.SelectedIndex + 1);
			info.InvokeDataChanged(this, "Update Course");
			info.InvokeObjectsCreated(this);
		}

		private void orderedNewButton_Click(object sender, RoutedEventArgs e) {
			if (info.Data == null) {
				return;
			}
			if (info.SelectedCourse == null) {
				return;
			}
			NewCourseObject wnd = new NewCourseObject();
			wnd.Owner = App.Current.MainWindow;
			wnd.SetInfo(info);
			wnd.SetCourse(info.SelectedCourse);
			wnd.ShowDialog();
			Update();
		}

	}

}
