/*
 * Copyright 2013 Google Inc.
 *
 * 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.template.soy;

import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.template.soy.base.SoySyntaxException;
import com.google.template.soy.msgs.SoyMsgBundle;
import com.google.template.soy.msgs.SoyMsgBundleHandler;
import com.google.template.soy.msgs.SoyMsgBundleHandler.OutputFileOptions;
import com.google.template.soy.shared.internal.MainEntryPointUtils;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.kohsuke.args4j.Option;

/**
 * Executable for pruning messages from extracted msgs files, given a set of Soy files as reference
 * for which messages to keep.
 *
 */
public final class SoyMsgPruner extends AbstractSoyCompiler {
  @Option(
      name = "--allowExternalCalls",
      usage = "Whether to allow external calls. New projects should set this to false, and" +
          " existing projects should remove existing external calls and then set this to false." +
          " It will save you a lot of headaches. Currently defaults to true for backward" +
          " compatibility.")
  private boolean allowExternalCalls = true;

  @Option(
      name = "--locales",
      usage = "[Required] Comma-delimited list of locales.",
      handler = MainClassUtils.StringListOptionHandler.class)
  private List<String> locales = Lists.newArrayList();

  @Option(
      name = "--inputMsgFilePathFormat",
      usage = "[Required] A format string that specifies how to build the path to each translated" +
          " messages file. The format string can include literal characters as well as the" +
          " placeholders {INPUT_PREFIX}, {LOCALE}, and {LOCALE_LOWER_CASE}. Note" +
          " {LOCALE_LOWER_CASE} also turns dash into underscore, e.g. pt-BR becomes pt_br. The" +
          " format string must end with an extension matching the message file format" +
          " (case-insensitive).")
  private String inputMsgFilePathFormat = "";

  @Option(
      name = "--outputMsgFilePathFormat",
      usage = "[Required] A format string that specifies how to build the path to each pruned" +
          " output translated messages file. The format string can include literal characters as" +
          " well as the placeholders {INPUT_PREFIX}, {LOCALE}, and {LOCALE_LOWER_CASE}. Note" +
          " {LOCALE_LOWER_CASE} also turns dash into underscore, e.g. pt-BR becomes pt_br. The" +
          " format string must end with an extension matching the message file format" +
          " (case-insensitive).")
  private String outputMsgFilePathFormat = "";

  @Option(
      name = "--msgPluginModule",
      usage = "Specifies the full class name of a Guice module that binds a" +
          " BidirectionalSoyMsgPlugin.")
  private Module msgPluginModule;

  /**
   * Prunes messages from XTB files, given a set of Soy files as reference for which messages to
   * keep.
   *
   * @param args Should contain command-line flags and the list of paths to the Soy files.
   * @throws IOException If there are problems reading the input files or writing the output file.
   * @throws SoySyntaxException If a syntax error is detected.
   */
  public static void main(String[] args) throws IOException, SoySyntaxException {
    new SoyMsgPruner().runMain(args);
  }

  @Override
  boolean acceptsSourcesAsArguments() {
    return false;
  }

  @Override
  Optional<Module> msgPluginModule() {
    return Optional.fromNullable(msgPluginModule);
  }

  @Override
  void compile(SoyFileSet.Builder sfsBuilder, Injector injector) throws IOException {
    sfsBuilder.setAllowExternalCalls(allowExternalCalls);
    SoyFileSet sfs = sfsBuilder.build();
    SoyMsgBundleHandler msgBundleHandler = injector.getInstance(SoyMsgBundleHandler.class);

    // Main loop.
    for (String locale : locales) {

      // Get the input msg bundle.
      String inputMsgFilePath = MainEntryPointUtils.buildFilePath(
          inputMsgFilePathFormat, locale, null, inputPrefix);
      SoyMsgBundle origTransMsgBundle = msgBundleHandler.createFromFile(new File(inputMsgFilePath));
      if (origTransMsgBundle.getLocaleString() == null) {
        throw new IOException("Error opening or parsing message file " + inputMsgFilePath);
      }

      // Do the pruning.
      SoyMsgBundle prunedTransSoyMsgBundle = sfs.pruneTranslatedMsgs(origTransMsgBundle);

      // Write out the pruned msg bundle.
      String outputMsgFilePath = MainEntryPointUtils.buildFilePath(
          outputMsgFilePathFormat, locale, inputMsgFilePath, inputPrefix);
      msgBundleHandler.writeToTranslatedMsgsFile(
          prunedTransSoyMsgBundle, new OutputFileOptions(), new File(outputMsgFilePath));
    }
  }
}
