using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Configuration.Assemblies;
using System.Threading;
using System.Xml.Serialization;
using System.Xml;

using CategoryTheory;
using MathGraph;

namespace DiagramUI
{
	/// <summary>
	/// The base class of named components: object components
	/// and arrow components
	/// </summary>
	[Serializable()]
	public abstract class NamedComponent : Panel, ISerializable, INamedComponent
	{
		
		#region Fields
		
		/// <summary>
		/// The name editor rectangle
		/// </summary>
		protected Rectangle editorRect;

		/// <summary>
		/// The editor of component caption
		/// </summary>
		protected TextBox captionEditor;

		/// <summary>
		/// The position of the component image
		/// </summary>
		protected PointF imagePosition;

		/// <summary>
		/// The name of the component
		/// </summary>
		protected string name;


		/// <summary>
		/// String kind
		/// </summary>
		protected string stringKind;

		/// <summary>
		/// The button associated with component
		/// </summary>
		protected PaletteButton button;

		/// <summary>
		/// The font of caption label
		/// </summary>
		protected Font font;

		/// <summary>
		/// The brush for caption drawing
		/// </summary>
		protected Brush textBrush;

		/// <summary>
		/// The form for component properties edining
		/// </summary>
		protected Form form;

		/// <summary>
		/// The kind of the component
		/// </summary>
		protected int kind = -1;

		/// <summary>
		/// The type of the component
		/// </summary>
		protected string type;

		/// <summary>
		/// The selection flag
		/// </summary>
		protected bool selected;

		/// <summary>
		/// Tree nodes
		/// </summary>
		protected ArrayList nodes = new ArrayList();

		/// <summary>
		/// The node
		/// </summary>
		protected TreeNode node;

		#endregion

		#region Constructors / Destructor

		/// <summary>
		/// Constructor
		/// </summary>
		protected NamedComponent()
		{
		}


		/// <summary>
		/// Constructor from correspond button
		/// </summary>
		/// <param name="button">the button</param>
		protected NamedComponent(PaletteButton button)
		{
			this.button = button;
			this.kind = button.Kind;
			this.type = button.Type;
			name = "";
		}

		/// <summary>
		/// Serialization constructor
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		public NamedComponent(SerializationInfo info, StreamingContext context)
		{
			kind = (int)info.GetValue("Kind", typeof(int));
			type = (string)info.GetValue("Type", typeof(string));
			name = (string)info.GetValue("Name", typeof(string));

		}
		/// <summary>
		/// Destructor
		/// </summary>
		~NamedComponent()
		{
			if (form != null)
			{
				form.Dispose();
				form = null;
				GC.Collect();
			}
		}

		#endregion

		#region ISerializable Members

		/// <summary>
		/// ISerializable interface implementation
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Kind", kind);
			info.AddValue("Type", type);
			info.AddValue("Name", name);
		}

		#endregion

		#region INamedComponent Members

		new public virtual string Name
		{
			get
			{
				return ComponentName;
			}
		}

		public void Remove()
		{
			
		}

		public virtual int X
		{
			get
			{
				return Left;
			}
			set
			{
				Left = value;
			}
		}

		public virtual int Y
		{
			get
			{
				return Top;
			}
			set
			{
				Top = value;
			}
		}

		IDesktop INamedComponent.Desktop
		{
			get
			{
				return Parent as IDesktop;
			}
			set
			{
			}
		}

		string INamedComponent.Kind
		{
			get
			{
				return stringKind;
			}
		}

		/// <summary>
		/// Order on desktop
		/// </summary>
		public int Ord
		{
			get
			{
				Control c = base.Parent;
				return c.Controls.GetChildIndex(this);
			}
			set
			{
				Control c = base.Parent;
				c.Controls.SetChildIndex(this, value);
			}
		}



		/// <summary>
		/// The type of the component
		/// </summary>
		public virtual string Type
		{
			get
			{
				return type;
			}
		}
		


		/// <summary>
		/// Parent component
		/// </summary>
		INamedComponent INamedComponent.Parent
		{
			get
			{
				return null;
			}
			set
			{
				throw new Exception("You should not set parent to UI component");
			}
		}

		public INamedComponent GetRoot(IDesktop desktop)
		{
			return PureObjectLabel.GetRoot(this, desktop);
		}


		/// <summary>
		/// Gets component name relatively desktop
		/// </summary>
		/// <param name="desktop">The desktop</param>
		/// <returns>Relalive name</returns>
		public string GetName(IDesktop desktop)
		{
			return PureObjectLabel.GetName(this, desktop);
		}

		/// <summary>
		/// Gets name relatively root
		/// </summary>
		public string RootName
		{
			get
			{
				return GetName(Desktop.Root);
			}
		}

		/// <summary>
		/// Root control
		/// </summary>
		public INamedComponent Root
		{
			get
			{
				return PureObjectLabel.GetRoot(this);
			}
		}

		#endregion

		#region Specific Members


		/// <summary>
		/// Gets root UI desktop of component
		/// </summary>
		/// <param name="component">The component</param>
		/// <returns>The desktop</returns>
		public static PanelDesktop GetDesktop(INamedComponent component)
		{
			if (component.Desktop is PanelDesktop)
			{
				return component.Desktop as PanelDesktop;
			}
			return GetDesktop(component.Parent);
		}


		/// <summary>
		/// Gets image of component
		/// </summary>
		/// <param name="component">The component</param>
		/// <returns>The image</returns>
		public static Image GetImage(INamedComponent component)
		{
			PaletteButton button = GetButton(component);
			return button.ButtonImage;
		}


		/// <summary>
		/// Gets component button
		/// </summary>
		/// <param name="component">Component</param>
		/// <returns>The component button</returns>
		public static PaletteButton GetButton(INamedComponent component)
		{
			PanelDesktop desktop = GetDesktop(component);
			return desktop.Tools.FindButton(component);
		}


		/// <summary>
		/// Gets image number
		/// </summary>
		/// <param name="component">Component</param>
		/// <returns>The image number</returns>
		public static int GetImageNumber(INamedComponent component)
		{
			PaletteButton button = GetButton(component);
			return button.ImageNumber;
		}



		/// <summary>
		/// Gets tooltip of component
		/// </summary>
		/// <param name="component">The component</param>
		/// <returns>The tooltip</returns>
		public static string GetToolTip(INamedComponent component)
		{
			PaletteButton button = GetButton(component);
			return button.ToolTipText;
		}


		/// <summary>
		/// Removes form
		/// </summary>
		/// <param name="component">Component for form removing</param>
/*		public static void RemoveForm(INamedComponent component)
		{
			removeForm(component);
		}
*/

		/// <summary>
		/// Editor of properties
		/// </summary>
		public Form Form
		{
			get
			{
				return form;
			}
		}

		/// <summary>
		/// The name of the component
		/// </summary>
		public virtual string ComponentName
		{
			get
			{
				return name;
			}
			set
			{
                if (value == null)
                {
                    return;
                }
				name = value;
                if (node != null)
                {
                    node.Text = value;
                }
			}
		}


		/// <summary>
		/// Adds node to tree
		/// </summary>
		/// <param name="node">The node</param>
		public void AddNode(NamedNode node)
		{
			nodes.Add(node);
		}


		/// <summary>
		/// The associated button
		/// </summary>
		public PaletteButton ComponentButton
		{
			get
			{
				return button;
			}
			set
			{
				button = value;
			}
		}

		/// <summary>
		/// The node
		/// </summary>
		public TreeNode Node
		{
			get
			{
				return node;
			}
			set
			{
				node = value;
			}
		}

		/// <summary>
		/// The selection indicator
		/// </summary>
		public abstract bool Selected
		{
			get;
			set;
		}
		
		/// <summary>
		/// The kind of the component
		/// </summary>
		public virtual int Kind
		{
			get
			{
				return kind;
			}
		}

		
		/// <summary>
		/// Refreshes the property editor
		/// </summary>
		public void RefreshForm()
		{
			if (form != null)
			{
				form.Refresh();
			}
		}
		
		/// <summary>
		/// The desktop
		/// </summary>
		public virtual PanelDesktop Desktop
		{
			get
			{
				return (PanelDesktop)Parent;
			}
			set
			{
			}
		}

		/// <summary>
		/// Sets name
		/// </summary>
		/// <param name="name">The name</param>
		public void SetName(string name)
		{
			this.name = name;
			updateNodes();
			UpdateForms();
			Refresh();
		}

		/// <summary>
		/// Shows form
		/// </summary>
		public void ShowForm()
		{
			try
			{
				if (form == null)
				{
					form = Desktop.Tools.Factory.CreateForm(this);
				}
				if (form != null)
				{
                    if (form.IsDisposed)
                    {
                        form = Desktop.Tools.Factory.CreateForm(this);
                    }
					form.Show();
					form.BringToFront();
					form.Activate();
					form.Focus();
					form.Show();
				}
			}
			catch (Exception e)
			{
				Desktop.Tools.Factory.ShowError(e);
			}
		}



		

		/// <summary>
		/// Removes itself from desktop
		/// </summary>
		public void RemoveFromComponent()
		{
			Desktop.Controls.Remove(this);
		}

		/// <summary>
		/// Removes properties editor
		/// </summary>
		/// <param name="dispose">The "should dispose" flag</param>
		public void RemoveForm()
		{
			if (form != null)
			{
                try
                {
                    if (!form.IsDisposed)
                    {
                        form.Dispose();
                    }
                }
                catch (Exception ex)
                {
                }
				form = null;
				GC.Collect();
			}
		}

		/// <summary>
		/// Updates property editor
		/// </summary>
		public void UpdateForm()
		{
			if (form == null)
			{
				return;
			}
			if (!(form is IUpdatableForm))
			{
				return;
			}
			IUpdatableForm updatable = form as IUpdatableForm;
			updatable.UpdateFormUI();
		}

		/// <summary>
		/// The properties editor
		/// </summary>
		public Form LabelForm
		{
			get
			{
				return form;
			}
		}

		public void ShowDialog(Form form)
		{
			Form f = Desktop.Tools.Factory.CreateForm(this);
			f.ShowDialog(form);
		}
		

		/// <summary>
		/// Updates forms
		/// </summary>
		public abstract void UpdateForms();

		/// <summary>
		/// The rectangle of the name editor
		/// </summary>
		protected Rectangle EditorRectangle
		{
			get
			{
				return editorRect;
			}
			set
			{
				editorRect = value;
			}
		}




		/// <summary>
		/// Event handlers initialization
		/// </summary>
		protected virtual void initNamedEventHandlers()
		{
			captionEditor = new TextBox();
			Controls.Add(captionEditor);
			font = (Font)captionEditor.Font.Clone();
			MouseDown += new MouseEventHandler(namedComponentMouseEventHandler) + 
				new MouseEventHandler(selectMouseClick);
			captionEditor.KeyUp += new KeyEventHandler(namedComponentKeyEventHandler);
			Paint += new PaintEventHandler(imagedPaintEventHandler);
			imagePosition = new PointF((Width - button.ButtonImage.Width) / 2, 
				(editorRect.Height + Height - button.ButtonImage.Height) / 2);
			MouseUp += new MouseEventHandler(showForm);
		}

		/// <summary>
		/// The key event handler
		/// </summary>
		/// <param name="sender">The sender</param>
		/// <param name="e">The event arguments</param>
		protected void namedComponentKeyEventHandler(object sender, KeyEventArgs e)
		{
			if (e.KeyData == Keys.Cancel)
			{
				captionEditor.Visible = false;
				Refresh();
				return;
			}
			if (e.KeyData == Keys.Enter)
			{
				name = captionEditor.Text;
				captionEditor.Visible = false;
				updateNodes();
				UpdateForms();
				Refresh();
			}
		}

		/// <summary>
		/// The selection event handler
		/// </summary>
		/// <param name="sender">The sender</param>
		/// <param name="e">The event arguments</param>
		protected void selectMouseClick(object sender, MouseEventArgs e)
		{
			if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
			{
				Selected = !Selected;
			}
		}

		/// <summary>
		/// The name editor event handler
		/// </summary>
		/// <param name="sender">The sender</param>
		/// <param name="e">The event arguments</param>
		protected void namedComponentMouseEventHandler(object sender, MouseEventArgs e)
		{
			if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
			{
				return;
			}
			if (e.Button == MouseButtons.Right)
			{
				return;
			}
			if (!editorRect.Contains(e.X, e.Y))
			{
				if (captionEditor.Visible)
				{
					name = captionEditor.Text;
					updateNodes();
					captionEditor.Visible = false;
					UpdateForms();
					Refresh();
					return;
				}
			}
			else
			{
				captionEditor.Visible = true;
				captionEditor.Text = name;
			}
		}




		/// <summary>
		/// On paint event handler
		/// </summary>
		/// <param name="sender">The sender</param>
		/// <param name="e">The event arguments</param>
		protected virtual void imagedPaintEventHandler(object sender, PaintEventArgs e)
		{
			Graphics g = e.Graphics;
			if (selected)
			{
				BackColor = Color.LightGray;
			}
			else
			{
				BackColor = Color.White;
			}
			g.DrawImage(button.ButtonImage, imagePosition);
		}


		private static void removeForm(INamedComponent component)
		{
			if (component is NamedComponent)
			{
				NamedComponent nc = component as NamedComponent;
				nc.RemoveForm();
				return;
			}
			ChildObjectLabel l = ContainerObjectLabel.GetPanel(component) as ChildObjectLabel;
			l.removeForm();
		}


		private void updateNodes()
		{
			foreach (NamedNode node in nodes)
			{
				node.Text = this.name;
			}
		}

		/// <summary>
		/// The properties editor event handler
		/// </summary>
		/// <param name="sender">The sender</param>
		/// <param name="e">The event arguments</param>
		private void showForm(object sender, MouseEventArgs e)
		{
			if (e.Button != MouseButtons.Right)
			{
				return;
			}
			ShowForm();
		}

		#endregion

	}

}
