using System;
using System.Xml;
using System.IO;
using DevComponents.DotNetBar;
namespace DevComponents.AdvTree
{
	/// 
	/// Provides means for AdvTree serialization.
	/// 
	public class TreeSerializer
	{
		#region Private Variables
		private static string XmlNodeName="Node";
		private static string XmlCellsName="Cells";
		private static string XmlCellName="Cell";
		private static string XmlCellImagesName="Images";
		private static string XmlAdvTreeName="AdvTree";
		private static string XmlCustomName = "Custom";
		#endregion
		
		#region Saving
		/// 
		/// Saves Nodes to specified file.
		/// 
		/// AdvTree to save
		/// Target file name
		public static void Save(AdvTree tree, string fileName)
		{
			XmlDocument document=Save(tree);
			document.Save(fileName);
		}
		
		/// 
		/// Saves Nodes to stream.
		/// 
		/// AdvTree to save
		/// Stream to save nodes to.
		public static void Save(AdvTree tree, Stream outStream)
		{
			XmlDocument document=Save(tree);
			document.Save(outStream);
		}
		
		/// 
		/// Saves Nodes to TextWriter
		/// 
		/// AdvTree to save
		/// TextWriter to write nodes to.
		public static void Save(AdvTree tree, TextWriter writer)
		{
			XmlDocument document=Save(tree);
			document.Save(writer);
		}
		
		/// 
		/// Saves nodes to XmlWriter.
		/// 
		/// AdvTree to save
		/// XmlWriter to write nodes to
		public static void Save(AdvTree tree, XmlWriter writer)
		{
			XmlDocument document=Save(tree);
			document.Save(writer);
		}
		
		/// 
		/// Creates new XmlDocument and serializes AdvTree into it.
		/// 
		/// AdvTree to serialize
		/// New instance of XmlDocument/returns>
		public static XmlDocument Save(AdvTree tree)
		{
			XmlDocument document=new XmlDocument();
			Save(tree, document);
			return document;
		}
		
		/// 
		/// Saves AdvTree to an existing XmlDocument. New node AdvTree is created in document and Nodes are serialized into it.
		/// 
		/// AdvTree to serialize
		/// XmlDocument instance.
		public static void Save(AdvTree tree, XmlDocument document)
		{
			XmlElement parent = document.CreateElement(XmlAdvTreeName);
			document.AppendChild(parent);
			TreeSerializer.Save(tree, parent);
		}
		
		/// 
		/// Serializes AdvTree object to XmlElement object.
		/// 
		/// Instance of AdvTree to serialize.
		/// XmlElement to serialize to.
		public static void Save(AdvTree tree, XmlElement parent)
		{
			NodeSerializationContext context = new NodeSerializationContext();
			context.RefXmlElement = parent;
			context.AdvTree = tree;
			context.HasSerializeNodeHandlers = tree.HasSerializeNodeHandlers;
			context.HasDeserializeNodeHandlers = tree.HasDeserializeNodeHandlers;
			
			foreach(Node node in tree.Nodes)
			{
				Save(node, context);
			}
		}
		
		/// 
		/// Serializes Node and all child nodes to XmlElement object.
		/// 
		/// Node to serialize.
		/// Provides serialization context.
		public static void Save(Node node, NodeSerializationContext context)
		{
			XmlElement parent = context.RefXmlElement;
			
			XmlElement xmlNode=parent.OwnerDocument.CreateElement(XmlNodeName);
			parent.AppendChild(xmlNode);
			
			ElementSerializer.Serialize(node, xmlNode);
			
			if(context.HasSerializeNodeHandlers)
			{
				XmlElement customXml = parent.OwnerDocument.CreateElement(XmlCustomName);
				SerializeNodeEventArgs e = new SerializeNodeEventArgs(node, xmlNode, customXml);
				context.AdvTree.InvokeSerializeNode(e);
				if (customXml.Attributes.Count > 0 || customXml.ChildNodes.Count > 0)
					xmlNode.AppendChild(customXml);
			}
			
			if(node.Cells.Count>1)
			{
				XmlElement xmlCells = parent.OwnerDocument.CreateElement(XmlCellsName);
				xmlNode.AppendChild(xmlCells);
				
				for(int i=1; i
		/// Load AdvTree Nodes from file.
		/// 
		/// Reference to AdvTree to populate
		/// File name.
		public static void Load(AdvTree tree, string fileName)
		{
			XmlDocument document=new XmlDocument();
			document.Load(fileName);
			Load(tree, document);
		}
		
		/// 
		/// Load AdvTree Nodes from stream.
		/// 
		/// Reference to AdvTree to populate
		/// Reference to stream
		public static void Load(AdvTree tree, Stream inStream)
		{
			XmlDocument document=new XmlDocument();
			document.Load(inStream);
			Load(tree, document);
		}
		
		/// 
		/// Load AdvTree Nodes from reader.
		/// 
		/// Reference to AdvTree to populate
		/// Reference to reader.
		public static void Load(AdvTree tree, TextReader reader)
		{
			XmlDocument document=new XmlDocument();
			document.Load(reader);
			Load(tree, document);
		}
		
		/// 
		/// Load AdvTree Nodes from reader.
		/// 
		/// Reference to AdvTree to populate
		/// Reference to reader.
		public static void Load(AdvTree tree, XmlReader reader)
		{
			XmlDocument document=new XmlDocument();
			document.Load(reader);
			Load(tree, document);
		}
		
		/// 
		/// Load AdvTree from XmlDocument that was created by Save method.
		/// 
		/// Tree Control to load
		/// XmlDocument to load control from
		public static void Load(AdvTree tree, XmlDocument document)
		{
			foreach(XmlNode xmlNode in document.ChildNodes)
			{
				if(xmlNode.Name==XmlAdvTreeName && xmlNode is XmlElement)
				{
					Load(tree, xmlNode as XmlElement);
					break;
				}
			}
		}
		
		/// 
		/// Load nodes from XmlElement.
		/// 
		/// Reference to AdvTree to be populated.
		/// XmlElement that tree was serialized to.
		public static void Load(AdvTree tree, XmlElement parent)
		{
			tree.BeginUpdate();
			tree.DisplayRootNode = null;
			tree.Nodes.Clear();
			
			NodeSerializationContext context = new NodeSerializationContext();
			context.AdvTree = tree;
			context.HasDeserializeNodeHandlers  = tree.HasDeserializeNodeHandlers;
			context.HasSerializeNodeHandlers = tree.HasSerializeNodeHandlers;
			
			try
			{
				foreach(XmlNode xmlNode in parent.ChildNodes)
				{
					if(xmlNode.Name==XmlNodeName && xmlNode is XmlElement)
					{
						Node node=new Node();
						tree.Nodes.Add(node);
						context.RefXmlElement = xmlNode as XmlElement;
						LoadNode(node, context);
					}
				}
			}
			finally
			{
				tree.EndUpdate();
			}
		}
		
		/// 
		/// Load single node and it's child nodes if any.
		/// 
		/// New instance of node that is populated with loaded data.
		/// Provides deserialization context.
		public static void LoadNode(Node nodeToLoad, NodeSerializationContext context)
		{
			XmlElement xmlNode = context.RefXmlElement;
			
			ElementSerializer.Deserialize(nodeToLoad, xmlNode);
			foreach(XmlNode xmlChild in xmlNode.ChildNodes)
			{
				XmlElement xmlElem = xmlChild as XmlElement;
				if(xmlElem == null)
					continue;
				if(xmlElem.Name==XmlNodeName)
				{
					Node node=new Node();
					nodeToLoad.Nodes.Add(node);
					context.RefXmlElement = xmlElem;
					LoadNode(node, context);
				}
				else if(xmlElem.Name == XmlCellsName)
				{
					LoadCells(nodeToLoad, xmlElem);
				}
				else if(xmlElem.Name == XmlCustomName)
				{
					if(context.HasDeserializeNodeHandlers)
					{
						SerializeNodeEventArgs e = new SerializeNodeEventArgs(nodeToLoad, xmlNode, xmlElem);
						context.AdvTree.InvokeDeserializeNode(e);
					}
				}
			}
			context.RefXmlElement = xmlNode;
		}
		
		private static void LoadCells(Node parentNode, XmlElement xmlCells)
		{
			foreach(XmlNode xmlChild in xmlCells.ChildNodes)
			{
				if(xmlChild.Name==XmlCellName && xmlChild is XmlElement)
				{
					Cell cell=new Cell();
					parentNode.Cells.Add(cell);
					ElementSerializer.Deserialize(cell, xmlChild as XmlElement);
					// Load images if any
					foreach(XmlElement xmlImage in xmlChild.ChildNodes)
					{
						if(xmlImage.Name==XmlCellImagesName)
						{
							ElementSerializer.Deserialize(cell.Images, xmlImage);
							break;
						}
					}
				}
			}
		}
		#endregion
	}
	
	/// 
	/// Provides context information for serialization.
	/// 
	public class NodeSerializationContext
	{
		/// 
		/// Gets or sets reference to context parent XmlElement when serializing or actual Node element when deserializing.
		/// 
		public System.Xml.XmlElement RefXmlElement = null;
		/// 
		/// Gets or sets whether SerializeNode event handler has been defined and whether event should be fired.
		/// 
		public bool HasSerializeNodeHandlers = false;
		/// 
		/// Gets or sets whether DeserializeNode event handler has been defined and whether event should be fired.
		/// 
		public bool HasDeserializeNodeHandlers = false;
		/// 
		/// Provides access to serializer.
		/// 
		public AdvTree AdvTree = null;
	}
}