using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;

namespace SqlDynamite
{
    public static class XmlUtil
    {
        public static void InsertConfig(string configFile, string configName, ServerInfo serverInfo)
        {
            var settings = new XmlWriterSettings
            {
                NewLineChars = Environment.NewLine,
                Indent = true
            };
            XmlDocument xd = new XmlDocument();
            XmlNode rn;
            if (File.Exists(configFile))
            {
                xd.Load(configFile);
                rn = xd["Connections"];
            }
            else
            {
                rn = xd.AppendChild(xd.CreateNode(XmlNodeType.Element, "Connections", null));
            }
            XmlNode cn = rn.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.InnerText == configName);
            cn = cn ?? rn.AppendChild(xd.CreateNode(XmlNodeType.Element, "Connection", null));

            cn.InnerText = configName;
            cn.Attributes.Append(xd.CreateAttribute("ServerType"));
            cn.Attributes.Append(xd.CreateAttribute("Driver"));
            cn.Attributes.Append(xd.CreateAttribute("Server"));
            cn.Attributes.Append(xd.CreateAttribute("Database"));
            cn.Attributes.Append(xd.CreateAttribute("User"));
            cn.Attributes.Append(xd.CreateAttribute("Password"));
            cn.Attributes.Append(xd.CreateAttribute("SSPI"));
            cn.Attributes.Append(xd.CreateAttribute("Default"));
            cn.Attributes.Append(xd.CreateAttribute("ConnectionType"));
            cn.Attributes["ServerType"].InnerText = serverInfo.ServerType;
            cn.Attributes["Driver"].InnerText = serverInfo.Driver;
            cn.Attributes["Server"].InnerText = serverInfo.Server;
            cn.Attributes["Database"].InnerText = serverInfo.Database;
            cn.Attributes["User"].InnerText = serverInfo.User;
            cn.Attributes["Password"].InnerText = serverInfo.Password;
            cn.Attributes["SSPI"].InnerText = serverInfo.SSPI;
            cn.Attributes["Default"].InnerText = false.ToString();
            cn.Attributes["ConnectionType"].InnerText = serverInfo.ConnectionType;
            XmlWriter xw = XmlWriter.Create(configFile, settings);
            xd.WriteTo(xw);
            xw.Close();
        }

        public static void InsertConfig(string configFile, string configName, string serverType, string driver, string server, string database, string user, string password, string sspi, string connectionType)
        {
            var settings = new XmlWriterSettings
            {
                NewLineChars = Environment.NewLine,
                Indent = true
            };
            XmlDocument xd = new XmlDocument();
            XmlNode rn;
            if (File.Exists(configFile))
            {
                xd.Load(configFile);
                rn = xd["Connections"];
            }
            else
            {
                rn = xd.AppendChild(xd.CreateNode(XmlNodeType.Element, "Connections", null));
            }
            XmlNode cn = rn.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.InnerText == configName);
            cn = cn ?? rn.AppendChild(xd.CreateNode(XmlNodeType.Element, "Connection", null));

            cn.InnerText = configName;
            cn.Attributes.Append(xd.CreateAttribute("ServerType"));
            cn.Attributes.Append(xd.CreateAttribute("Driver"));
            cn.Attributes.Append(xd.CreateAttribute("Server"));
            cn.Attributes.Append(xd.CreateAttribute("Database"));
            cn.Attributes.Append(xd.CreateAttribute("User"));
            cn.Attributes.Append(xd.CreateAttribute("Password"));
            cn.Attributes.Append(xd.CreateAttribute("SSPI"));
            cn.Attributes.Append(xd.CreateAttribute("Default"));
            cn.Attributes.Append(xd.CreateAttribute("ConnectionType"));
            cn.Attributes["ServerType"].InnerText = serverType;
            cn.Attributes["Driver"].InnerText = driver;
            cn.Attributes["Server"].InnerText = server;
            cn.Attributes["Database"].InnerText = database;
            cn.Attributes["User"].InnerText = user;
            cn.Attributes["Password"].InnerText = password;
            cn.Attributes["SSPI"].InnerText = sspi;
            cn.Attributes["Default"].InnerText = false.ToString();
            cn.Attributes["ConnectionType"].InnerText = connectionType;
            XmlWriter xw = XmlWriter.Create(configFile, settings);
            xd.WriteTo(xw);
            xw.Close();
        }

        public static void UpdateConfig(string configFile, string configName, string connectionName, ServerInfo serverInfo)
        {
            if (!File.Exists(configFile)) return;
            var settings = new XmlWriterSettings
            {
                NewLineChars = Environment.NewLine,
                Indent = true
            };
            XmlDocument xd = new XmlDocument();
            xd.Load(configFile);
            XmlNode rn = xd["Connections"];
            XmlNode cn = rn.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.InnerText == configName);
            if (cn == null) return;
            if (cn.Attributes["ConnectionType"] == null)
            {
                cn.Attributes.Append(xd.CreateAttribute("ConnectionType"));
            }
            cn.InnerText = connectionName;
            cn.Attributes["ServerType"].InnerText = serverInfo.ServerType;
            cn.Attributes["Driver"].InnerText = serverInfo.Driver;
            cn.Attributes["Server"].InnerText = serverInfo.Server;
            cn.Attributes["Database"].InnerText = serverInfo.Database;
            cn.Attributes["User"].InnerText = serverInfo.User;
            cn.Attributes["Password"].InnerText = serverInfo.Password;
            cn.Attributes["SSPI"].InnerText = serverInfo.SSPI;
            cn.Attributes["ConnectionType"].InnerText = serverInfo.ConnectionType;
            XmlWriter xw = XmlWriter.Create(configFile, settings);
            xd.WriteTo(xw);
            xw.Close();
        }

        public static void MakeDefaultConfig(string configFile, string configName)
        {
            if (!File.Exists(configFile)) return;
            var settings = new XmlWriterSettings
            {
                NewLineChars = Environment.NewLine,
                Indent = true
            };
            XmlDocument xd = new XmlDocument();
            xd.Load(configFile);
            XmlNode rn = xd["Connections"];
            XmlNode cn = null;
            foreach (XmlNode node in rn.ChildNodes)
            {
                if (node.InnerText == configName)
                {
                    cn = node;
                }
                else
                {
                    node.Attributes["Default"].InnerText = false.ToString();
                }
            }
            if (cn == null) return;
            cn.Attributes["Default"].InnerText = true.ToString();
            XmlWriter xw = XmlWriter.Create(configFile, settings);
            xd.WriteTo(xw);
            xw.Close();
        }

        public static void DeleteConfig(string configFile, string configName)
        {
            if (!File.Exists(configFile)) return;
            var settings = new XmlWriterSettings
            {
                NewLineChars = Environment.NewLine,
                Indent = true
            };
            XmlDocument xd = new XmlDocument();
            xd.Load(configFile);
            XmlNode rn = xd["Connections"];
            XmlNode cn = rn.ChildNodes.Cast<XmlNode>().FirstOrDefault(node => node.InnerText == configName);
            if (cn == null) return;
            rn.RemoveChild(cn);
            XmlWriter xw = XmlWriter.Create(configFile, settings);
            xd.WriteTo(xw);
            xw.Close();
        }

        public static IEnumerable<Tuple<string, bool>> SelectConfig(string configFile)
        {
            List<Tuple<string, bool>> result = new List<Tuple<string, bool>>();
            if (File.Exists(configFile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(configFile);
                XmlNode rn = xd["Connections"];
                result.AddRange(from XmlNode node in rn.ChildNodes
                                select
                                    new Tuple<string, bool>(node.InnerText,
                                                                   bool.Parse(node.Attributes?["Default"].InnerText ?? "false")));
            }
            return result;
        }

        public static ServerInfo SelectConfig(string configFile, string configName)
        {
            if (File.Exists(configFile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(configFile);
                XmlNode rn = xd["Connections"];
                return (from XmlNode node in rn.ChildNodes
                    where configName == node.InnerText
                    select
                        new ServerInfo(node.Attributes?["ServerType"]?.InnerText, node.Attributes?["Driver"]?.InnerText,
                            node.Attributes?["Server"]?.InnerText, node.Attributes?["Database"]?.InnerText,
                            node.Attributes?["User"]?.InnerText, node.Attributes?["Password"]?.InnerText,
                            node.Attributes?["SSPI"]?.InnerText ?? "false", node.Attributes?["ConnectionType"]?.InnerText ?? "NORMAL",
                            node.InnerText)).FirstOrDefault();
            }
            return null;
        }

        public static IList<ServerInfo> LoadConfig(string configFile)
        {
            List<ServerInfo> result = new List<ServerInfo>();
            if (File.Exists(configFile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(configFile);
                XmlNode rn = xd["Connections"];
                result.AddRange(from XmlNode node in rn.ChildNodes
                    select
                        new ServerInfo(node.Attributes?["ServerType"]?.InnerText, node.Attributes?["Driver"]?.InnerText,
                            node.Attributes?["Server"]?.InnerText, node.Attributes?["Database"]?.InnerText,
                            node.Attributes?["User"]?.InnerText, node.Attributes?["Password"]?.InnerText,
                            node.Attributes?["SSPI"]?.InnerText, node.Attributes?["ConnectionType"]?.InnerText, node.InnerText));
            }
            return result;
        }
    }
}
