namespace TranslationLibrary.Resources
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Xml;

    public static class TranslateResources
    {
        private static readonly Translate TranslateService = new Translate();

        /// <summary>
        /// Starts the specified resource directory.
        /// </summary>
        /// <param name="resourceDirectory">The resource directory.</param>
        public static void Start(string resourceDirectory)
        {
            ReadResourceFiles(resourceDirectory);
        }

        /// <summary>
        /// Reads the resource files.
        /// </summary>
        /// <param name="resourceDirectory">The resource directory.</param>
        private static void ReadResourceFiles(string resourceDirectory)
        {
            Dictionary<string, string> translatedFiles = new Dictionary<string, string>();

            // The .resx file name
            string fileName = resourceDirectory + @"\Resources.resx";

            // Check if the file exists
            if (File.Exists(fileName))
            {
                // Load the xml document
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load(fileName);

                // Select the data we need to translate
                XmlNodeList xmlNodeList = xmlDocument.SelectNodes("//root/data");

                string appId;

                foreach (var configSetting in GetConfigSettings(resourceDirectory, out appId))
                {
                    translatedFiles.Clear();

                    string language = configSetting.Key;
                    string cultureCode = configSetting.Value;

                    // Loop through and request translation
                    if (xmlNodeList != null)
                    {
                        foreach (XmlNode xmlNode in xmlNodeList)
                        {
                            // Request Translation
                            string translatedText = TranslateXmlNode(xmlNode.InnerText, language, appId);

                            translatedFiles.Add(GetNameAttribute(xmlNode), translatedText);
                        }
                    }

                    // Write the file to XML
                    WriteToXml(translatedFiles, cultureCode, resourceDirectory);
                }
            }
        }

        /// <summary>
        /// Gets the name attribute of the XML Node.
        /// </summary>
        /// <param name="xmlNode">The XML node to get attribute from</param>
        /// <returns>A string with the attribute name</returns>
        private static string GetNameAttribute(XmlNode xmlNode)
        {
            if (xmlNode.Attributes != null)
            {
                foreach (XmlAttribute attribute in xmlNode.Attributes)
                {
                    if (attribute.Name.ToUpper() == "NAME")
                    {
                        return attribute.Value;
                    }
                }
            }
 
            return string.Empty;
        }

        /// <summary>
        /// Gets the config setting.
        /// </summary>
        /// <param name="resourceDirectory">The resource directory.</param>
        /// <param name="appId">The app id.</param>
        /// <returns>
        /// A dictionary of the config settings
        /// </returns>
        private static Dictionary<string, string> GetConfigSettings(string resourceDirectory, out string appId)
        {
            string fileName = resourceDirectory + @"\config.xml";

            // Load the file
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(fileName);

            // Select the app Id
            XmlNode appIdNode = xmlDocument.SelectSingleNode("//root/AppKey/Key");

            if (appIdNode == null)
            {
                throw new Exception("Can't find app Id - please add one");
            }

            appId = appIdNode.InnerText;

            // Read in the language values
            XmlNodeList xmlNodeList = xmlDocument.SelectNodes("//root/Language");

            Dictionary<string, string> languageList = new Dictionary<string, string>();
            if (xmlNodeList != null)
            {
                foreach (XmlNode language in xmlNodeList)
                {
                        languageList.Add(GetNameAttribute(language), language.InnerText);
                }
            }

            return languageList;
        }

        /// <summary>
        /// Translates the XML node.
        /// </summary>
        /// <param name="text">The tex to translate.</param>
        /// <param name="language">The language to translate to.</param>
        /// <param name="appId">The application id.</param>
        /// <returns>A translated XML node</returns>
        private static string TranslateXmlNode(string text, string language, string appId)
        {
            return TranslateService.TranslateText(appId, text, "en", language, "text/plain", "general");
        }

        /// <summary>
        /// Writes the document to XML.
        /// </summary>
        /// <param name="translatedFiles">The translated files.</param>
        /// <param name="cultureCode">The culture code.</param>
        /// <param name="resourceDirectory">The resource directory.</param>
        private static void WriteToXml(Dictionary<string, string> translatedFiles, string cultureCode, string resourceDirectory)
        {
            // Create the xml document containe
            XmlDocument xmlDocument = new XmlDocument();

            // Create the XML Declaration, and append it to XML document
            XmlDeclaration xmlDeclaration = xmlDocument.CreateXmlDeclaration("1.0", null, null);
            xmlDocument.AppendChild(xmlDeclaration);

            // Create the root element
            XmlElement root = xmlDocument.CreateElement("root");
            xmlDocument.AppendChild(root);

            // First we need to add the standard tag values required to make this a valid resx file.
            AddStandardElements(xmlDocument, root);

            // Loop through the file and add values
            foreach (KeyValuePair<string, string> translatedFile in translatedFiles)
            {
                AddElementToXml(xmlDocument, root, translatedFile.Key, translatedFile.Value, "data");
            }

            // Save the file with todays date and time the test ran
            // It is currently set to use the "mydocuments" folder, but this can be changed
            string directory = resourceDirectory;
            string fileName = directory + @"\Resources." + cultureCode + ".resx";

            // Create the directory if it doesn't exist
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            xmlDocument.Save(fileName);
        }

        /// <summary>
        /// Adds the standard elements that are required to 
        /// make the document a standard resx document.
        /// </summary>
        /// <param name="doc">The XMl document</param>
        /// <param name="root">The root of the document</param>
        private static void AddStandardElements(XmlDocument doc, XmlElement root)
        {
            // Mime Type
            AddElementToXml(doc, root, "resmimetype", "text/microsoft-resx", "resheader");

            // Version
            AddElementToXml(doc, root, "version", "2.0", "resheader");

            // Resource Reader
            AddElementToXml(doc, root, "reader", "System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "resheader");

            // Resource Writer
            AddElementToXml(doc, root, "writer", "System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "resheader");
        }

        /// <summary>
        /// Adds the element to XML document.
        /// </summary>
        /// <param name="doc">The XMl document</param>
        /// <param name="root">The root of the document</param>
        /// <param name="key">The key of the attribute.</param>
        /// <param name="value">The value to write</param>
        /// <param name="elementName">Name of the element.</param>
        private static void AddElementToXml(XmlDocument doc, XmlElement root, string key, string value, string elementName)
        {
            XmlElement xmlElement = doc.CreateElement(elementName);
            xmlElement.SetAttribute("name", key);

            // Child Node - Value
            XmlElement childNode = doc.CreateElement("value");
            childNode.InnerText = value;

            xmlElement.AppendChild(childNode);
            root.AppendChild(xmlElement);
        }
    }
}
