//
// System.Windows.UIElement.cs
//
// Contact:
//   Moonlight List (moonlight-list@lists.ximian.com)
//
// Copyright 2007 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows;
#if notyet
using System.Windows.Automation.Peers;
#endif
using System.Windows.Media;
using System.Windows.Input;
using Mono;

namespace System.Windows {
	public abstract partial class UIElement : DependencyObject {

		[SecuritySafeCritical]
		public bool CaptureMouse ()
		{
			return NativeMethods.uielement_capture_mouse (native);
		}

		[SecuritySafeCritical]
		public void ReleaseMouseCapture ()
		{
			NativeMethods.uielement_release_mouse_capture (native);
		}

		[SecuritySafeCritical]
		public void Arrange (Rect finalRect)
		{
			UnmanagedRect unmanagedFinalRect = new UnmanagedRect();
			unmanagedFinalRect.left = finalRect.X;
			unmanagedFinalRect.top = finalRect.Y;
			unmanagedFinalRect.width = finalRect.Width;
			unmanagedFinalRect.height = finalRect.Height;
			NativeMethods.uielement_arrange(native, unmanagedFinalRect);
		}

		[SecuritySafeCritical]
		public void InvalidateArrange ()
		{
			NativeMethods.uielement_invalidate_arrange(native);
		}

		[SecuritySafeCritical]
		public void Measure (Size availableSize)
		{
			UnmanagedSize unmanagedAvailableSize = new UnmanagedSize();

			unmanagedAvailableSize.width = availableSize.Width;
			unmanagedAvailableSize.height = availableSize.Height;

			NativeMethods.uielement_measure (native, unmanagedAvailableSize);
		}

		[SecuritySafeCritical]
		public void InvalidateMeasure ()
		{
			NativeMethods.uielement_invalidate_measure (native);
		}

		[SecuritySafeCritical]
		public void UpdateLayout ()
		{
			NativeMethods.uielement_update_layout (native);
		}

		[SecuritySafeCritical]
		public GeneralTransform TransformToVisual (UIElement visual)
		{
			IntPtr t = NativeMethods.uielement_get_transform_to_uielement (native, visual.native);

			return (GeneralTransform)DependencyObject.Lookup (Kind.GENERALTRANSFORM, t);
		}


		[SecuritySafeCritical]
		public IEnumerable<UIElement> HitTest (Point point)
		{
			throw new NotImplementedException ();
		}

		[SecuritySafeCritical]
		public IEnumerable<UIElement> HitTest (Rect rect)
		{
			throw new NotImplementedException ();
		}

#if notyet
		[SecuritySafeCritical]
		public AutomationPeer OnCreateAutomationPeer ()
		{
			throw new NotImplementedException ();
		}
#endif

		public Size DesiredSize {
			[SecuritySafeCritical]
			get {
				UnmanagedSize sz = NativeMethods.uielement_get_desired_size (native);
				return new Size (sz.width, sz.height);
			}
		}

		public Size RenderSize {
			get {
				UnmanagedSize sz = NativeMethods.uielement_get_render_size (native);
				return new Size (sz.width, sz.height);
			}
		}

		static object GotFocusEvent = new object ();
		static object LostFocusEvent = new object ();
		static object KeyDownEvent = new object ();
		static object KeyUpEvent = new object ();
		static object MouseEnterEvent = new object ();
		static object MouseLeaveEvent = new object ();
		static object MouseLeftButtonDownEvent = new object ();
		static object MouseLeftButtonUpEvent = new object ();
		static object MouseMoveEvent = new object ();
		
		public event RoutedEventHandler GotFocus {
			add {
				if (events[GotFocusEvent] == null)
					Events.AddHandler (this, "GotFocus", Events.got_focus);
				events.AddHandler (GotFocusEvent, value);
			}
			remove {
				events.RemoveHandler (GotFocusEvent, value);
				if (events[GotFocusEvent] == null)
					Events.RemoveHandler (this, "GotFocus", Events.got_focus);
			}
		}
		
		public event RoutedEventHandler LostFocus {
			add {
				if (events[LostFocusEvent] == null)
					Events.AddHandler (this, "LostFocus", Events.lost_focus);
				events.AddHandler (LostFocusEvent, value);
			}
			remove {
				events.RemoveHandler (LostFocusEvent, value);
				if (events[LostFocusEvent] == null)
					Events.RemoveHandler (this, "LostFocus", Events.lost_focus);
			}
		}

		public event KeyEventHandler KeyDown {
			add {
				if (events[KeyDownEvent] == null)
					Events.AddHandler (this, "KeyDown", Events.key_down);
				events.AddHandler (KeyDownEvent, value);
			}
			remove {
				events.RemoveHandler (KeyDownEvent, value);
				if (events[KeyDownEvent] == null)
					Events.RemoveHandler (this, "KeyDown", Events.key_down);
			}
		}

		public event KeyEventHandler KeyUp {
			add {
				if (events[KeyUpEvent] == null)
					Events.AddHandler (this, "KeyUp", Events.key_up);
				events.AddHandler (KeyUpEvent, value);
			}
			remove {
				events.RemoveHandler (KeyUpEvent, value);
				if (events[KeyUpEvent] == null)
					Events.RemoveHandler (this, "KeyUp", Events.key_up);
			}
		}

		public event MouseEventHandler MouseEnter {
			add {
				if (events[MouseEnterEvent] == null)
					Events.AddHandler (this, "MouseEnter", Events.mouse_enter);
				events.AddHandler (MouseEnterEvent, value);
			}
			remove {
				events.RemoveHandler (MouseEnterEvent, value);
				if (events[MouseEnterEvent] == null)
					Events.RemoveHandler (this, "MouseEnter", Events.mouse_enter);
			}
		}

		public event MouseEventHandler MouseLeave {
			add {
				if (events[MouseLeaveEvent] == null)
					Events.AddHandler (this, "MouseLeave", Events.mouse_leave);
				events.AddHandler (MouseLeaveEvent, value);
			}
			remove {
				events.RemoveHandler (MouseLeaveEvent, value);
				if (events[MouseLeaveEvent] == null)
					Events.RemoveHandler (this, "MouseLeave", Events.mouse_leave);
			}
		}

		public event MouseButtonEventHandler MouseLeftButtonDown {
			add {
				if (events[MouseLeftButtonDownEvent] == null)
					Events.AddHandler (this, "MouseLeftButtonDown", Events.mouse_button_down);
				events.AddHandler (MouseLeftButtonDownEvent, value);
			}
			remove {
				events.RemoveHandler (MouseLeftButtonDownEvent, value);
				if (events[MouseLeftButtonDownEvent] == null)
					Events.RemoveHandler (this, "MouseLeftButtonDown", Events.mouse_button_down);
			}
		}

		public event MouseButtonEventHandler MouseLeftButtonUp {
			add {
				if (events[MouseLeftButtonUpEvent] == null)
					Events.AddHandler (this, "MouseLeftButtonUp", Events.mouse_button_up);
				events.AddHandler (MouseLeftButtonUpEvent, value);
			}
			remove {
				events.RemoveHandler (MouseLeftButtonUpEvent, value);
				if (events[MouseLeftButtonUpEvent] == null)
					Events.RemoveHandler (this, "MouseLeftButtonUp", Events.mouse_button_up);
			}
		}

		public event MouseEventHandler MouseMove {
			add {
				if (events[MouseMoveEvent] == null)
					Events.AddHandler (this, "MouseMove", Events.mouse_motion);
				events.AddHandler (MouseMoveEvent, value);
			}
			remove {
				events.RemoveHandler (MouseMoveEvent, value);
				if (events[MouseMoveEvent] == null)
					Events.RemoveHandler (this, "MouseMove", Events.mouse_motion);
			}
		}


		internal void InvokeGotFocus (RoutedEventArgs r)
		{
			RoutedEventHandler h = (RoutedEventHandler)events[GotFocusEvent];
			if (h != null)
				h (this, r);
		}

		internal void InvokeLostFocus (RoutedEventArgs r)
		{
			RoutedEventHandler h = (RoutedEventHandler)events[LostFocusEvent];
			if (h != null)
				h (this, r);
		}

		internal void InvokeMouseMove (MouseEventArgs m)
		{
			MouseEventHandler h = (MouseEventHandler)events[MouseMoveEvent];
			if (h != null)
				h (this, m);
		}

		internal void InvokeMouseButtonDown (MouseButtonEventArgs m)
		{
			MouseButtonEventHandler h = (MouseButtonEventHandler)events[MouseLeftButtonDownEvent];
			if (h != null)
				h (this, m);
		}

		internal void InvokeMouseButtonUp (MouseButtonEventArgs m)
		{
			MouseButtonEventHandler h = (MouseButtonEventHandler)events[MouseLeftButtonUpEvent];
			if (h != null)
				h (this, m);
		}

		internal void InvokeKeyDown (KeyEventArgs k)
		{
			KeyEventHandler h = (KeyEventHandler)events[KeyDownEvent];
			if (h != null)
				h (this, k);
		}

		internal void InvokeKeyUp (KeyEventArgs k)
		{
			KeyEventHandler h = (KeyEventHandler)events[KeyUpEvent];
			if (h != null)
				h (this, k);
		}

		internal void InvokeMouseLeave ()
		{
			MouseEventHandler h = (MouseEventHandler)events[MouseLeaveEvent];
			if (h != null)
				h (this, null);
		}

		internal void InvokeMouseEnter (MouseEventArgs m)
		{
			MouseEventHandler h = (MouseEventHandler)events[MouseEnterEvent];
			if (h != null)
				h (this, m);
		}
	}
}
