/// <summary>
 /// Private constructor.
 /// </summary>
 private Settings()
 {
     settings = new XMLTable();
 }
 private Settings(string path)
 {
     settings = XMLTable.Load(path);
 }
        /// <summary>
        /// Loads the given XMLTable file.
        /// </summary>
        /// <param name="path">Path to load from.</param>
        /// <returns>An initialized XMLTable class with the loaded contents.</returns>
        /// <exception cref="InvalidXMLTableFileException">
        /// Thrown if the XMLTable file is not in a supported format or invalid.
        /// </exception>
        public static XMLTable Load(string path)
        {
            XMLTable loaded = new XMLTable();
            loaded.Filename = path;
            loaded.SaveOnUpdate = false;

            XmlDocument doc = new XmlDocument();
            doc.Load(path);

            XmlNode root = doc.SelectSingleNode(RootNode);
            if (root == null)
                throw new InvalidXMLTableFileException();

            double version = -1f;
            if (root.Attributes["Version"] != null)
            {
                if (double.TryParse(root.Attributes["Version"].Value, out version) == false)
                    version = -1f;
            }

            if (version < OldestSupported)
                throw new InvalidXMLTableFileException();

            XmlNode itemsNode = root.SelectSingleNode(ItemsNode);
            XmlNode informationNode = root.SelectSingleNode(InformationNode);

            List<string> invalidItems = new List<string>();
            foreach (XmlNode item in itemsNode.ChildNodes)
            {
                string name = item.Name;
                if (item.Attributes[IsNull] != null)
                    loaded[name] = null;
                else
                {
                    try
                    {
                        // The following uses reflection to get the type of the item,
                        // load the relevant assembly, and then to run a converter over it.
                        // Any errors will be reported after loading is complete.
                        XmlNode currentInfoNode = informationNode.SelectSingleNode(name);
                        string typeName = currentInfoNode.Attributes["Type"].Value;
                        string assemblyName = currentInfoNode.Attributes["Assembly"].Value;

                        Assembly assembly = Assembly.Load(assemblyName);
                        Type type = assembly.GetType(typeName);
                        if (type == null)
                            throw new InvalidOperationException("Unable to load specified type " + typeName);
                        TypeConverter converter = TypeDescriptor.GetConverter(type);
                        if (converter.CanConvertFrom(typeof(string)))
                            loaded[name] = converter.ConvertFrom(item.InnerText);
                        else
                            invalidItems.Add(name + ": Cannot convert from string");
                    }
                    catch (Exception ex)
                    {
                        invalidItems.Add(name + ": " + ex.Message);
                    }
                }
            }

            if (root.Attributes[SaveOnUpdateNode] != null)
                bool.TryParse(root.Attributes[SaveOnUpdateNode].Value, out loaded.SaveOnUpdate);

            if (invalidItems.Count > 0)
            {
                string seperator = Environment.NewLine + Environment.NewLine;
                string joined = " " + String.Join(seperator + " ", invalidItems.ToArray());
                System.Windows.Forms.MessageBox.Show("The following items could not be loaded from the XMLTable file:" + seperator + joined,
                    "XMLTable.Load", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
            }

            return loaded;
        }