/// <summary>
        /// Starts the serialization process. Takes the abstract of the graph and
        /// constructs a NMLType proxy-like object which will be serialized via the
        /// standard .Net XmlSerializer process.
        /// </summary>
        /// <param name="writer">An XmlWriter</param>
        /// <param name="g">The GraphAbstract object to be serialized</param>
        public void Serialize(XmlWriter writer, GraphAbstract g)
        {
            try
            {
                //the root of the NML
                NMLType nml = new NMLType();
                //add the version node
                nml.Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
                //the graph node
                GraphType graph = new GraphType();
                nml.Graph = graph;
                //add the graph information
                graph.GraphInformation = new GraphInformationType(g.GraphInformation);
                //serialize the shapes
                foreach (Shape s in g.Shapes)
                {
                    graph.Items.Add(SerializeNode(s));
                }
                //serialize the connections
                foreach (Connection c in g.Connections)
                {
                    graph.Items.Add(SerializeEdge(c));
                }

                //			foreach(DictionaryEntry de in keyList)
                //			{
                //				nml.Key.Add(BuildKeyType((String)de.Key));
                //			}


                // serialize
                XmlSerializer ser = new XmlSerializer(typeof(NMLType));

                ser.Serialize(writer, nml);
            }


            catch (Exception exc)
            {
                site.OutputInfo(exc.Message, "NMLSerializer.Serialize", OutputInfoLevels.Exception);
            }
            catch
            {
                site.OutputInfo("Non-CLS exception caught.", "BinarySerializer.Serialize", OutputInfoLevels.Exception);
            }
            finally
            {
            }
        }
		/// <summary>
		/// Starts the serialization process. Takes the abstract of the graph and
		/// constructs a NMLType proxy-like object which will be serialized via the 
		/// standard .Net XmlSerializer process.
		/// </summary>
		/// <param name="writer">An XmlWriter</param>
		/// <param name="g">The GraphAbstract object to be serialized</param>
		public void Serialize(XmlWriter writer, GraphAbstract g	)
		{
			try
			{
				//the root of the NML
				NMLType nml = new NMLType(); 
				//add the version node
				nml.Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
				//the graph node 
				GraphType graph = new GraphType();	
				nml.Graph = graph;				
				//add the graph information				
				graph.GraphInformation = new GraphInformationType(g.GraphInformation);
				//serialize the shapes
				foreach ( Shape s in g.Shapes )				
					graph.Items.Add(SerializeNode(s));				
				//serialize the connections
				foreach(Connection c in g.Connections)
					graph.Items.Add(SerializeEdge(c));
				
				//			foreach(DictionaryEntry de in keyList)
				//			{
				//				nml.Key.Add(BuildKeyType((String)de.Key));
				//			}

			
				// serialize
				XmlSerializer ser = new XmlSerializer(typeof(NMLType));
				
				ser.Serialize(writer,nml);
	
			}

			
			catch(Exception exc)
			{
				site.OutputInfo(exc.Message, "NMLSerializer.Serialize", OutputInfoLevels.Exception);
			}
			catch
			{
				site.OutputInfo("Non-CLS exception caught.", "BinarySerializer.Serialize", OutputInfoLevels.Exception);
			}
			finally
			{
						
			}
		}
        /// <summary>
        /// Deserializes the graphtype, here's where all the smart stuff happens
        /// </summary>
        /// <param name="gml">the graphtype which acts as an intermediate storage between XML and the GraphAbstract
        /// </param>
        /// <returns></returns>
        private GraphAbstract Deserialize(NMLType gml)
        {
            GraphAbstract abs = new GraphAbstract();

            #region Load the graph information
            GraphType g = gml.Graph;

            abs.GraphInformation = g.GraphInformation.ToGraphInformation();

            #endregion
            Shape          shape = null;
            ShapeType      node;
            DataType       dt;
            ConnectorType  ct;
            Connection     con = null;
            ConnectionType et;
            string         linePath = string.Empty;               //see the split deserialization of the connection

            FromToCollection ftc        = new FromToCollection(); //temporary store for from-to relations of connections
            Hashtable        connectors = new Hashtable();        //temporary collection of connector
            #region Loop over all items



            for (int k = 0; k < g.Items.Count; k++)        //loop over all serialized items
            {
                try
                {
                    if (g.Items[k] is ShapeType)
                    {
                        Trace.WriteLine("Node: " + (g.Items[k] as ShapeType).UID, "NMLSerializer.Deserialize");
                        node = g.Items[k] as ShapeType;

                        #region find out which type of shape needs to be instantiated
                        if (node != null && node.InstanceKey != string.Empty)
                        {
                            shape = GetShape(node.InstanceKey);
                        }
                        if (shape == null)
                        {
                            Trace.WriteLine("...but failed to instantiate the appropriate shape (missing or not loaded library?", "NMLSerializer.Deserialize");
                            continue;
                        }

                        #endregion
                        #region use the attribs again to reconstruct the props
                        for (int m = 0; m < node.Data.Count; m++)                   //loop over the serialized data
                        {
                            if (node.Data[m] is DataType)
                            {
                                #region Handle data node
                                dt = node.Data[m] as DataType;
                                if (dt == null)
                                {
                                    continue;
                                }

                                foreach (PropertyInfo pi in shape.GetType().GetProperties())
                                {
                                    if (Attribute.IsDefined(pi, typeof(GraphMLDataAttribute)))
                                    {
                                        try
                                        {
                                            if (pi.Name == dt.Name)
                                            {
                                                if (pi.GetIndexParameters().Length == 0)
                                                {
                                                    if (pi.PropertyType.Equals(typeof(int)))
                                                    {
                                                        pi.SetValue(shape, Convert.ToInt32(dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(Color)))                                                    //Color is stored as an integer
                                                    {
                                                        pi.SetValue(shape, Color.FromArgb(int.Parse(dt.Value[0].ToString())), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(string)))
                                                    {
                                                        pi.SetValue(shape, (string)(dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(bool)))
                                                    {
                                                        pi.SetValue(shape, Convert.ToBoolean(dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(Guid)))
                                                    {
                                                        pi.SetValue(shape, new Guid((string)dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(float)))
                                                    {
                                                        pi.SetValue(shape, Convert.ToSingle(dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.BaseType.Equals(typeof(Enum)))                                                   //yesyes, you can imp/exp enum types too
                                                    {
                                                        pi.SetValue(shape, Enum.Parse(pi.PropertyType, dt.Value[0].ToString()), null);
                                                    }
                                                    else if (dt.IsCollection)
                                                    {
                                                        #region Some explanations

                                                        /* OK, here's the deal.
                                                         * This part is related to the possibility to imp/exp property-collections from/to NML.
                                                         * However, since (see more specifically the ClassShape) the collections will usually be defined
                                                         * where the shapes is defined, i.e. in an external assembly, the collection-type is unknown.
                                                         * Importing/exporting collections to NML is itsel a problem and in this part of the code the data is reflected again.
                                                         * To bypass the problem that the collection-type is unknown I hereby assume that the collection can be built up again via
                                                         * a public constructor of the collection with argument 'ArrayList'. In the ArrayList the collection-elements are of type string[]
                                                         * whereby the order of the strings reflect the order of the GraphMLData-tagged properties of the collection elements.
                                                         * For example, the ClassPropertiesCollection has the required constructor and the ClassProperty object is instantiated via the string[] elements in the
                                                         * ArrayList.
                                                         * Of course, this brings some restriction but it's for the moment the most flexible way I have found.
                                                         * If the ClassProperty would itself have a property inheriting from CollectionBase this will not work...one has to draw a line somewhere.
                                                         * It's the price to pay for using reflection and external assemblies. The whole story can be forgotten if you link the shape-classes at compile-time.
                                                         * Remember; the Netron graphlib is more a toolkit than a all-in solution to all situations.
                                                         * However, the current implementation will cover, I beleive, 90% of the needs.
                                                         */
                                                        #endregion

                                                        ArrayList list = new ArrayList();
                                                        for (int p = 0; p < dt.Value.Count; p++)                                                //loop over the collection elements
                                                        {
                                                            DataType dat = dt.Value[p] as DataType;                                             //take a collection element
                                                            if (dat.IsCollection)                                                               //is it itself a collection?
                                                            {
                                                                string[] str = new string[dat.Value.Count];
                                                                for (int l = 0; l < dat.Value.Count; l++)
                                                                {
                                                                    if ((dat.Value[l] as DataType).Value.Count > 0)
                                                                    {
                                                                        str[l] = (string)(dat.Value[l] as DataType).Value[0];
                                                                    }
                                                                    else
                                                                    {
                                                                        str[l] = string.Empty;
                                                                    }
                                                                }
                                                                list.Add(str);
                                                            }
                                                            else
                                                            {
                                                                list.Add(new string[] { (string)dat.Value[0] });
                                                            }
                                                        }
                                                        object o;
                                                        o = pi.PropertyType.GetConstructor(new Type[] { typeof(ArrayList) }).Invoke(new Object[] { list });
                                                        pi.SetValue(shape, o, null);
                                                        Trace.WriteLine("'" + dt.Name + "' is an array type", "NMLSeriliazer.Deserialize");
                                                    }
                                                }
                                                else
                                                {
                                                    pi.SetValue(shape, dt.Value, null);
                                                }
                                                Trace.WriteLine("'" + dt.Name + "' deserialized.", "NMLSeriliazer.Deserialize");
                                                break;
                                            }
                                        }
                                        catch (Exception exc)
                                        {
                                            Trace.WriteLine("Failed '" + dt.Name + "': " + exc.Message, "NMLSeriliazer.Deserialize");
                                            continue;                                            //just try to make the best out of it
                                        }
                                    }
                                }
                                #endregion
                            }
                            else if (node.Data[m] is ConnectorType)
                            {
                                #region Handle connector data
                                ct = node.Data[m] as ConnectorType;
                                foreach (Connector c in shape.Connectors)
                                {
                                    if (c.Name == ct.Name)
                                    {
                                        c.UID = new Guid(ct.UID);
                                        break;
                                    }
                                }
                                #endregion
                            }
                        }
                        #endregion
                        //at this point the shape is fully deserialized
                        //but we still need to assign the ambient properties,
                        //i.e. the properties associated to the current hosting of the control
                        if (shape != null)
                        {
                            shape.Site = site;
                            shape.PostDeserialization();
                            shape.Font = site.Font;
                            //shape.FitSize(false);
                            abs.Shapes.Add(shape);
                            //keep the references to the connectors, to be used when creating the connections
                            foreach (Connector cor in shape.Connectors)
                            {
                                connectors.Add(cor.UID.ToString(), cor);
                            }
                        }
                    }
                    else if (g.Items[k] is ConnectionType)
                    {
                        #region  handle the edge
                        //we cannot create the connection here since not all shapes have been instantiated yet
                        //keep the edges in temp collection, treated in next loop
                        et       = g.Items[k] as ConnectionType;
                        con      = new Connection(site);
                        con.Font = site.Font;
                        con.UID  = new Guid(et.ID);
                        Trace.WriteLine("Connection: " + et.ID, "NMLSeriliazer.Deserialize");
                        #region use the attribs to reconstruct the props


                        for (int m = 0; m < et.Data.Count; m++)                   //loop over the serialized data
                        {
                            if (et.Data[m] is DataType)
                            {
                                #region Handle data node, same as the shape
                                dt = et.Data[m] as DataType;
                                if (dt == null)
                                {
                                    continue;
                                }

                                foreach (PropertyInfo pi in con.GetType().GetProperties())
                                {
                                    if (Attribute.IsDefined(pi, typeof(GraphMLDataAttribute)))
                                    {
                                        try
                                        {
                                            if (pi.Name == dt.Name)
                                            {
                                                if (dt.Name == "LinePath")
                                                {
                                                    //the LinePath will not work without non-null From and To, so set it afterwards
                                                    linePath = dt.Value[0].ToString();
                                                }
                                                else if (pi.GetIndexParameters().Length == 0)
                                                {
                                                    if (pi.PropertyType.Equals(typeof(int)))
                                                    {
                                                        pi.SetValue(con, Convert.ToInt32(dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(Color)))                                                    //Color is stored as an integer
                                                    {
                                                        pi.SetValue(con, Color.FromArgb(int.Parse(dt.Value[0].ToString())), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(string)))
                                                    {
                                                        pi.SetValue(con, (string)(dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(bool)))
                                                    {
                                                        pi.SetValue(con, Convert.ToBoolean(dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(Guid)))
                                                    {
                                                        pi.SetValue(con, new Guid((string)dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(float)))
                                                    {
                                                        pi.SetValue(con, Convert.ToSingle(dt.Value[0]), null);
                                                    }
                                                    else if (pi.PropertyType.Equals(typeof(ConnectionWeight)))
                                                    {
                                                        pi.SetValue(con, Enum.Parse(typeof(ConnectionWeight), dt.Value[0].ToString()), null);
                                                    }
                                                }
                                                else
                                                {
                                                    pi.SetValue(con, dt.Value, null);
                                                }
                                                Trace.WriteLine("'" + dt.Name + "' deserialized.", "NMLSeriliazer.Deserialize");
                                                break;
                                            }
                                        }
                                        catch (Exception exc)
                                        {
                                            Trace.WriteLine("Failed '" + dt.Name + "': " + exc.Message, "NMLSeriliazer.Deserialize");
                                            continue;                                            //just try to make the best out of it
                                        }
                                    }
                                }
                                #endregion
                            }
                        }

                        #endregion
                        ftc.Add(new FromTo(et.Sourceport, et.Targetport, con));
                        #endregion
                    }
                }
                catch (Exception exc)
                {
                    Trace.WriteLine(exc.Message, "NMLSeriliazer.Deserialize");
                    continue;
                }
            }            //loop over items in the graph-XML
            #endregion

            #region now for the edges;
            //loop over the FromTo collections and pick up the corresponding connectors
            for (int k = 0; k < ftc.Count; k++)
            {
                try
                {
                    con      = ftc[k].Connection;
                    con.From = connectors[ftc[k].From] as Connector;
                    con.To   = connectors[ftc[k].To] as Connector;
                    con.From.Connections.Add(con);               //if From is null we'll fail in the catch and continue
                    con.LinePath = linePath;                     //only setable after the From and To are found
                    con.To.Connections.Add(con);
                    abs.Insert(con);
                    Trace.WriteLine("Connection '" + con.UID + "' added.", "NMLSeriliazer.Deserialize");
                }
                catch (Exception exc)
                {
                    Trace.WriteLine("Connection failed: " + exc.Message, "NMLSeriliazer.Deserialize");
                    continue;                     //make the best of it
                }
            }
            #endregion


            //			for(int n=0; n<pcs.Count; n++)
            //			{
            //				from = pcs[n].ChildShape;
            //				to = abs.Shapes[pcs[n].Parent];
            //				con = new Connection(from, to );
            //				abs.Connections.Add(con);
            //				con.site = site;
            //				if(pcs[n].ChildShape.visible)
            //					con.visible = true;
            //				from.connection = con;	//a lot of crossing...to make life easy really
            //				from.parentNode =to;
            //				to.childNodes.Add(from);
            //
            //
            //			}

            return(abs);
        }