using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Xml;
using System.Diagnostics;
using nft.framework;

namespace nft.util
{
	/// <summary>
	/// Utility methods to help parsing XML documents.
	/// </summary>
	public class XmlUtil
	{
        /// <summary>
        /// Get node text of attribute or child element which has specified 'name'.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string GetNodeText(XmlNode node, string name)
        {
            XmlAttribute a = node.Attributes[name];
            if (a != null)
            {
                return a.Value;
            }
            XmlNode n = node.SelectSingleNode(name);
            if (n != null)
            {
                return n.InnerText;
            }
            return null;
        }

        /// <summary>
        /// Get node text of attribute or child element which has specified 'name'.
        /// </summary>
        public static bool IsNodeExist(XmlNode node, string name)
        {
            XmlAttribute a = node.Attributes[name];
            if (a != null)
            {
                return true;
            }
            XmlNode n = node.SelectSingleNode(name);
            if (n != null)
            {
                return true;
            }
            return false;
        }

        /// <summary>
		/// Performs a node selection and throws an exception if it's not found.
		/// </summary>
		/// <exception cref="XmlException"></exception>
		public static XmlNode SelectSingleNode( XmlNode node, string xpath ) {
			XmlNode n = node.SelectSingleNode(xpath);
			if(n==null)
				throw new XmlException("unable to find "+xpath,null);
			return n;
		}

		/// <summary>
		/// select single node and retruns InnerText.
		/// returns defaultVal if it's not found.
		/// </summary>
        /// <remarks>
        /// Use <c>PluginUtil.GetLocalizedInnerText</c> for localized text.
        /// </remarks>
        /// <seealso cref="PluginUtil.GetLocalizedInnerText"/>
        /// <exception cref="XmlException"></exception>
		public static string GetSingleNodeText( XmlNode node, string xpath, string defaultVal) 
		{
			XmlNode n = node.SelectSingleNode(xpath);
			if(n==null)
				return defaultVal;
			else
				return n.InnerText;
		}

		/// <summary>
		/// Resolves a relative URI.
		/// </summary>
		public static Uri resolve( XmlNode context, string relative ) 
		{
            Char c = relative[0];
            if(c=='/' || c=='\\'){
                relative = relative.Substring(1);
            }
            Uri baseuri = new Uri(context.BaseURI);
            return new Uri(baseuri,relative);
		}

        /// <summary>
        /// get value of specified attribute.
        /// returns defaultVal if it's not found.
        /// </summary>
        /// <remarks>
        /// Use <c>PluginUtil.GetLocalizedAttribute</c> for localized text.
        /// </remarks>
        /// <exception cref="XmlException"></exception>
        public static string GetAttribute(XmlNode node, string name, string defaultVal) {
            XmlAttribute a = node.Attributes[name];
            if (a == null)
                return defaultVal;
            else
                return a.Value;
        }

        /// <summary>
        /// get value of specified attribute.
        /// throw an exception if it's not found.
        /// </summary>
        /// <remarks>
        /// Use <c>PluginUtil.GetLocalizedAttribute</c> for localized text.
        /// </remarks>
        /// <exception cref="XmlException"></exception>
        public static string GetAttribute(XmlNode context, string name)
		{
			XmlAttribute a = context.Attributes[name];
			if(a==null)
			{
				throw new FormatException("the node ["+context.Name+"] must have attribute ["+name+"].");
			}
			return a.Value;	
		}

        /// <summary>
        /// set attribute with specified text.
        /// if there is no such attribute, append new one.
        /// note that this method does not change original file,
        /// but modify only on-memory data.
        /// </summary>
        /// <param name="e"></param>
        /// <param name="name"></param>
        /// <param name="txtval"></param>
        public static void SetAttribute(XmlElement e, string name, string txtval)
		{
            XmlAttribute a = e.Attributes[name];
            if (a != null) {
                a.Value = txtval;
            } else {
                a = e.OwnerDocument.CreateAttribute(name);
                a.Value = txtval;
                e.Attributes.Append(a);
            }
		}

		/// <summary>
		/// Loads plugin.xml file from the directory.
		/// </summary>
		public static XmlDocument LoadFile( string path ) {
            // TODO: Language Localizeation implements here
			using( FileStream file = new FileStream(path,FileMode.Open,FileAccess.Read,FileShare.ReadWrite) ) {
				XmlDocument doc = new XmlDocument();
				XmlReader reader = XmlReader.Create(new XmlTextReader(path,file),null);
				//reader.ValidationType = ValidationType.None;
				doc.Load(reader);
				return doc;
			}
		}

        public static XmlDocument LoadFile(IFileSource fs)
        {
            // TODO: Language Localizeation implements here
            using (Stream file = fs.OpenRead())
            {
                XmlDocument doc = new XmlDocument();
                XmlReader reader = XmlReader.Create(new XmlTextReader(fs.Uri, file), null);
                //reader.ValidationType = ValidationType.None;
                doc.Load(reader);
                return doc;
            }
        }

	}
}
