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.Windows.Controls.Primitives;

namespace OPlanner {

	public class SelectObjectAdorner : Adorner {

		Rectangle rectangle;
		VisualCollection visualChildren;
		Rect strokeBounds;
		OObjectVisual visual;
		Path centreMarker;
		Geometry centreGeometry;

		public SelectObjectAdorner(UIElement adornedElement) : base(adornedElement) {
			if (adornedElement is OObjectVisual) {
				visual = adornedElement as OObjectVisual;
			}
			visualChildren = new VisualCollection(this);
			rectangle = new Rectangle();
			rectangle.Stroke = Brushes.Black;
			rectangle.StrokeThickness = 1;
			rectangle.Fill = Brushes.Transparent;
			visualChildren.Add(rectangle);
			centreMarker = new Path();
			centreMarker.Stroke = Brushes.Black;
			centreMarker.StrokeThickness = 1;
			centreGeometry = Geometry.Parse("M -3,0 L 3,0 M 0,-3 L 0,3").Clone();
			centreMarker.Data = centreGeometry;
			visualChildren.Add(centreMarker);
		}

		protected override Size ArrangeOverride(Size finalSize) {
			if (visual != null) {
				strokeBounds = visual.GetVisualBounds();
			} else {
				strokeBounds = new Rect(AdornedElement.RenderSize);
			}
			strokeBounds.Inflate(1, 1);
			if (strokeBounds.IsEmpty) {
				return finalSize;
			}
			Rect rect = TransformRect(strokeBounds);
			rectangle.Arrange(rect);
			rect = new Rect(0, 0, 3, 3);
			if (visual == null) {
				rect = strokeBounds;
			} else {
				IMapObject obj = (IMapObject)visual.ObjectData.GetObject(typeof(IMapObject));
				if (!obj.IsCentred) {
					rect = strokeBounds;
				}
			}
			rect = TransformRect(rect);
			centreMarker.Arrange(rect);
			return finalSize;
		}

		protected override int VisualChildrenCount {
			get { return visualChildren.Count; }
		}

		protected override Visual GetVisualChild(int index) {
			return visualChildren[index];
		}

		private Rect TransformRect(Rect rect) {
			return GetTransform().TransformBounds(rect);
		}

		private GeneralTransform GetTransform() {
			return AdornedElement.TransformToVisual(AdornerLayer.GetAdornerLayer(AdornedElement));
		}

		public override GeneralTransform GetDesiredTransform(GeneralTransform transform) {
			return Transform.Identity;
		}

		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
			MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left);
			args.RoutedEvent = MouseLeftButtonDownEvent;
			AdornedElement.RaiseEvent(args);
		}

		protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) {
			MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left);
			args.RoutedEvent = MouseLeftButtonUpEvent;
			AdornedElement.RaiseEvent(args);
		}

		protected override void OnMouseRightButtonDown(MouseButtonEventArgs e) {
			MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Right);
			args.RoutedEvent = MouseRightButtonDownEvent;
			AdornedElement.RaiseEvent(args);
		}

		protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
			MouseButtonEventArgs args = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Right);
			args.RoutedEvent = MouseRightButtonUpEvent;
			AdornedElement.RaiseEvent(args);
			FrameworkElement obj = AdornedElement as FrameworkElement;
			if (obj != null) {
				if (obj.ContextMenu != null) {
					obj.ContextMenu.IsOpen = true;
				}
			}
		}

		protected override void OnMouseMove(MouseEventArgs e) {
			MouseEventArgs args = new MouseEventArgs(e.MouseDevice, e.Timestamp);
			args.RoutedEvent = MouseMoveEvent;
			AdornedElement.RaiseEvent(args);
		}

	}

	public class SelectionRectAdorner : Adorner {

		Rectangle rectangle;
		VisualCollection visualChildren;
		Rect strokeBounds = Rect.Empty;

		public SelectionRectAdorner(UIElement adornedElement)
			: base(adornedElement) {
			visualChildren = new VisualCollection(this);
			rectangle = new Rectangle();
			rectangle.Stroke = Brushes.Black;
			rectangle.StrokeThickness = 1;
			visualChildren.Add(rectangle);
		}

		public void SetRect(Rect bounds) {
			strokeBounds = bounds;
			InvalidateVisual();
		}

		public Rect GetRect() {
			return strokeBounds;
		}

		protected override Size ArrangeOverride(Size finalSize) {
			if (strokeBounds.IsEmpty) {
				return finalSize;
			}
			rectangle.Arrange(TransformRect(strokeBounds));
			return finalSize;
		}

		protected override int VisualChildrenCount {
			get { return visualChildren.Count; }
		}

		protected override Visual GetVisualChild(int index) {
			return visualChildren[index];
		}

		private Rect TransformRect(Rect rect) {
			return GetTransform().TransformBounds(rect);
		}

		private GeneralTransform GetTransform() {
			return AdornedElement.TransformToVisual(AdornerLayer.GetAdornerLayer(AdornedElement));
		}

		public override GeneralTransform GetDesiredTransform(GeneralTransform transform) {
			return Transform.Identity;
		}

	}


	public class LinePointAdorner : Adorner {

		FrameworkElement visual;
		VisualCollection visualChildren;
		int segmentNum;
		PointType pointType;
		CustomPath customPath;

		public PointType PointType {
			get {
				return pointType;
			}
			set {
				pointType = value;
				visualChildren.Clear();
				if (pointType == PointType.Control) {
					visual = new Ellipse();
					((Ellipse)visual).Fill = Brushes.Black;
					visualChildren.Add(visual);
				} else {
					visual = new Rectangle();
					((Rectangle)visual).Fill = Brushes.Black;
					visualChildren.Add(visual);
				}
			}
		}

		public int SegmentNum {
			get {
				return segmentNum;
			}
			set {
				segmentNum = value;
			}
		}

		public CustomPath CustomPath {
			get {
				return customPath;
			}
			set {
				customPath = value;
			}
		}

		public CustomPathSegment Segment {
			get {
				return CustomPath.Segments[SegmentNum];
			}
		}

		public Point Centre {
			get {
				if (pointType == PointType.End) {
					return Segment.End;
				} else if (pointType == PointType.Start) {
					return Segment.Start;
				} else if (pointType == PointType.Control) {
					CustomQuadraticBezierSegment quadratic = Segment as CustomQuadraticBezierSegment;
					if (quadratic == null) {
						return new Point(0, 0);
					}
					return quadratic.Control;
				} else {
					return new Point(0, 0);
				}
			}
		}

		public LinePointAdorner(UIElement adornedElement)
			: base(adornedElement) {
			visualChildren = new VisualCollection(this);
		}

		protected override Size ArrangeOverride(Size finalSize) {
			Point point = TransformPoint(Centre);
			double size = 4;
			Rect rect = new Rect(point.X - size / 2, point.Y - size / 2, size, size);
			if (visual != null) {
				visual.Arrange(rect);
			}
			return finalSize;
		}

		protected override int VisualChildrenCount {
			get { return visualChildren.Count; }
		}

		protected override Visual GetVisualChild(int index) {
			return visualChildren[index];
		}

		private Point TransformPoint(Point point) {
			return GetTransform().Transform(point);
		}

		private GeneralTransform GetTransform() {
			return AdornedElement.TransformToVisual(AdornerLayer.GetAdornerLayer(AdornedElement));
		}

		public override GeneralTransform GetDesiredTransform(GeneralTransform transform) {
			return Transform.Identity;
		}

		public void SetPoint(Point newPoint) {
			CustomPath.MovePoint(SegmentNum, PointType, newPoint);
		}

	}

}
