/*
 * 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.shared.internal;


import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.template.soy.base.internal.BaseUtils;
import com.google.template.soy.soytree.SoyFileNode;

import java.io.File;

import javax.annotation.Nullable;

/**
 * Private shared utils for main entry point classes (e.g. JsSrcMain) or classes with a main()
 * method.
 *
 * <p> Important: Do not use outside of Soy code (treat as superpackage-private).
 *
 */
public class MainEntryPointUtils {


  private MainEntryPointUtils() {}

  /**
   * Maps output paths to indices of inputs that should be emitted to them.
   *
   * @param locale The locale for the file path, or null if not applicable.
   * @param outputPathFormat The format string defining how to format output file paths.
   * @param inputPathsPrefix The input path prefix, or empty string if none.
   * @param fileNodes A list of the SoyFileNodes being written.
   * @return A map of output file paths to their respective input indicies.
   */
  public static Multimap<String, Integer> mapOutputsToSrcs(
      @Nullable String locale, String outputPathFormat, String inputPathsPrefix,
      ImmutableList<SoyFileNode> fileNodes) {
    Multimap<String, Integer> outputs = ArrayListMultimap.create();

    // First, check that the parent directories for all output files exist, and group the output
    // files by the inputs that go there.
    // This means that the compiled source from multiple input files might be written to a single
    // output file, as is the case when there are multiple inputs, and the output format string
    // contains no wildcards.
    for (int i = 0; i < fileNodes.size(); ++i) {
      SoyFileNode inputFile = fileNodes.get(i);
      String inputFilePath = inputFile.getFilePath();
      String outputFilePath = MainEntryPointUtils.buildFilePath(
          outputPathFormat, locale, inputFilePath, inputPathsPrefix);

      BaseUtils.ensureDirsExistInPath(outputFilePath);
      outputs.put(outputFilePath, i);
    }
    return outputs;
  }

  /**
   * Builds a specific file path given a path format and the info needed for replacing placeholders.
   *
   * @param filePathFormat The format string defining how to build the file path.
   * @param locale The locale for the file path, or null if not applicable.
   * @param inputFilePath Only applicable if you need to replace the placeholders {INPUT_DIRECTORY},
   *     {INPUT_FILE_NAME}, and {INPUT_FILE_NAME_NO_EXT} (otherwise pass null). This is the full
   *     path of the input file (including the input path prefix).
   * @param inputPathPrefix The input path prefix, or empty string if none.
   * @return The output file path corresponding to the given input file path.
   */
  public static String buildFilePath(
      String filePathFormat, @Nullable String locale, @Nullable String inputFilePath,
      String inputPathPrefix) {

    String path = filePathFormat;

    if (locale != null) {
      path = path.replace("{LOCALE}", locale);
      path = path.replace("{LOCALE_LOWER_CASE}", locale.toLowerCase().replace('-', '_'));
    }

    path = path.replace("{INPUT_PREFIX}", inputPathPrefix);

    if (inputFilePath != null) {
      // Remove the prefix (if any) from the input file path.
      inputFilePath = inputFilePath.substring(inputPathPrefix.length());

      // Compute directory and file name.
      int lastSlashIndex = inputFilePath.lastIndexOf(File.separatorChar);
      String directory = inputFilePath.substring(0, lastSlashIndex + 1);
      String fileName = inputFilePath.substring(lastSlashIndex + 1);

      // Compute file name without extension.
      int lastDotIndex = fileName.lastIndexOf('.');
      if (lastDotIndex == -1) {
        lastDotIndex = fileName.length();
      }
      String fileNameNoExt = fileName.substring(0, lastDotIndex);

      // Substitute placeholders.
      path = path.replace("{INPUT_DIRECTORY}", directory);
      path = path.replace("{INPUT_FILE_NAME}", fileName);
      path = path.replace("{INPUT_FILE_NAME_NO_EXT}", fileNameNoExt);
    }

    // Remove redundant /'s if any placeholder representing a directory was empty.
    path = path.replaceAll("//", "/");

    return path;
  }

}
