using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Aga.Controls.Tree;
using Aga.Controls.Tree.NodeControls;
using MySQL.Grt;

namespace MySQL.Grt
{
	/// <summary>
	/// A generic GRT tree model class implementing ITreeModel from the TreeViewAdv control
	/// </summary>
	public class GrtListModel : ITreeModel
	{
		/// <summary>
		/// The tree view control this model is used for
		/// </summary>
		protected TreeViewAdv listView;

		/// <summary>
		/// The GRT tree this model is representing
		/// </summary>
		protected MySQL.Grt.ListModel grtList;

		/// <summary>
		/// The top node if any, otherwise null
		/// </summary>
		protected GrtTreeNode topNode = null;

		/// <summary>
		/// The NodeIcon Node Control that displays the icon
		/// </summary>
		protected NodeIcon nodeIcon = null;

		/// <summary>
		/// Hide the default constructor
		/// </summary>
		private GrtListModel()
		{
		}

		/// <summary>
		/// The constructor that has to be overwritten in the derived model classes
		/// </summary>
		/// <param name="TreeView">The TreeViewAdv control this model is used for</param>
		/// <param name="GrtList">The GRT list this model is representing</param>
		protected GrtListModel(TreeViewAdv ListView, MySQL.Grt.ListModel GrtList)
			: this()
		{
			grtList = GrtList;
			listView = ListView;	
		}

		protected GrtListModel(TreeViewAdv ListView, MySQL.Grt.ListModel GrtList, NodeIcon NodeIcon)
			: this(ListView, GrtList)
		{
			nodeIcon = NodeIcon;

			// Ensure that the VirtualMode is enabled
			nodeIcon.VirtualMode = true;

			// Assign virtual value events for displaying and processing the edited value content
			nodeIcon.ValueNeeded += new EventHandler<NodeControlValueEventArgs>(IconNeeded);
		}

		/// <summary>
		/// Virtual function that needs to be overwritten in derived model classes. 
		/// Has to return a list of child nodes for the given path
		/// </summary>
		/// <param name="treePath">The path of the parent node</param>
		/// <returns>The list of child nodes for the given parent path node</returns>
		public virtual System.Collections.IEnumerable GetChildren(TreePath treePath)
		{
			return null;
		}

		/// <summary>
		/// As this is a list, every node is a leaf
		/// </summary>
		/// <param name="treePath">The path of the node</param>
		/// <returns>False if the node can be expanded, true if the node is a leaf</returns>
		public virtual bool IsLeaf(TreePath treePath)
		{
			return true;
		}

		#region Events
		public event EventHandler<TreeModelEventArgs> NodesChanged;
		internal void OnNodesChanged(TreeModelEventArgs args)
		{
			if (NodesChanged != null)
				NodesChanged(this, args);
		}

		public event EventHandler<TreePathEventArgs> StructureChanged;
		public void OnStructureChanged(TreePathEventArgs args)
		{
			if (StructureChanged != null)
				StructureChanged(this, args);
		}

		public event EventHandler<TreeModelEventArgs> NodesInserted;
		internal void OnNodeInserted(Node parent, int index, Node node)
		{
			if (NodesInserted != null)
			{
				TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new int[] { index }, new object[] { node });
				NodesInserted(this, args);
			}
		}

		public event EventHandler<TreeModelEventArgs> NodesRemoved;
		internal void OnNodeRemoved(Node parent, int index, Node node)
		{
			if (NodesRemoved != null)
			{
				TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new int[] { index }, new object[] { node });
				NodesRemoved(this, args);
			}
		}
		#endregion

		#region Properties
		public MySQL.Grt.ListModel GrtList
		{
			get { return grtList; }
		}

		public TreeViewAdv ListView
		{
			get { return listView; }
		}
		#endregion

		/// <summary>
		/// Returns the path of the given node
		/// </summary>
		/// <param name="node">Node of interest</param>
		/// <returns>The path to the given node</returns>
		public virtual TreePath GetPath(Node node)
		{
			if (node == topNode)
				return TreePath.Empty;
			else
			{
				Stack<object> stack = new Stack<object>();
				while (node != topNode)
				{
					stack.Push(node);
					node = node.Parent;
				}
				return new TreePath(stack.ToArray());
			}
		}

		/// <summary>
		/// Refreshes the tree
		/// </summary>
		public virtual void RefreshModel()
		{
			grtList.refresh();
			OnStructureChanged(new TreePathEventArgs());
		}

		/// <summary>
		/// Event handler that gets the icon for the node
		/// </summary>
		/// <param name="sender">The object triggering the event</param>
		/// <param name="e">The event parameter</param>
		private void IconNeeded(object sender, NodeControlValueEventArgs e)
		{
			if (e.Node != null && e.Node.Tag != null)
			{
				// Use the GRT Icon manager to get the correct icon
				GrtListNode node = e.Node.Tag as GrtListNode;

				if (node != null)
				{
					int iconId = GrtList.get_field_icon(node.NodeId, 0, IconSize.Icon16);
					Image icon = GrtIconManager.get_instance().get_icon(iconId);

					if (icon != null)
						e.Value = icon;
				}
			}
		}

		/// <summary>
		/// Detaches the events handlers from the tree
		/// </summary>
		public virtual void DetachEvents()
		{
			// remove virtual value events
			if (nodeIcon != null)
				nodeIcon.ValueNeeded -= IconNeeded;
		}
	}
}
