using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;

namespace Generator_Class_BD.Clases.Utilitarios
{
    public class Traductor
    {
        #region Properties

        /// <summary>
        /// Gets the supported languages.
        /// </summary>
        public static IEnumerable<string> Languages
        {
            get
            {
                Traductor.EnsureInitialized();
                return Traductor._languageModeMap.Keys.OrderBy(p => p);
            }
        }

        /// <summary>
        /// Gets the time taken to perform the translation.
        /// </summary>
        public TimeSpan TranslationTime
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the url used to speak the translation.
        /// </summary>
        /// <value>The url used to speak the translation.</value>
        public string TranslationSpeechUrl
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the error.
        /// </summary>
        public Exception Error
        {
            get;
            private set;
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Translates the specified source text.
        /// </summary>
        /// <param name="sourceText">The source text.</param>
        /// <param name="sourceLanguage">The source language.</param>
        /// <param name="targetLanguage">The target language.</param>
        /// <returns>The translation.</returns>
        public string Traducir
            (string sourceText,
             string sourceLanguage,
             string targetLanguage)
        {
            // Initialize
            this.Error = null;
            this.TranslationSpeechUrl = null;
            this.TranslationTime = TimeSpan.Zero;
            DateTime tmStart = DateTime.Now;
            string translation = string.Empty;

            try
            {
                // Download translation
                string url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}",
                                            Traductor.LanguageEnumToIdentifier(sourceLanguage),
                                            Traductor.LanguageEnumToIdentifier(targetLanguage),
                                            HttpUtility.UrlEncode(sourceText));
                string outputFile = Path.GetTempFileName();
                using (WebClient wc = new WebClient())
                {
                    wc.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
                    wc.DownloadFile(url, outputFile);
                }

                // Get translated text
                if (File.Exists(outputFile))
                {

                    // Get phrase collection
                    string text = File.ReadAllText(outputFile);
                    int index = text.IndexOf(string.Format(",,\"{0}\"", Traductor.LanguageEnumToIdentifier(sourceLanguage)));
                    if (index == -1)
                    {
                        // Translation of single word
                        int startQuote = text.IndexOf('\"');
                        if (startQuote != -1)
                        {
                            int endQuote = text.IndexOf('\"', startQuote + 1);
                            if (endQuote != -1)
                            {
                                translation = text.Substring(startQuote + 1, endQuote - startQuote - 1);
                            }
                        }
                    }
                    else
                    {
                        // Translation of phrase
                        text = text.Substring(0, index);
                        text = text.Replace("],[", ",");
                        text = text.Replace("]", string.Empty);
                        text = text.Replace("[", string.Empty);
                        text = text.Replace("\",\"", "\"");

                        // Get translated phrases
                        string[] phrases = text.Split(new[] { '\"' }, StringSplitOptions.RemoveEmptyEntries);
                        for (int i = 0; (i < phrases.Count()); i += 2)
                        {
                            string translatedPhrase = phrases[i];
                            if (translatedPhrase.StartsWith(",,"))
                            {
                                i--;
                                continue;
                            }
                            translation += translatedPhrase + "  ";
                        }
                    }

                    // Fix up translation
                    translation = translation.Trim();
                    translation = translation.Replace(" ?", "?");
                    translation = translation.Replace(" !", "!");
                    translation = translation.Replace(" ,", ",");
                    translation = translation.Replace(" .", ".");
                    translation = translation.Replace(" ;", ";");

                    // And translation speech URL
                    this.TranslationSpeechUrl = string.Format("https://translate.googleapis.com/translate_tts?ie=UTF-8&q={0}&tl={1}&total=1&idx=0&textlen={2}&client=gtx",
                                                               HttpUtility.UrlEncode(translation), Traductor.LanguageEnumToIdentifier(targetLanguage), translation.Length);
                }
            }
            catch (Exception ex)
            {
                this.Error = ex;
            }

            // Return result
            this.TranslationTime = DateTime.Now - tmStart;
            return translation;
        }

        #endregion

        #region Private methods

        /// <summary>
        /// Converts a language to its identifier.
        /// </summary>
        /// <param name="language">The language."</param>
        /// <returns>The identifier or <see cref="string.Empty"/> if none.</returns>
        private static string LanguageEnumToIdentifier
            (string language)
        {
            string mode = string.Empty;
            Traductor.EnsureInitialized();
            Traductor._languageModeMap.TryGetValue(language, out mode);
            return mode;
        }

        /// <summary>
        /// Ensures the translator has been initialized.
        /// </summary>
        private static void EnsureInitialized()
        {
            if (Traductor._languageModeMap == null)
            {
                Traductor._languageModeMap = new Dictionary<string, string>();

                /*Idiomas de la semilla React*/
                Traductor._languageModeMap.Add("ar_SA", "ar");
                Traductor._languageModeMap.Add("de_DE", "de");
                Traductor._languageModeMap.Add("en_US", "en");
                Traductor._languageModeMap.Add("fr_FR", "fr");
                Traductor._languageModeMap.Add("he_HE", "iw");
                Traductor._languageModeMap.Add("hu_HU", "hu");
                Traductor._languageModeMap.Add("it_IT", "it");
                Traductor._languageModeMap.Add("ja_JA", "ja");
                Traductor._languageModeMap.Add("ko_KO", "ko");
                Traductor._languageModeMap.Add("ru_RU", "ru");
                Traductor._languageModeMap.Add("zh-Hans", "zh-CN");
                /*-----------------------------------------------------------*/
                
                Traductor._languageModeMap.Add("Afrikaans", "af");
                Traductor._languageModeMap.Add("Albanian", "sq");
                Traductor._languageModeMap.Add("Arabic", "ar");
                Traductor._languageModeMap.Add("Armenian", "hy");
                Traductor._languageModeMap.Add("Azerbaijani", "az");
                Traductor._languageModeMap.Add("Basque", "eu");
                Traductor._languageModeMap.Add("Belarusian", "be");
                Traductor._languageModeMap.Add("Bengali", "bn");
                Traductor._languageModeMap.Add("Bulgarian", "bg");
                Traductor._languageModeMap.Add("Catalan", "ca");
                Traductor._languageModeMap.Add("Chinese", "zh-CN");
                Traductor._languageModeMap.Add("Croatian", "hr");
                Traductor._languageModeMap.Add("Czech", "cs");
                Traductor._languageModeMap.Add("Danish", "da");
                Traductor._languageModeMap.Add("Dutch", "nl");
                Traductor._languageModeMap.Add("English", "en");
                Traductor._languageModeMap.Add("Esperanto", "eo");
                Traductor._languageModeMap.Add("Estonian", "et");
                Traductor._languageModeMap.Add("Filipino", "tl");
                Traductor._languageModeMap.Add("Finnish", "fi");
                Traductor._languageModeMap.Add("French", "fr");
                Traductor._languageModeMap.Add("Galician", "gl");
                Traductor._languageModeMap.Add("German", "de");
                Traductor._languageModeMap.Add("Georgian", "ka");
                Traductor._languageModeMap.Add("Greek", "el");
                Traductor._languageModeMap.Add("Haitian Creole", "ht");
                Traductor._languageModeMap.Add("Hebrew", "iw");
                Traductor._languageModeMap.Add("Hindi", "hi");
                Traductor._languageModeMap.Add("Hungarian", "hu");
                Traductor._languageModeMap.Add("Icelandic", "is");
                Traductor._languageModeMap.Add("Indonesian", "id");
                Traductor._languageModeMap.Add("Irish", "ga");
                Traductor._languageModeMap.Add("Italian", "it");
                Traductor._languageModeMap.Add("Japanese", "ja");
                Traductor._languageModeMap.Add("Korean", "ko");
                Traductor._languageModeMap.Add("Lao", "lo");
                Traductor._languageModeMap.Add("Latin", "la");
                Traductor._languageModeMap.Add("Latvian", "lv");
                Traductor._languageModeMap.Add("Lithuanian", "lt");
                Traductor._languageModeMap.Add("Macedonian", "mk");
                Traductor._languageModeMap.Add("Malay", "ms");
                Traductor._languageModeMap.Add("Maltese", "mt");
                Traductor._languageModeMap.Add("Norwegian", "no");
                Traductor._languageModeMap.Add("Persian", "fa");
                Traductor._languageModeMap.Add("Polish", "pl");
                Traductor._languageModeMap.Add("Portuguese", "pt");
                Traductor._languageModeMap.Add("Romanian", "ro");
                Traductor._languageModeMap.Add("Russian", "ru");
                Traductor._languageModeMap.Add("Serbian", "sr");
                Traductor._languageModeMap.Add("Slovak", "sk");
                Traductor._languageModeMap.Add("Slovenian", "sl");
                Traductor._languageModeMap.Add("Spanish", "es");
                Traductor._languageModeMap.Add("Swahili", "sw");
                Traductor._languageModeMap.Add("Swedish", "sv");
                Traductor._languageModeMap.Add("Tamil", "ta");
                Traductor._languageModeMap.Add("Telugu", "te");
                Traductor._languageModeMap.Add("Thai", "th");
                Traductor._languageModeMap.Add("Turkish", "tr");
                Traductor._languageModeMap.Add("Ukrainian", "uk");
                Traductor._languageModeMap.Add("Urdu", "ur");
                Traductor._languageModeMap.Add("Vietnamese", "vi");
                Traductor._languageModeMap.Add("Welsh", "cy");
                Traductor._languageModeMap.Add("Yiddish", "yi");
            }
        }
        #endregion

        #region Fields

        /// <summary>
        /// The language to translation mode map.
        /// </summary>
        private static Dictionary<string, string> _languageModeMap;

        #endregion
    }
}
