using System;
using System.Collections.Generic;
using System.Text;
using Vortex.Drawing;
using Vortex.Debugging;
using Vortex.SceneFramework.CSS;
using Vortex.Input;

namespace Vortex.SceneFramework {

	/// <summary>
	/// Base node of screen graph. Each node has Id, location, scaling, rotation
	/// </summary>
	public abstract class Node : IStyledNode, ITransform {
		///<summary>List of children nodes</summary>
		private List<Node> _children = new List<Node>();		
		private Node _parent;
		private DomainNode _domain;

		private string _id;
		private string _className;

		private NodeStyle _nodeStyle;

		///<summary>Location relative to parent node. It defines origin point</summary>
		private Vector2 _location;
		///<summary>Origin point, it allows change rotation/scaling point relative to location</summary>
		private Vector2 _origin;
		///<summary>Element scale. Origin point is location point or (0,0) in node space</summary>
		private Vector2 _scale = Vector2.Unit;
		///<summary>Rotation of node around its origin point</summary>
		private float   _rotation;
		///<summary>Post-computed 2D transform of this node</summary>
		private Transform2D _transform;

		private bool _hovered;
		private bool _focused;
		private bool _pressed;

		private bool _enabled = true;
		private bool _visible = true;
		private bool _transient;
		private bool _focusable = false;
		private bool _eventBubblingEnabled = false;

		private GameCursor _cursor = GameCursor.Default;

		/// <summary>
		/// Initializes a new instance of the <see cref="Element"/> class.
		/// </summary>
		public Node() {
			ComputeTransform();
			//create node style instance :)
			_nodeStyle = new NodeStyle(this);
		}

		/// <summary>
		/// Gets the node styles object. You may set style value properties of it to override all of style-sheet node styles.
		/// </summary>
		/// <value>The node style object.</value>
		public NodeStyle Style {
			get { return _nodeStyle; }
		}

		#region IStyledElement Members

		/// <summary>
		/// Gets the style sheet used by node. Can be <c>null</c> if node is out of domain.
		/// </summary>
		/// <value>The style sheet used by node.</value>
		public virtual StyleSheet StyleSheet {
			get { return Domain != null ? Domain.StyleSheet : null; }
		}

		/// <summary>
		/// Id of this node. You can use id as node's unique identifier. This id also may be used as style selector in form "#id"
		/// </summary>
		/// <value>The id of node.</value>
		public string Id {
			get { return _id; }
			set {
				if (_id != value) {
					_id = value;
					Style.Discard();
				}
			}
		}

		/// <summary>
		/// Gets or sets the name space separated style class names
		/// </summary>
		/// <value>The style class names space separated (may be <c>null</c>).</value>
		public string Class {
			get { return _className; }
			set {
				if (_className != value) {
					_className = value;
					Style.Discard();
				}
			}
		}

		/// <summary>
		/// Gets the all of node style states.
		/// </summary>
		/// <returns>Enumeration of all of node style states</returns>
		public virtual IEnumerable<StyleState> GetElementStates() {
			if (IsEnabled) {
				if (IsPressed) {
					yield return StyleState.Pressed;
				} else if (IsHovered) {
					yield return StyleState.Hovered;
				} else if (IsFocused) {
					yield return StyleState.Focused;
				} else {
					yield return StyleState.Default;
				}
			} else {
				yield return StyleState.Disabled;
			}
		}

		#endregion

		#region Internal Element Notifications

		/// <summary>
		/// Prefers some action when style is changed
		/// Style values can be obtained each frame with name/index property access but caching of style values reduces these lookups
		/// greatly improving performance of rendering/measurement routines.
		/// </summary>
		protected virtual void ElementStyleChanged() {
			;
		}

		/// <summary>
		/// Notifies nodes that it is added to another node is not alone anymore. Most common usage is refining style class
		/// </summary>
		protected virtual void NotifyNodeAddedToDomain() {
			_domain = GetNodeDomain();
			Style.Discard();
			
		}

		/// <summary>
		/// Notifies node that it is removed to domain. Required actions, remove all of temporary states like "focused", "pressed", "hovered")
		/// </summary>
		protected virtual void NotifyNodeRemovedFromDomain() {			
			IsFocused = false;
			IsPressed = false;
			IsHovered = false;

			//remove node domain reference
			_domain = null;
			Style.Discard();
		}

		#endregion

		#region Graph Management

		/// <summary>
		/// Gets the node domain.
		/// </summary>
		/// <value>The domain which this node belongs to. May be null if node is out of graph.</value>
		public virtual DomainNode Domain {
			get { return _domain; }
		}

		/// <summary>
		/// Enumeration of node's child nodes
		/// </summary>
		/// <value>The child nodes.</value>
		public IEnumerable<Node> Children {
			get { return _children; }
		}

		/// <summary>
		/// Number of node children
		/// </summary>
		/// <value>The number of child nodes.</value>
		public int ChildrenCount {
			get { return _children.Count; }
		}

		/// <summary>
		/// True if this node has children
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this node has children; otherwise, <c>false</c>.
		/// </value>
		public bool HasChildren {
			get { return _children.Count > 0; }
		}

		/// <summary>
		/// Gets child node by its index
		/// </summary>
		/// <value>Another node which is child of this node</value>
		public Node this[int index] {
			get { return _children[index]; }
		}

		/// <summary>
		/// Gets the node domain. This method iterates though hierarchy and check each parent until reach the domain node.
		/// </summary>
		/// <returns><see cref="Vortex.SceneFramework.DomainNode"/> instance which contains this node; if node detached from graph - <c>null</c> </returns>
		protected virtual DomainNode GetNodeDomain() {
			Node parent = Parent;
			while (parent != null) {
				DomainNode domain = parent as DomainNode;
				if (domain != null) return domain;
				parent = parent.Parent;
			}
			return null;
		}

		/// <summary>
		/// Gets the children of the specified type only.
		/// </summary>
		/// <typeparam name="T">Type of child to return</typeparam>
		/// <returns>Enumeration of node children of specified type</returns>
		public IEnumerable<T> GetChildren<T>() where T:Node{
			Type returnType = typeof(T);
			foreach (Node node in Children) {
				if (returnType.IsInstanceOfType(node)) {
					yield return node as T;
				}
			}
		}

		/// <summary>
		/// Parent node for this node
		/// </summary>
		/// <value>The parent node.</value>
		public Node Parent {
			get { return _parent; }
			set {
				//remove node from parent list first
				if (null != _parent) {
					_parent.RemoveChild(this);
				}
				//add node to new parent or leave abandoned
				if (value != null) {
					value.AddChild(this);
				}
			}
		}

		/// <summary>
		/// Add child to this node
		/// </summary>
		/// <param name="childNode">The child node.</param>
		public void AddChild(Node childNode) {
			//remove previous linkage
			if (childNode.Parent != null) {
				childNode.Parent.RemoveChild(childNode);
			}
			//add it to new list
			_children.Add(childNode);
			childNode._parent = this;

			//notify all of nodes : they've added to parent node
			childNode.ForEach(delegate(Node node) {
				node.NotifyNodeAddedToDomain();
			});
		}

		/// <summary>
		/// Remove child from children list of this node. 
		/// </summary>
		/// <param name="childNode">The child node.</param>
		/// <returns>Returns <c>true</c> if node was successfully removed</returns>
		public bool RemoveChild(Node childNode)
		{
		    if (_children.Remove(childNode)) {				
				//notify all of nodes : they've added to parent node
				childNode.ForEach(delegate(Node node) {
					node.NotifyNodeRemovedFromDomain();
				});
				//now we can null parent :)
				childNode._parent = null;
				return true;
			}
		    return false;
		}

	    ///<summary>Removes all children</summary>
		public void RemoveAllChildren() {
			foreach (Node node in _children.ToArray()) {
				RemoveChild(node);
			}
		}

		/// <summary>
		/// Executes callback for each of node in hierarchy down starting current one (including all of its children).
		/// </summary>
		/// <param name="callback">The callback to invoke for each of node.</param>
		public void ForEach(NodeCallbackHandler callback) {
			if (null == callback) throw new ArgumentNullException("callback");

			//call for this node only
			callback(this);

			//now the same for children
			foreach (Node node in _children) {
				node.ForEach(callback);
			}
		}

		#endregion

		#region Element Traversing

		/// <summary>
		/// Selects the first node with specified id. Element scope: children of current node, their children, etc...
		/// </summary>
		/// <param name="nodeId">The node id.</param>
		/// <returns><see cref="Element"/> with specified id if exists or <c>null</c>s</returns>
		public Node SelectNodeById(string nodeId) {
			NodeList<Node> nodes = SelectNodes<Node>(obj => nodeId == obj.Id, false, true);
			if (nodes.Count > 0) {
				return nodes[0];
			}
		    return null;
		}

		/// <summary>
		/// Selects the nodes collection with nodes matching type criteria.
		/// </summary>
		/// <typeparam name="T">Type of node to search</typeparam>
		/// <param name="exactTypeMatch">if set to <c>true</c> then only nodes with exact type match will be found; otherwise all of nodes which can be casted to specified type will be returned.</param>
		/// <param name="recursive">if set to <c>true</c> then scope of search will include children of children, etc.</param>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>(bool exactTypeMatch, bool recursive) where T:Node {
			return SelectNodes((T obj) => true, exactTypeMatch, recursive);
		}

		/// <summary>
		/// Selects the nodes collection with nodes exactly matching type criteria.
		/// </summary>
		/// <typeparam name="T">Type of node to search</typeparam>
		/// <param name="recursive">if set to <c>true</c> then scope of search will include children of children, etc.</param>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>(bool recursive) where T : Node {
			return SelectNodes<T>(true, recursive);
		}

		/// <summary>
		/// Selects the nodes collection with nodes exactly matching type criteria recursively.
		/// </summary>
		/// <typeparam name="T">Type of node to search</typeparam>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>() where T : Node {
			return SelectNodes<T>(true, true);
		}

		/// <summary>
		/// Selects the nodes collection with nodes matching type and class name criteria.
		/// </summary>
		/// <typeparam name="T">Type of node to search only</typeparam>
		/// <param name="className">Name of the class to find.</param>
		/// <param name="exactTypeMatch">if set to <c>true</c> then only nodes with exact type match will be found; otherwise all of nodes which can be casted to specified type will be returned.</param>
		/// <param name="recursive">if set to <c>true</c> then scope of search will include children of children, etc.</param>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>(string className, bool exactTypeMatch, bool recursive) where T : Node {
			return SelectNodes((T obj) => className == obj.Class, exactTypeMatch, recursive);
		}

		/// <summary>
		/// Selects the nodes collection with nodes exactly matching type and class name criteria.
		/// </summary>
		/// <typeparam name="T">Type of node to search only</typeparam>
		/// <param name="className">Name of the class to find.</param>
		/// <param name="recursive">if set to <c>true</c> then scope of search will include children of children, etc.</param>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>(string className, bool recursive) where T : Node {
			return SelectNodes<T>(className, true, recursive);
		}

		/// <summary>
		/// Selects the nodes collection with nodes exactly matching type and class name criteria recursively.
		/// </summary>
		/// <typeparam name="T">Type of node to search only</typeparam>
		/// <param name="className">Name of the class to find.</param>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>(string className) where T : Node {
			return SelectNodes<T>(className, true, true);
		}

		/// <summary>
		/// Selects the nodes collection with nodes matching type and specified predicate rule.
		/// </summary>
		/// <typeparam name="T">Type of node to search only</typeparam>
		/// <param name="rule">The rule to check.</param>
		/// <param name="exactTypeMatch">if set to <c>true</c> then only nodes with exact type match will be found; otherwise all of nodes which can be casted to specified type will be returned.</param>
		/// <param name="recursive">if set to <c>true</c> then scope of search will include children of children, etc.</param>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>(Predicate<T> rule, bool exactTypeMatch, bool recursive) where T : Node {
			NodeList<T> result = new NodeList<T>();
			SelectNodes(this, rule, exactTypeMatch, recursive, result);
			return result;
		}

		/// <summary>
		/// Selects the nodes collection with nodes exactly matching type and specified predicate rule.
		/// </summary>
		/// <typeparam name="T">Type of node to search only</typeparam>
		/// <param name="rule">The rule to check.</param>
		/// <param name="recursive">if set to <c>true</c> then scope of search will include children of children, etc.</param>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>(Predicate<T> rule, bool recursive) where T : Node {
			return SelectNodes<T>(rule, true, recursive);
		}

		/// <summary>
		/// Selects the nodes collection with nodes exactly matching type and specified predicate rule recursively.
		/// </summary>
		/// <typeparam name="T">Type of node to search only</typeparam>
		/// <param name="rule">The rule to check.</param>
		/// <param name="exactTypeMatch">if set to <c>true</c> then only nodes with exact type match will be found; otherwise all of nodes which can be casted to specified type will be returned.</param>
		/// <param name="recursive">if set to <c>true</c> then scope of search will include children of children, etc.</param>
		/// <returns>Collection of nodes matching criteria</returns>
		public NodeList<T> SelectNodes<T>(Predicate<T> rule) where T : Node {
			return SelectNodes<T>(rule, true, true);
		}

		/// <summary>
		/// Selects the nodes by rule filling node collection if match. 
		/// </summary>
		/// <typeparam name="T">Type of node to search only</typeparam>
		/// <param name="containerNode">The search scope node.</param>
		/// <param name="rule">The rule to check.</param>
		/// <param name="exactTypeMatch">if set to <c>true</c> then only nodes with exact type match will be found; otherwise all of nodes which can be casted to specified type will be returned.</param>
		/// <param name="recursive">if set to <c>true</c> then scope of search will include children of children, etc.</param>
		/// <param name="result">The result.</param>
		private static void SelectNodes<T>(Node containerNode, Predicate<T> rule, bool exactTypeMatch, bool recursive, NodeList<T> result) where T:Node{
			Type lookupType = typeof(T);

			//iterate over children
			foreach (Node node in containerNode.Children) {
				Type nodeType = node.GetType();

				//check type condition
				if (exactTypeMatch && nodeType.Equals(lookupType) || lookupType.IsAssignableFrom(nodeType)) {
					T typedElement = (T)node;
					//check user condition
					if (rule(typedElement)) {
						result.Add(typedElement);
					}
				}

				//check recursive lookup
				if (recursive && node.HasChildren) {
					SelectNodes(node, rule, exactTypeMatch, true, result);
				}
			}
		}

		#endregion

		#region Element Geometry Positioning

		/// <summary>
		/// Gets or sets the location of node relative to its parent.
		/// </summary>
		/// <value>The location of node.</value>
		public virtual Vector2 Location {
			get { return _location; }
			set { _location = value; ComputeTransform(); }
		}

	    /// <summary>
	    /// Gets or sets the X component of location of node relative to its parent.
	    /// </summary>
	    /// <value>The X component of location</value>
	    public virtual float LocationX
	    {
            get { return _location.X; }
            set
            {
                _location.X = value;
                ComputeTransform();
            }
	    }

        /// <summary>
        /// Gets or sets the Y component of location of node relative to its parent.
        /// </summary>
        /// <value>The Y component of location</value>
	    public virtual float LocationY
	    {
            get { return _location.Y; }
            set
            {
                _location.Y = value;
                ComputeTransform();
            }
	    }

		/// <summary>
		/// Gets or sets the origin point offset which is relative to location (like a correction offset).
		/// </summary>
		/// <value>The origin point offset of node.</value>
		public virtual Vector2 Origin {
			get { return _origin; }
			set { _origin = value; ComputeTransform(); }
		}

		/// <summary>
		/// Gets or sets the scale of node against it origin point (node center).
		/// </summary>
		/// <value>The scale of node against it origin point.</value>
		public virtual Vector2 Scale {
			get { return _scale; }
			set { _scale = value; ComputeTransform(); }
		}

		/// <summary>
		/// Gets or sets the rotation of node around its origin point.
		/// </summary>
		/// <value>The node rotation around its origin point.</value>
		public virtual float Rotation {
			get { return _rotation; }
			set { _rotation = value; ComputeTransform(); }
		}

		/// <summary>
		/// Transformation of current node relative to parent one
		/// </summary>
		/// <value>The node transform.</value>
		public Transform2D Transform {
			get { return _transform; }
		}

		/// <summary>
		/// Transformation of current node relative to global screen space. You can use it for transforming local values to screen or reverse - screen to local
		/// </summary>
		/// <value>The node screen transform.</value>
		public Transform2D ScreenTransform {
			get {
				Transform2D transform = _transform;
				Node parent = Parent;
				while (parent != null) {
					transform = transform * parent.Transform;
					parent = parent.Parent;
				}
				return transform;
			}
		}

		/// <summary>
		/// Updates transform matrix based on all of transformations: scale, rotation and location
		/// </summary>
		private void ComputeTransform() {
			//TODO Investigate and optimize!

			Transform2D origin, revOrigin, scale, rotation, translation;
			Transform2D.CreateScaling(ref _scale, out scale);
			Transform2D.CreateRotation(_rotation, out rotation);
			Transform2D.CreateTranslation(ref _origin, out origin);
			Transform2D.CreateTranslation(ref _location, out translation);
			
			//make reverse origin
			revOrigin.M11 = origin.M11;
			revOrigin.M12 = origin.M12;
			revOrigin.M21 = origin.M21;
			revOrigin.M22 = origin.M22;
			revOrigin.TX = -origin.TX;
			revOrigin.TY = -origin.TY;

			_transform = revOrigin * scale * rotation * translation * origin;
		}

		#endregion

		#region Common States

		/// <summary>
		/// Gets or sets the tag object. It can be any type of object which helps to identify this node or use for any purposes.
		/// </summary>
		/// <value>The tag object.</value>
		public object Tag {
			get;
			set;
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is visibile.
		/// Invisible nodes doesn't receive any messages from input. Also such nodes are not rendered.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is visible; otherwise, <c>false</c>.
		/// </value>
		public bool IsVisible {
			get { return _visible; }
			set { _visible = value; }
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is transient.
		/// Transient nodes is not click targets, they are abolsutely transparent for mouse.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is transient; otherwise, <c>false</c>.
		/// </value>
		public bool IsTransient {
			get { return _transient; }
			set { _transient = value; }
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance is enabled.
		/// Enabled means node can receive focus, input mouse/keyboard events. Mouse doesn't click through disabled nodes
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is enabled; otherwise, <c>false</c>.
		/// </value>
		public bool IsEnabled {
			get { return _enabled; }
			set {
				if (_enabled != value) {
					_enabled = value;
					Style.Discard();
					//remove intermediate states if node becomes disabled
					if (!value) {
						IsHovered = false;
						IsPressed = false;
						IsFocused = false;
					}
				}
			}
		}

		/// <summary>
		/// Gets or sets flag that defines can node gain input focus and receive OnBlur event after focus is lost
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is focusable; otherwise, <c>false</c>.
		/// </value>
		public bool IsFocusable {
			get { return _focusable; }
			set { _focusable = value; }
		}

		/// <summary>
		/// Gets the cursor to show over this node.
		/// </summary>
		/// <value>The game cursor to show over the node.</value>
		public GameCursor Cursor {
			get {
				return Style.Get<GameCursor>(Styles.Cursor) ?? GameCursor.Default;
			}
		}

		/// <summary>
		/// If this property is true then event bubbling will occur for this node.
		/// Parent node will receive these events too
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance will bubble events; otherwise, <c>false</c>.
		/// </value>
		public bool IsEventBubblingEnabled {
			get { return _eventBubblingEnabled; }
			set { _eventBubblingEnabled = value; }
		}

		/// <summary>
		/// Gets a value indicating whether this node is hovered.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this node is hovered; otherwise, <c>false</c>.
		/// </value>
		public bool IsHovered {
			get { return _hovered; }
			protected set {
				if (_hovered != value) {
					_hovered = value;
					Style.Discard();
				}
			}
		}

		/// <summary>
		/// Gets a value indicating whether this node is focused.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this node is focused; otherwise, <c>false</c>.
		/// </value>
		public bool IsFocused {
			get { return _focused; }
			protected set {
				if (_focused != value) {
					_focused = value;
					Style.Discard();
				}
			}
		}

		/// <summary>
		/// Gets a value indicating whether this node is pressed.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this node is pressed; otherwise, <c>false</c>.
		/// </value>
		public bool IsPressed {
			get { return _pressed; }
			protected set {
				if (_pressed != value) {
					_pressed = value;
					Style.Discard();
				}
			}
		}

		#endregion

		#region ITransform Members

		/// <summary>
		/// Gets the transform which represents this node relative to parent.
		/// </summary>
		/// <param name="transform">The transform to fill.</param>
		public void GetTransform(out Transform2D transform) {
			transform = _transform;
		}

		#endregion

		#region Element Picking

		/// <summary>
		/// Gets the bounding box of node in its local coordinates.
		/// </summary>
		/// <value>The bounding box of node in its local coordinates.</value>
		public virtual Rect BoundingBox {
			get { return Rect.Empty; }
		}

		/// <summary>
		/// Checks is point (in local units) inside of node
		/// </summary>
		/// <param name="point">The point in local units.</param>
		/// <returns>
		/// 	<c>true</c> if the specified node contains point; otherwise, <c>false</c>.
		/// </returns>
		public virtual bool ContainsPoint(Vector2 point) {
			return BoundingBox.Contains(point);
		}

		/// <summary>
		/// Looking for topmost node starting this one at specified outer point and returns it
		/// </summary>
		/// <param name="point">The point in node parent coord space.</param>
		/// <returns><see cref="Element"/> instance if some node under the point was found; otherwise <c>null</c></returns>
		public Node FindElementAtPoint(Vector2 point) {
			if (IsVisible) {
				Vector2 localPoint = _transform.ReverseMultiply(point);
				//try to look between child nodes
				for (int n = ChildrenCount - 1; n >= 0; --n) {
					Node innerMatch = this[n].FindElementAtPoint(localPoint);
					if (null != innerMatch) {
						return innerMatch;
					}
				}
				//check self if no child nodes were found
				return !IsTransient && ContainsPoint(localPoint) ? this : null;
			} else {
				return null;
			}
		}

		#endregion

		#region Element Update

		/// <summary>
		/// Update node for this frame time change
		/// </summary>
		/// <param name="timeDelta">The time delta in seconds.</param>
		public virtual void Update(float timeDelta) {
		}

		#endregion

		#region Element Drawing

		/// <summary>
		/// Draws the content of this node and all of its children. Specified canvas should be used to draw node content. 
		/// You may override this method in some rare cases.
		/// </summary>
		/// <param name="canvas">The canvas to use for node drawing.</param>
		public virtual void DrawContent(Canvas2D canvas) {
			canvas.PushTransform();
			canvas.ApplyTransformBefore(ref _transform);

			//all content inside is drawn relatively to this node origin point
			Draw(canvas);
			DrawChildren(canvas);

			canvas.PopTransform();
		}

		/// <summary>
		/// Draws the own node content. This method have to be overridden for each of node type.
		/// </summary>
		/// <param name="canvas">The canvas to use for node drawing.</param>
		protected virtual void Draw(Canvas2D canvas) {
			;
		}

		/// <summary>
		/// Draws node's children. You may override this method to provide custom implementation of children drawing composition. E.g. using render target, clipping or else.
		/// </summary>
		/// <param name="canvas">The canvas to use for children node drawing.</param>
		protected virtual void DrawChildren(Canvas2D canvas) {
			foreach (Node node in Children) {
				if (node.IsVisible) {
					node.DrawContent(canvas);
				}
			}
		}

		#endregion

		#region Event Processors

		/// <summary>
		/// Processes the mouse move event.
		/// </summary>
		/// <param name="eventInfo">The mouse event info.</param>
		protected internal virtual void ProcessMouseMove(MouseEventInfo eventInfo) {
			if (null != OnMouseMove) {
				OnMouseMove(this, eventInfo);
			}
		}

		/// <summary>
		/// Processes the mouse over event.
		/// </summary>
		/// <param name="eventInfo">The mouse event info.</param>
		protected internal virtual void ProcessMouseOver(MouseEventInfo eventInfo) {
			if (null != OnMouseOver) {
				OnMouseOver(this, eventInfo);
			}
			//set node hovered
			IsHovered = true;
		}

		/// <summary>
		/// Processes the mouse out event.
		/// </summary>
		/// <param name="eventInfo">The mouse event info.</param>
		protected internal virtual void ProcessMouseOut(MouseEventInfo eventInfo) {
			if (null != OnMouseOut) {
				OnMouseOut(this, eventInfo);
			}
			//remove hovered status
			IsHovered = false;
		}

		/// <summary>
		/// Processes the mouse down event.
		/// </summary>
		/// <param name="eventInfo">The mouse event info.</param>
		protected internal virtual void ProcessMouseDown(MouseEventInfo eventInfo) {
			if (null != OnMouseDown) {
				OnMouseDown(this, eventInfo);
			}
			//set pressed if left button was pressed
			if (eventInfo.Button == MouseButton.Left) {
				IsPressed = true;
			}
		}

		/// <summary>
		/// Processes the mouse up event.
		/// </summary>
		/// <param name="eventInfo">The mouse event info.</param>
		protected internal virtual void ProcessMouseUp(MouseEventInfo eventInfo) {
			if (null != OnMouseUp) {
				OnMouseUp(this, eventInfo);
			}
			//set pressed if left button was pressed
			if (eventInfo.Button == MouseButton.Left) {
				IsPressed = false;
			}
		}

		/// <summary>
		/// Processes the click event.
		/// </summary>
		/// <param name="eventInfo">The mouse event info.</param>
		protected internal virtual void ProcessClick(MouseEventInfo eventInfo) {
			if (null != OnClick) {
				OnClick(this, eventInfo);
			}
		}

		/// <summary>
		/// Processes the double click event.
		/// </summary>
		/// <param name="eventInfo">The mouse event info.</param>
		protected internal virtual void ProcessDoubleClick(MouseEventInfo eventInfo) {
			if (null != OnDoubleClick) {
				OnDoubleClick(this, eventInfo);
			}
		}

		/// <summary>
		/// Processes the key down event.
		/// </summary>
		/// <param name="eventInfo">The keyboard event info.</param>		
		protected internal virtual void ProcessKeyDown(KeyboardEventInfo eventInfo) {
			if (null != OnKeyDown) {
				OnKeyDown(this, eventInfo);
			}
		}

		/// <summary>
		/// Processes the key up event.
		/// </summary>
		/// <param name="eventInfo">The keyboard event info.</param>
		protected internal virtual void ProcessKeyUp(KeyboardEventInfo eventInfo) {
			if (null != OnKeyUp) {
				OnKeyUp(this, eventInfo);
			}
		}

		/// <summary>
		/// Processes the char input event.
		/// </summary>
		/// <param name="eventInfo">The keyboard event info.</param>
		protected internal virtual void ProcessChar(KeyboardEventInfo eventInfo) {
			if (null != OnChar) {
				OnChar(this, eventInfo);
			}
		}

		/// <summary>
		/// Processes the gaining of input focus.
		/// </summary>
		protected internal virtual void ProcessGainFocus() {
			IsFocused = true;

			if (null != OnFocus) {
				OnFocus(this);
			}
		}

		/// <summary>
		/// Processes the loosing of input focus.
		/// </summary>
		protected internal virtual void ProcessLooseFocus() {
			IsFocused = false;

			if (null != OnBlur) {
				OnBlur(this);
			}
		}

		#endregion

		#region Element Events

		/// <summary>
		/// Occurs when mouse comes into node area.
		/// </summary>
		public event MouseGraphEventHandler OnMouseOver;
		
		/// <summary>
		/// Occurs when mouse leaves node area.
		/// </summary>
		public event MouseGraphEventHandler OnMouseOut;

		/// <summary>
		/// Occurs when mouse cursor moves in node area.
		/// </summary>
		public event MouseGraphEventHandler OnMouseMove;

		/// <summary>
		/// Occurs when when mouse button is pressed down being in node area.
		/// </summary>
		public event MouseGraphEventHandler OnMouseDown;

		/// <summary>
		/// Occurs when when mouse button is released after was down in node area.
		/// </summary>
		public event MouseGraphEventHandler OnMouseUp;

		/// <summary>
		/// Occurs when click happened in this node area.
		/// </summary>
		public event MouseGraphEventHandler OnClick;

		/// <summary>
		/// Occurs when double click happened in this node area.
		/// </summary>
		public event MouseGraphEventHandler OnDoubleClick;

		/// <summary>
		/// Occurs when some key was pressed down when this node is focused.
		/// </summary>
		public event KeyboardGraphEventHandler OnKeyDown;

		/// <summary>
		/// Occurs when some key was released when this node is focused.
		/// </summary>
		public event KeyboardGraphEventHandler OnKeyUp;

		/// <summary>
		/// Occurs when some input char was encoded when this node is focused.
		/// </summary>
		public event KeyboardGraphEventHandler OnChar;

		/// <summary>
		/// Occurs when node gains input focus.
		/// </summary>
		public event GraphEventHandler OnFocus;

		/// <summary>
		/// Occurs when node looses its input focus.
		/// </summary>
		public event GraphEventHandler OnBlur;

		#endregion

		#region Standard Overrides

		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this node instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this node instance.
		/// </returns>
		public override string ToString() {
			return string.Format("{{{0}, Location='{1}, {2}', ChildrenCount={3}, ClassName='{4}', Id='{5}'}}'", GetType().FullName, LocationX, LocationY, ChildrenCount, Class ?? "<none>", Id ?? "<none>");
		}
		#endregion
	}
}
