/*
 * Copyright 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>A utility which auto-translates English strings in Android string resources using
 * Google Translate.</p>
 *
 * <p>Pass the Android client res/ directory as first argument, and optionally message keys
 * who should be forced to retranslate.
 * Usage: {@code StringsResourceTranslator android/res/ [key_1 ...]}</p>
 *
 * @author Sean Owen
 */
public final class StringsResourceTranslator {

  private static final Charset UTF8 = Charset.forName("UTF-8");
  private static final Pattern ENTRY_PATTERN = Pattern.compile("<string name=\"([^\"]+)\">([^<]+)</string>");
  private static final Pattern STRINGS_FILE_NAME_PATTERN = Pattern.compile("values-(.+)");
  private static final Pattern TRANSLATE_RESPONSE_PATTERN = Pattern.compile(
      "\\{\"translatedText\":\"([^\"]+)\"\\}");

  private static final String APACHE_2_LICENSE =
      "<!--\n" +
      " Copyright (C) 2010 ZXing authors\n" +
      '\n' +
      " Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
      " you may not use this file except in compliance with the License.\n" +
      " You may obtain a copy of the License at\n" +
      '\n' +
      "      http://www.apache.org/licenses/LICENSE-2.0\n" +
      '\n' +
      " Unless required by applicable law or agreed to in writing, software\n" +
      " distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
      " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
      " See the License for the specific language governing permissions and\n" +
      " limitations under the License.\n" +
      " -->\n";

  private static final Map<String,String> LANGUAGE_CODE_MASSAGINGS = new HashMap<String,String>(7);
  static {
    LANGUAGE_CODE_MASSAGINGS.put("ja-rJP", "ja");
    LANGUAGE_CODE_MASSAGINGS.put("zh-rCN", "zh-cn");
    LANGUAGE_CODE_MASSAGINGS.put("zh-rTW", "zh-tw");
	  LANGUAGE_CODE_MASSAGINGS.put("kr",     "ko");
  }

  private StringsResourceTranslator() {}

  public static void main(String[] args) throws IOException {

    File resDir = new File(args[0]);
    File valueDir = new File(resDir, "values");
    File stringsFile = new File(valueDir, "strings.xml");
    Collection<String> forceRetranslation = Arrays.asList(args).subList(1, args.length);

    File[] translatedValuesDirs = resDir.listFiles(new FileFilter() {
      public boolean accept(File file) {
        return file.isDirectory() && file.getName().startsWith("values-");
      }
    });
    for (File translatedValuesDir : translatedValuesDirs) {
      File translatedStringsFile = new File(translatedValuesDir, "strings.xml");
      translate(stringsFile, translatedStringsFile, forceRetranslation);
    }

  }

  private static void translate(File englishFile, File translatedFile, Collection<String> forceRetranslation)
      throws IOException {

    SortedMap<String,String> english = readLines(englishFile);
    SortedMap<String,String> translated = readLines(translatedFile);
    String parentName = translatedFile.getParentFile().getName();

    Matcher stringsFileNameMatcher = STRINGS_FILE_NAME_PATTERN.matcher(parentName);
    stringsFileNameMatcher.find();
    String language = stringsFileNameMatcher.group(1);
    String massagedLanguage = LANGUAGE_CODE_MASSAGINGS.get(language);
    if (massagedLanguage != null) {
      language = massagedLanguage;
    }

    System.out.println("Translating " + language);

    File resultTempFile = File.createTempFile(parentName, ".xml");

    boolean anyChange = false;
    Writer out = null;
    try {
      out = new OutputStreamWriter(new FileOutputStream(resultTempFile), UTF8);
      out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
      out.write(APACHE_2_LICENSE);
      out.write("<resources>\n");

      for (Map.Entry<String,String> englishEntry : english.entrySet()) {
        String key = englishEntry.getKey();
        out.write("  <string name=\"");
        out.write(key);
        out.write("\">");

        String translatedString = translated.get(key);
        if (translatedString == null || forceRetranslation.contains(key)) {
          anyChange = true;
          translatedString = translateString(englishEntry.getValue(), language);
        }
        out.write(translatedString);

        out.write("</string>\n");
      }

      out.write("</resources>\n");
      out.flush();

    } finally {
      quietClose(out);
    }

    if (anyChange) {
      System.out.println("  Writing translations");
      translatedFile.delete();
      resultTempFile.renameTo(translatedFile);
    }
  }

  private static String translateString(String english, String language) throws IOException {
    System.out.println("  Need translation for " + english);
    URL translateURL = new URL(
        "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=" +
        URLEncoder.encode(english, "UTF-8") +
        "&langpair=en%7C" + language);
    StringBuilder translateResult = new StringBuilder();
    Reader in = null;
    try {
      in = new InputStreamReader(translateURL.openStream(), UTF8);
      char[] buffer = new char[1024];
      int charsRead;
      while ((charsRead = in.read(buffer)) > 0) {
        translateResult.append(buffer, 0, charsRead);
      }
    } finally {
      quietClose(in);
    }
    Matcher m = TRANSLATE_RESPONSE_PATTERN.matcher(translateResult);
    if (!m.find()) {
      throw new IOException("No translate result");
    }
    String translation = m.group(1);
    System.out.println("  Got translation " + translation);
    return translation;
  }

  private static SortedMap<String,String> readLines(File file) throws IOException {
    SortedMap<String,String> entries = new TreeMap<String,String>();
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), UTF8));
      String line;
      while ((line = reader.readLine()) != null) {
        Matcher m = ENTRY_PATTERN.matcher(line);
        if (m.find()) {
          String key = m.group(1);
          String value = m.group(2);
          entries.put(key, value);
        }
      }
      return entries;
    } finally {
      quietClose(reader);
    }
  }

  private static void quietClose(Closeable closeable) {
    if (closeable != null) {
      try {
        closeable.close();
      } catch (IOException ioe) {
        // continue
      }
    }
  }

}
