#region Copyright Notice
/*
 * gitter - VCS repository management tool
 * Copyright (C) 2014  Popovskiy Maxim Vladimirovitch <[email protected]>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#endregion

namespace gitter.Framework.Controls
{
	using System;
	using System.Collections.Generic;
	using System.Windows.Forms;
	using System.Drawing;
	using System.ComponentModel;

	/// <summary>Hosts view hosts and applies grid layout.</summary>
	public sealed class ViewDockGrid : Control, IDockHost
	{
		#region Static

		private static readonly LinkedList<ViewDockGrid> _grids;

		internal static IEnumerable<ViewDockGrid> Grids
		{
			get { return _grids; }
		}

		/// <summary>Initializes the <see cref="ViewDockGrid"/> class.
		static ViewDockGrid()
		{
			_grids = new LinkedList<ViewDockGrid>();
		}

		#endregion

		#region Data

		private readonly ViewHost _rootHost;
		private readonly GridDockMarkers _dockMarkers;
		private Control _rootControl;
		private PopupNotificationsStack _popupsStack;

		private ViewDockSide _left;
		private ViewDockSide _top;
		private ViewDockSide _right;
		private ViewDockSide _bottom;
		private LinkedList<FloatingViewForm> _floatingViewForms;

		#endregion

		#region .ctor

		/// <summary>Initializes a new instance of the <see cref="ViewDockGrid"/> class.
		public ViewDockGrid()
		{
			_dockMarkers = new GridDockMarkers(this);
			var bounds = ClientRectangle;
			bounds.X += ViewConstants.Spacing;
			bounds.Y += ViewConstants.Spacing;
			bounds.Width -= ViewConstants.Spacing * 2;
			bounds.Height -= ViewConstants.Spacing * 2;
			_rootHost = new ViewHost(this, true, true, null)
			{
				Bounds = bounds,
				Anchor = ViewConstants.AnchorAll,
			};
			_rootControl = _rootHost;
			_floatingViewForms = new LinkedList<FloatingViewForm>();
			_popupsStack = new PopupNotificationsStack();

			SetStyle(ControlStyles.ContainerControl, true);

			SuspendLayout();
			_rootHost.Parent = this;
			ResumeLayout(true);

			lock(_grids)
			{
				_grids.AddLast(this);
			}

			BackColor = ViewManager.Renderer.BackgroundColor;
		}

		#endregion

		#region Properties

		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public override Color BackColor
		{
			get { return base.BackColor; }
			set { base.BackColor = value; }
		}

		internal ViewHost RootHost
		{
			get { return _rootHost; }
		}

		internal Control RootControl
		{
			get { return _rootControl; }
			set { _rootControl = value; }
		}

		internal IEnumerable<FloatingViewForm> FloatingViewForms
		{
			get { return _floatingViewForms; }
		}

		private ViewRenderer Renderer
		{
			get { return ViewManager.Renderer; }
		}

		#endregion

		internal void AddFloatingForm(FloatingViewForm floatingViewForm)
		{
			Verify.Argument.IsNotNull(floatingViewForm, "floatingViewForm");

			_floatingViewForms.AddLast(floatingViewForm);
		}

		internal void RemoveFloatingForm(FloatingViewForm floatingViewForm)
		{
			Verify.Argument.IsNotNull(floatingViewForm, "floatingViewForm");

			_floatingViewForms.Remove(floatingViewForm);
		}

		private void SpawnLeftSide()
		{
			Verify.State.IsTrue(_left == null);

			var size = Size;
			var bounds = new Rectangle(
				0, ViewConstants.Spacing,
				Renderer.SideTabHeight, 0);

			int hspace = size.Width - (Renderer.SideTabHeight + ViewConstants.Spacing * 2);
			if(_right != null) hspace -= Renderer.SideTabHeight;

			if(_top != null)
			{
				if(_top.Width > hspace)
				{
					_top.Bounds = new Rectangle(
						Renderer.SideTabHeight + ViewConstants.Spacing, 0,
						hspace, Renderer.SideTabHeight);
				}
				else
				{
					_top.Left += Renderer.SideTabHeight;
				}
				bounds.Y += Renderer.SideTabHeight;
			}
			if(_bottom != null)
			{
				if(_bottom.Width > hspace)
				{
					_bottom.Bounds = new Rectangle(
						Renderer.SideTabHeight + ViewConstants.Spacing, size.Height - Renderer.SideTabHeight,
						hspace, Renderer.SideTabHeight);
				}
				else
				{
					_bottom.Left += Renderer.SideTabHeight;
				}
			}
			_rootControl.SetBounds(
				_rootControl.Left + Renderer.SideTabHeight, 0,
				_rootControl.Width - Renderer.SideTabHeight, 0,
				BoundsSpecified.X | BoundsSpecified.Width);
			_left = new ViewDockSide(this, AnchorStyles.Left)
			{
				Anchor = AnchorStyles.Left | AnchorStyles.Top,
				Bounds = bounds,
				Parent = this,
			};
		}

		private void SpawnTopSide()
		{
			Verify.State.IsTrue(_top == null);

			var size = Size;
			var bounds = new Rectangle(
				ViewConstants.Spacing, 0,
				0, Renderer.SideTabHeight);

			int vspace = size.Height - Renderer.SideTabHeight - ViewConstants.Spacing * 2;
			if(_bottom != null) vspace -= Renderer.SideTabHeight;

			if(_left != null)
			{
				if(_left.Height > vspace)
				{
					_left.Bounds = new Rectangle(
						0, Renderer.SideTabHeight + ViewConstants.Spacing,
						Renderer.SideTabHeight, vspace);
				}
				else
				{
					_left.Top += Renderer.SideTabHeight;
				}
				bounds.X += Renderer.SideTabHeight;
			}
			if(_right != null)
			{
				if(_right.Height > vspace)
				{
					_right.Bounds = new Rectangle(
						size.Width - Renderer.SideTabHeight, Renderer.SideTabHeight + ViewConstants.Spacing,
						Renderer.SideTabHeight, vspace);
				}
				else
				{
					_right.Top += Renderer.SideTabHeight;
				}
			}
			_rootControl.SetBounds(
				0, _rootControl.Top + Renderer.SideTabHeight,
				0, _rootControl.Height - Renderer.SideTabHeight,
				BoundsSpecified.Y | BoundsSpecified.Height);
			_top = new ViewDockSide(this, AnchorStyles.Top)
			{
				Anchor = AnchorStyles.Left | AnchorStyles.Top,
				Bounds = bounds,
				Parent = this,
			};
		}

		private void SpawnRightSide()
		{
			Verify.State.IsTrue(_right == null);

			var size = Size;
			var bounds = new Rectangle(
				size.Width - Renderer.SideTabHeight, ViewConstants.Spacing,
				Renderer.SideTabHeight, 0);

			int hspace = size.Width - Renderer.SideTabHeight - ViewConstants.Spacing * 2;
			if(_left != null) hspace -= Renderer.SideTabHeight;

			if(_top != null)
			{
				if(_top.Width > hspace)
				{
					_top.Width = hspace;
				}
				bounds.Y += Renderer.SideTabHeight;
			}
			if(_bottom != null)
			{
				if(_bottom.Width > hspace)
				{
					_bottom.Width = hspace;
				}
			}
			_rootControl.Width -= Renderer.SideTabHeight;
			_right = new ViewDockSide(this, AnchorStyles.Right)
			{
				Anchor = AnchorStyles.Right | AnchorStyles.Top,
				Bounds = bounds,
				Parent = this,
			};
		}

		private void SpawnBottomSide()
		{
			Verify.State.IsTrue(_bottom == null);

			var size = Size;
			var bounds = new Rectangle(
				ViewConstants.Spacing, size.Height - Renderer.SideTabHeight,
				0, Renderer.SideTabHeight);

			int vspace = size.Height - Renderer.SideTabHeight - ViewConstants.Spacing * 2;
			if(_top != null) vspace -= Renderer.SideTabHeight;

			if(_left != null)
			{
				if(_left.Height > vspace)
				{
					_left.Height = vspace;
				}
				bounds.X += Renderer.SideTabHeight;
			}
			if(_right != null)
			{
				if(_right.Height > vspace)
				{
					_right.Height = vspace;
				}
			}
			_rootControl.Height -= Renderer.SideTabHeight;
			_bottom = new ViewDockSide(this, AnchorStyles.Bottom)
			{
				Anchor = AnchorStyles.Left | AnchorStyles.Bottom,
				Bounds = bounds,
				Parent = this,
			};
		}

		internal void KillSide(AnchorStyles side)
		{
			switch(side)
			{
				case AnchorStyles.Left:
					RemoveLeftSide();
					break;
				case AnchorStyles.Top:
					RemoveTopSide();
					break;
				case AnchorStyles.Right:
					RemoveRightSide();
					break;
				case AnchorStyles.Bottom:
					KillBottomSide();
					break;
				default:
					throw new ArgumentException(
						"Unknown AnchorStyles value: {0}".UseAsFormat(side),
						"side");
			}
		}

		private void RemoveAllSides()
		{
			SuspendLayout();
			if(_left != null)
			{
				_left.Parent = null;
				_left.Dispose();
				_left = null;
			}
			if(_top != null)
			{
				_top.Parent = null;
				_top.Dispose();
				_top = null;
			}
			if(_right != null)
			{
				_right.Parent = null;
				_right.Dispose();
				_right = null;
			}
			if(_bottom != null)
			{
				_bottom.Parent = null;
				_bottom.Dispose();
				_bottom = null;
			}
			RootControl.SetBounds(
				ViewConstants.Spacing, ViewConstants.Spacing,
				Width - ViewConstants.Spacing * 2, Height - ViewConstants.Spacing * 2,
				BoundsSpecified.All);
			ResumeLayout(true);
		}

		private void RemoveLeftSide()
		{
			if(_left != null)
			{
				_left.Parent = null;
				_left.Dispose();
				_left = null;

				var bounds = _rootControl.Bounds;
				bounds.X -= Renderer.SideTabHeight;
				bounds.Width += Renderer.SideTabHeight;
				_rootControl.Bounds = bounds;
				var hcs = Width - ViewConstants.Spacing * 2;
				if(_right != null) hcs -= Renderer.SideTabHeight;
				if(_top != null)
				{
					var w = _top.Width;
					var len = _top.OptimalLength;
					if(w >= len)
					{
						_top.Left = ViewConstants.Spacing;
					}
					else
					{
						if(len > hcs) len = hcs;
						_top.SetBounds(
							ViewConstants.Spacing, 0, len, Renderer.SideTabHeight,
							BoundsSpecified.X | BoundsSpecified.Width);
					}
				}
				if(_bottom != null)
				{
					var w = _bottom.Height;
					var len = _bottom.OptimalLength;
					if(w >= len)
					{
						_bottom.Left = ViewConstants.Spacing;
					}
					else
					{
						if(len > hcs) len = hcs;
						_bottom.SetBounds(
							ViewConstants.Spacing, 0, len, Renderer.SideTabHeight,
							BoundsSpecified.X | BoundsSpecified.Width);
					}
				}
			}
		}

		private void RemoveTopSide()
		{
			if(_top != null)
			{
				_top.Parent = null;
				_top.Dispose();
				_top = null;

				var bounds = _rootControl.Bounds;
				bounds.Y -= Renderer.SideTabHeight;
				bounds.Height += Renderer.SideTabHeight;
				_rootControl.Bounds = bounds;
				var vcs = Height - Renderer.SideTabHeight * 2;
				if(_bottom != null) vcs -= Renderer.SideTabHeight;
				if(_left != null)
				{
					var h = _left.Height;
					var len = _left.OptimalLength;
					if(h >= len)
					{
						_left.Top = ViewConstants.Spacing;
					}
					else
					{
						if(len > vcs) len = vcs;
						_left.SetBounds(
							0, ViewConstants.Spacing, Renderer.SideTabHeight, len,
							BoundsSpecified.Y | BoundsSpecified.Height);
					}
				}
				if(_right != null)
				{
					var h = _right.Height;
					var len = _right.OptimalLength;
					if(h >= len)
					{
						_right.Top = ViewConstants.Spacing;
					}
					else
					{
						if(len > vcs) len = vcs;
						_right.SetBounds(
							0, ViewConstants.Spacing, Renderer.SideTabHeight, len,
							BoundsSpecified.Y | BoundsSpecified.Height);
					}
				}
			}
		}

		private void RemoveRightSide()
		{
			if(_right != null)
			{
				_right.Parent = null;
				_right.Dispose();
				_right = null;
				_rootControl.Width += Renderer.SideTabHeight;

				var hcs = Width - ViewConstants.Spacing * 2;
				if(_left != null) hcs -= Renderer.SideTabHeight;
				if(_top != null)
				{
					var w = _top.Width;
					var len = _top.OptimalLength;
					if(w < len)
					{
						if(len > hcs) len = hcs;
						_top.Width = len;
					}
				}
				if(_bottom != null)
				{
					var w = _bottom.Height;
					var len = _bottom.OptimalLength;
					if(w < len)
					{
						if(len > hcs) len = hcs;
						_bottom.Width = len;
					}
				}
			}
		}

		private void KillBottomSide()
		{
			if(_bottom != null)
			{
				_bottom.Parent = null;
				_bottom.Dispose();
				_bottom = null;
				_rootControl.Height += Renderer.SideTabHeight;

				var vcs = Height - Renderer.SideTabHeight * 2;
				if(_bottom != null) vcs -= Renderer.SideTabHeight;
				if(_left != null)
				{
					var h = _left.Height;
					var len = _left.OptimalLength;
					if(h < len)
					{
						if(len > vcs) len = vcs;
						_left.Height = len;
					}
				}
				if(_right != null)
				{
					var h = _right.Height;
					var len = _right.OptimalLength;
					if(h < len)
					{
						if(len > vcs) len = vcs;
						_right.Height = len;
					}
				}
			}
		}

		internal ViewDockSide LeftSide
		{
			get { return _left; }
		}

		internal ViewDockSide RightSide
		{
			get { return _right; }
		}

		internal ViewDockSide TopSide
		{
			get { return _top; }
		}

		internal ViewDockSide BottomSide
		{
			get { return _bottom; }
		}

		private ViewDockSide GetCreateDockSide(AnchorStyles side)
		{
			ViewDockSide viewDockSide;
			switch(side)
			{
				case AnchorStyles.Left:
					if(_left == null) SpawnLeftSide();
					viewDockSide = _left;
					break;
				case AnchorStyles.Top:
					if(_top == null) SpawnTopSide();
					viewDockSide = _top;
					break;
				case AnchorStyles.Right:
					if(_right == null) SpawnRightSide();
					viewDockSide = _right;
					break;
				case AnchorStyles.Bottom:
					if(_bottom == null) SpawnBottomSide();
					viewDockSide = _bottom;
					break;
				default:
					throw new ArgumentException(
						"Unknown AnchorStyles value: {0}".UseAsFormat(side),
						"side");
			}
			return viewDockSide;
		}

		public PopupNotificationsStack PopupsStack
		{
			get { return _popupsStack; }
		}

		internal int HorizontalClientSpace
		{
			get
			{
				var w = Width - ViewConstants.Spacing * 2;
				if(_left != null) w -= Renderer.SideTabHeight;
				if(_right != null) w -= Renderer.SideTabHeight;
				return w;
			}
		}

		internal int VerticalClientSpace
		{
			get
			{
				var h = Height - ViewConstants.Spacing * 2;
				if(_top != null) h -= Renderer.SideTabHeight;
				if(_bottom != null) h -= Renderer.SideTabHeight;
				return h;
			}
		}

		private static ViewBase FindView(Control control, Guid guid, object viewModel, bool considerViewModel)
		{
			foreach(Control child in control.Controls)
			{
				var viewHost = child as ViewHost;
				if(viewHost != null)
				{
					foreach(var view in viewHost.Views)
					{
						if(view.Guid == guid)
						{
							if(considerViewModel)
							{
								if(object.Equals(view.ViewModel, viewModel))
								{
									return view;
								}
								else
								{
									continue;
								}
							}
							return view;
						}
					}
				}
				else
				{
					var view = FindView(child, guid, viewModel, considerViewModel);
					if(view != null) return view;
				}
			}
			return null;
		}

		public ViewBase FindView(Guid guid)
		{
			return FindView(this, guid, null, false);
		}

		public ViewBase FindView(Guid guid, IDictionary<string, object> parameters)
		{
			return FindView(this, guid, parameters, true);
		}

		public void DockSide(AnchorStyles side, ViewBase view, bool autoHide)
		{
			DockSide(side, new ViewHost(this, false, false, new[] { view }), autoHide);
		}

		internal void DockSide(AnchorStyles side, ViewHost host, bool autoHide)
		{
			host.DockToSide(RootControl, side);
		}

		public void DockRoot(ViewBase view)
		{
			_rootHost.AddView(view);
		}

		/// <summary>
		/// Raises the <see cref="E:System.Windows.Forms.Control.Resize"/> event.
		/// </summary>
		/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.
		protected override void OnResize(EventArgs e)
		{
			base.OnResize(e);
			var vspace = VerticalClientSpace;
			var hspace = HorizontalClientSpace;
			if(_left != null)
			{
				var h = _left.Height;
				if(h > vspace)
				{
					_left.Height = vspace;
				}
				else
				{
					if(h < _left.OptimalLength)
					{
						h = _left.OptimalLength;
						if(h > vspace) h = vspace;
						_left.Height = h;
					}
				}
			}
			if(_top != null)
			{
				var w = _top.Width;
				if(w > hspace)
				{
					_top.Width = hspace;
				}
				else
				{
					if(w < _top.OptimalLength)
					{
						w = _top.OptimalLength;
						if(w > hspace) w = hspace;
						_top.Width = w;
					}
				}
			}
			if(_right != null)
			{
				var h = _right.Height;
				if(h > vspace)
				{
					_right.Height = vspace;
				}
				else
				{
					if(h < _right.OptimalLength)
					{
						h = _right.OptimalLength;
						if(h > vspace) h = vspace;
						_right.Height = h;
					}
				}
			}
			if(_bottom != null)
			{
				var w = _bottom.Width;
				if(w > hspace)
				{
					_bottom.Width = hspace;
				}
				else
				{
					if(w < _bottom.OptimalLength)
					{
						w = _bottom.OptimalLength;
						if(w > hspace) w = hspace;
						_bottom.Width = w;
					}
				}
			}
		}

		/// <summary>
		/// Releases the unmanaged resources used by the <see cref="T:System.Windows.Forms.Control"/> and its child controls and optionally releases the managed resources.
		/// </summary>
		/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
		protected override void Dispose(bool disposing)
		{
			lock(_grids)
			{
				_grids.Remove(this);
			}
			if(disposing)
			{
				_dockMarkers.Dispose();
				if(_left != null)
				{
					_left.Dispose();
					_left = null;
				}
				if(_top != null)
				{
					_top.Dispose();
					_top = null;
				}
				if(_right != null)
				{
					_right.Dispose();
					_right = null;
				}
				if(_bottom != null)
				{
					_bottom.Dispose();
					_bottom = null;
				}
				if(_popupsStack != null)
				{
					_popupsStack.Dispose();
					_popupsStack = null;
				}
				_rootControl = null;
				_floatingViewForms.Clear();
			}
			base.Dispose(disposing);
		}

		#region IDockHost

		/// <summary>Provides dock helper markers to determine dock position (<see cref="DockResult"/>).
		public IDockMarkerProvider DockMarkers
		{
			get { return _dockMarkers; }
		}

		/// <summary>Determines if <see cref="ViewHost"/> cn be docked into this .
		/// <param name="viewHost"><see cref="ViewHost"/> to dock.
		/// <param name="dockResult">Position for docking.</param>
		/// <returns>true if docking is possible.</returns>
		public bool CanDock(ViewHost viewHost, DockResult dockResult)
		{
			Verify.Argument.IsNotNull(viewHost, "viewHost");

			if(viewHost.IsDocumentWell || (viewHost.ViewsCount == 1 && viewHost.GetView(0).IsDocument))
			{
				return false;
			}
			switch(dockResult)
			{
				case DockResult.Left:
				case DockResult.Top:
				case DockResult.Right:
				case DockResult.Bottom:
					return true;
				default:
					return false;
			}
		}

		/// <summary>Docks <paramref name="viewHost"/> into this .
		/// <param name="viewHost"><see cref="ViewHost"/> to dock.
		/// <param name="dockResult">Position for docking.</param>
		public void PerformDock(ViewHost viewHost, DockResult dockResult)
		{
			Verify.Argument.IsNotNull(viewHost, "viewHost");
			Verify.Argument.IsFalse(viewHost.IsDocumentWell, "viewHost");
			Verify.Argument.IsFalse(viewHost.ViewsCount == 1 && viewHost.GetView(0).IsDocument, "viewHost");

			switch(dockResult)
			{
				case DockResult.Left:
					DockSide(AnchorStyles.Left, viewHost, false);
					viewHost.Status = ViewHostStatus.Docked;
					break;
				case DockResult.Top:
					DockSide(AnchorStyles.Top, viewHost, false);
					viewHost.Status = ViewHostStatus.Docked;
					break;
				case DockResult.Right:
					DockSide(AnchorStyles.Right, viewHost, false);
					viewHost.Status = ViewHostStatus.Docked;
					break;
				case DockResult.Bottom:
					DockSide(AnchorStyles.Bottom, viewHost, false);
					viewHost.Status = ViewHostStatus.Docked;
					break;
				case DockResult.AutoHideLeft:
					GetCreateDockSide(AnchorStyles.Left).AddHost(viewHost);
					break;
				case DockResult.AutoHideTop:
					GetCreateDockSide(AnchorStyles.Top).AddHost(viewHost);
					break;
				case DockResult.AutoHideRight:
					GetCreateDockSide(AnchorStyles.Right).AddHost(viewHost);
					break;
				case DockResult.AutoHideBottom:
					GetCreateDockSide(AnchorStyles.Bottom).AddHost(viewHost);
					break;
				default:
					throw new ArgumentException(
						"Unsupported DockResult value: {0}".UseAsFormat(dockResult),
						"dockResult");
			}
		}

		/// <summary>Get bounding rectangle for docked view.</summary>
		/// <param name="viewHost">Tested <see cref="ViewHost"/>.
		/// <param name="dockResult">Position for docking.</param>
		/// <returns>Bounding rectangle for docked view.</returns>
		public Rectangle GetDockBounds(ViewHost viewHost, DockResult dockResult)
		{
			Verify.Argument.IsNotNull(viewHost, "viewHost");

			var rootBounds = RootControl.Bounds;
			Rectangle bounds;
			switch(dockResult)
			{
				case DockResult.Left:
					{
						var w1 = viewHost.Width;
						var w2 = rootBounds.Width;
						ViewSplit.OptimalSizes(w2, ViewConstants.MinimumHostWidth, ref w1, ref w2);
						bounds = new Rectangle(0, 0, w1, rootBounds.Height);
					}
					break;
				case DockResult.Top:
					{
						var h1 = viewHost.Height;
						var h2 = rootBounds.Height;
						ViewSplit.OptimalSizes(h2, ViewConstants.MinimumHostHeight, ref h1, ref h2);
						bounds = new Rectangle(0, 0, rootBounds.Width, h1);
					}
					break;
				case DockResult.Right:
					{
						var w1 = rootBounds.Width;
						var w2 = viewHost.Width;
						ViewSplit.OptimalSizes(w1, ViewConstants.MinimumHostWidth, ref w1, ref w2);
						bounds = new Rectangle(rootBounds.Width - w2, 0, w2, rootBounds.Height);
					}
					break;
				case DockResult.Bottom:
					{
						var h1 = rootBounds.Height;
						var h2 = viewHost.Height;
						ViewSplit.OptimalSizes(h1, ViewConstants.MinimumHostHeight, ref h1, ref h2);
						bounds = new Rectangle(0, rootBounds.Height - h2, rootBounds.Width, h2);
					}
					break;
				default:
					throw new ArgumentException(
						"Unsuported DockResult value: {0}".UseAsFormat(dockResult),
						"dockResult");
			}
			bounds.Offset(rootBounds.X, rootBounds.Y);
			return RectangleToScreen(bounds);
		}

		#endregion
	}
}