using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using System.Xml;

using CategoryTheory;
using MathGraph;


namespace DiagramUI
{
	/// <summary>
	/// Container of objects
	/// </summary>
	[Serializable()]
	public class ObjectContainer : ICategoryObject, ISerializable, IPostSetArrow
	{

		#region Fields

		/// <summary>
		/// Associated object
		/// </summary>
		private object obj;
		
		/// <summary>
		/// Byte information
		/// </summary>
		private byte[] bytes;
		
		/// <summary>
		/// Interface
		/// </summary>
		private Hashtable inter = new Hashtable();
		
		/// <summary>
		/// Type
		/// </summary>
		private string type;

		/// <summary>
		/// Serialization binders
		/// </summary>
		static private SerializationBinder[] binders;

		/// <summary>
		/// Child desktop
		/// </summary>
		private PureDesktopPeer desktop = new PureDesktopPeer();

		#endregion

		#region Constructors

		/// <summary>
		/// Main constructor
		/// </summary>
		/// <param name="desktop">The parent desktop</param>
		public ObjectContainer(PureDesktopPeer desktop)
		{
			this.desktop = desktop;
		}

		/// <summary>
		/// Serialization constructor
		/// </summary>
		/// <param name="info"></param>
		/// <param name="context"></param>
		public ObjectContainer(SerializationInfo info, StreamingContext context)
		{
			bytes = info.GetValue("Bytes", typeof(byte[])) as byte[];
			inter = info.GetValue("Interface", typeof(Hashtable)) as Hashtable;
			type = info.GetValue("Type", typeof(string)) as string;
		}

		#endregion

		#region ISerializable Members

		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			MemoryStream stream = new MemoryStream();
			desktop.Save(stream);
			bytes = stream.GetBuffer();
			info.AddValue("Bytes", bytes);
			info.AddValue("Interface", inter);
			info.AddValue("Type", type);
		}

		#endregion

		#region ICategoryObject Members

		public ICategoryArrow Id
		{
			get
			{
				return null;
			}
		}

		public ICategory Category
		{
			get
			{
				return null;
			}
		}

		#endregion

		#region IAssociatedObject Members

		public object Object
		{
			get
			{
				return obj;
			}
			set
			{
				obj = value;
			}
		}

		#endregion

		#region IPostSetArrow Members

		public void PostSetArrow()
		{
			desktop.postDeserialize();
		}

		#endregion

		#region Specific Members

		/// <summary>
		/// Sets parents of objects
		/// </summary>
		/// <param name="desktop">The desktop</param>
		public void SetParents(IDesktop desktop)
		{
			ICollection objs = desktop.Objects;
			INamedComponent comp = null;
			foreach (IObjectLabel ol in objs)
			{
				if (ol.Object == this)
				{
					comp = ol;
					break;
				}
			}
			ICollection objects = this.desktop.Components;
			foreach (INamedComponent nc in objects)
			{
				if (nc is IObjectLabel)
				{
					IObjectLabel l = nc as IObjectLabel;
					if (l.Object is ObjectContainer)
					{
						ObjectContainer oc = l.Object as ObjectContainer;
						PureDesktopPeer.SetParents(oc.desktop);
					}
				}
				nc.Parent = comp;
			}
		}

		/// <summary>
		/// The post load operation
		/// </summary>
		public void PostLoad()
		{
			MemoryStream ms = new MemoryStream(bytes);
			desktop.loadBinders(ms, binders);
			desktop.setParent(this);
			ICollection c = desktop.Components;
			foreach (INamedComponent nc in c)
			{
				if (nc.Parent == null)
				{
					nc.Parent = Object as INamedComponent;
				}
			}
			bytes = null;
			GC.Collect();
		}

		/// <summary>
		/// Gets relative name of component
		/// </summary>
		/// <param name="comp">The component</param>
		/// <returns>The relative name</returns>
		public string GetName(INamedComponent comp)
		{
			return comp.GetName(desktop);
		}

		/// <summary>
		/// All child objects
		/// </summary>
		public ICollection AllObjects
		{
			get
			{
				return PureDesktopPeer.GetAllObjects(desktop);
			}
		}

		/// <summary>
		/// Adds a component
		/// </summary>
		/// <param name="c">The component to add</param>
		/// <param name="x">The x - coordinate</param>
		/// <param name="y">The y - coordinate</param>
		/// <param name="comment">The comment</param>
		public void Add(INamedComponent c, int x, int y, string comment)
		{
			string name = c.GetName(desktop);
			inter[name] = new object[]{x, y, comment};
		}

		/// <summary>
		/// Serialization binders
		/// </summary>
		public static SerializationBinder[] Binders
		{
			set
			{
				binders = value;
			}
		}

		/// <summary>
		/// The type
		/// </summary>
		public string Type
		{
			get
			{
				return type;
			}
			set
			{
				type = value;
			}
		}

		/// <summary>
		/// Access to child by name
		/// </summary>
		/// <param name="name">The name</param>
		/// <returns>The child</returns>
		public INamedComponent this[string name]
		{
			get
			{
				return desktop[name];
			}
		}

		/// <summary>
		/// The interface
		/// </summary>
		public Hashtable Interface
		{
			get
			{
				return inter;
			}
		}

		/// <summary>
		/// The desktop
		/// </summary>
		public IDesktop Desktop
		{
			get
			{
				return desktop;
			}
		}


		#endregion

	}
	

}
