package org.solovyev.android.translations;

import org.apache.commons.codec.Charsets;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.http.util.TextUtils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Microsoft {

    private static final Pattern TRANSLATION_REGEX = Pattern.compile("<TranslatedText>(.+?)</TranslatedText>");

    private static final String xmlVersions = "<ter:Versions>\n" +
            "<ter:Version>\n" +
            "<ter:Name>${version}</ter:Name>\n" +
            "</ter:Version>\n" +
            "</ter:Versions>\n";
    private static final String xmlPre = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ter=\"http://api.terminology.microsoft.com/terminology\">\n" +
            "<soapenv:Header/>\n" +
            "<soapenv:Body>\n" +
            "<ter:GetTranslations>\n" +
            "<ter:text>${text}</ter:text>\n" +
            "<ter:from>en-us</ter:from>\n" +
            "<ter:to>${to}</ter:to>\n" +
            "<ter:searchOperator>Contains</ter:searchOperator>\n" +
            "<ter:sources>\n" +
            "<ter:TranslationSource>UiStrings</ter:TranslationSource>\n" +
            "</ter:sources>\n" +
            "<ter:unique>false</ter:unique>\n" +
            "<ter:maxTranslations>1</ter:maxTranslations>\n" +
            "<ter:includeDefinitions>true</ter:includeDefinitions>\n" +
            "<ter:products>\n" +
            "<ter:Product>\n" +
            "<ter:Name>${product}</ter:Name>\n";
    private static final String xmlPost = "</ter:Product>\n" +
            "</ter:products>\n" +
            "</ter:GetTranslations>\n" +
            "</soapenv:Body>\n" +
            "</soapenv:Envelope>";
    private static final String xml = xmlPre +
            xmlVersions +
            xmlPost;
    private static final String xmlNoVersion = xmlPre + xmlPost;

    public static void main(String... args) throws Exception {
        final String inFileName = "app/src/main/res/values/strings_microsoft.xml";
        final File inFile = new File(inFileName);

        final File outDir = new File("build/translations/res");
        Utils.delete(outDir);
        outDir.mkdirs();

        final Resources resources = Utils.persister.read(Resources.class, inFile);

        final CloseableHttpClient client = HttpClients.createDefault();
        try {
            final Map<String, Resources> allTranslations = new HashMap<>();
            for (String languageLocale : Utils.languageLocales) {
                final String language = toLanguage(languageLocale);
                Resources translations = allTranslations.get(language);
                if (translations == null) {
                    translations = new Resources();
                    allTranslations.put(language, translations);
                    for (ResourceString string : resources.strings) {
                        if (TextUtils.isEmpty(string.comment)) {
                            System.err.println("No product/version for " + string.value);
                            continue;
                        }
                        final String[] comments = string.comment.split("-");
                        final String translation = translate(client, string.value, language, comments[0], comments.length > 1 ? comments[1] : "");
                        if (!TextUtils.isEmpty(translation)) {
                            translations.strings.add(new ResourceString(string.name, translation));
                        }
                    }
                }
                Utils.saveTranslations(translations, languageLocale, outDir, inFile.getName());
            }

        } finally {
            Utils.close(client);
        }
    }

    private static String translate(CloseableHttpClient client, String word, String language, String product, String version)
            throws UnsupportedEncodingException {
        final HttpPost request = new HttpPost("http://api.terminology.microsoft.com/Terminology.svc");
        request.addHeader("Content-Type", "text/xml; charset=utf-8");
        request.addHeader("SOAPAction", "\"http://api.terminology.microsoft.com/terminology/Terminology/GetTranslations\"");
        final String xml;
        if (version.length() == 0) {
            xml = Microsoft.xmlNoVersion;
        } else {
            xml = Microsoft.xml.replace("${version}", version);
        }
        word = word.replace("%1$s", "{0}").replace("%2$s", "{1}").replace("\\\'", "\'");
        final String body = xml.replace("${text}", word).replace("${to}", language).replace("${product}", product);
        request.setEntity(new StringEntity(body, Charsets.UTF_8));
        CloseableHttpResponse response = null;
        try {
            response = client.execute(request);
            final String result = EntityUtils.toString(response.getEntity());
            if (TextUtils.isEmpty(result)) {
                System.err.println("No translation for " + word + " in " + language);
                return null;
            }
            final Matcher matcher = TRANSLATION_REGEX.matcher(result);
            if (!matcher.find()) {
                System.err.println("No translation for " + word + " in " + language);
                return null;
            }
           return "\"" + matcher.group(1).replace("{0}", "%1$s").replace("{1}", "%2$s") + "\"";
        } catch (IOException | RuntimeException e) {
            e.printStackTrace();
        } finally {
            Utils.close(response);
        }
        return null;
    }

    private static String toLanguage(String languageLocale) {
        switch (languageLocale) {
            case "en":
                return "en-us";
            case "cs":
                return "cs-cz";
            case "ar":
                return "ar-sa";
            case "vi":
                return "vi-vn";
            case "ja":
                return "ja-jp";
            case "uk":
                return "uk-ua";
            case "pt-rBR":
                return "pt-br";
            case "pt-rPT":
                return "pt-pt";
            case "zh-rTW":
                return "zh-tw";
            case "zh-rCN":
                return "zh-cn";
            default:
                final int i = languageLocale.indexOf('-');
                final String language = i >= 0 ? languageLocale.substring(0, i) : languageLocale;
                return language + "-" + language;
        }
    }
}
