// Copyright 2018 The Bazel Authors. All rights reserved.
//
// 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.devtools.build.lib.rules.android;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ExecutionRequirements;
import com.google.devtools.build.lib.actions.ParamFileInfo;
import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
import com.google.devtools.build.lib.util.OS;
import com.google.errorprone.annotations.CompileTimeConstant;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;

/** Builder for actions that invoke the Android BusyBox. */
public final class BusyBoxActionBuilder {

  // Some flags (e.g. --mainData) may specify lists (or lists of lists) separated by special
  // characters (colon, semicolon, hashmark, ampersand) that don't work on Windows, and quoting
  // semantics are very complicated (more so than in Bash), so let's just always use a parameter
  // file.
  // TODO(laszlocsomor), TODO(corysmith): restructure the Android BusyBux's flags by deprecating
  // list-type and list-of-list-type flags that use such problematic separators in favor of
  // multi-value flags (to remove one level of listing) and by changing all list separators to a
  // platform-safe character (= comma).
  private static final ParamFileInfo FORCED_PARAM_FILE_INFO =
      ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED)
          .setUseAlways(OS.getCurrent() == OS.WINDOWS)
          .build();

  private static final ParamFileInfo WORKERS_FORCED_PARAM_FILE_INFO =
      ParamFileInfo.builder(ParameterFileType.UNQUOTED)
          .setUseAlways(true)
          .build();

  private final AndroidDataContext dataContext;
  private final NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder();
  private final ImmutableList.Builder<Artifact> outputs = ImmutableList.builder();
  private final SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder();
  private final CustomCommandLine.Builder commandLine = CustomCommandLine.builder();

  public static BusyBoxActionBuilder create(
      AndroidDataContext dataContext, @CompileTimeConstant String toolName) {
    BusyBoxActionBuilder builder = new BusyBoxActionBuilder(dataContext);
    builder.commandLine.add("--tool").add(toolName).add("--");
    return builder;
  }

  private BusyBoxActionBuilder(AndroidDataContext dataContext) {
    this.dataContext = dataContext;
  }

  /** Adds a direct input artifact. */
  public BusyBoxActionBuilder addInput(Artifact value) {
    Preconditions.checkNotNull(value);
    commandLine.addExecPath(value);
    inputs.add(value);
    return this;
  }

  /** Adds a direct input artifact. */
  public BusyBoxActionBuilder addInput(@CompileTimeConstant String arg, Artifact value) {
    Preconditions.checkNotNull(value);
    commandLine.addExecPath(arg, value);
    inputs.add(value);
    return this;
  }

  /**
   * Adds a series of direct input artifacts.
   *
   * <p>For efficiency, when adding a NestedSet of artifacts, use one of the transitive methods,
   * such as {@link #addTransitiveFlag(String, NestedSet, AndroidDataConverter)} and {@link
   * #addTransitiveInputValues(NestedSet)}, instead.
   *
   * @param value a string representation of the value artifacts
   */
  public BusyBoxActionBuilder addInput(
      @CompileTimeConstant String arg, String value, Iterable<Artifact> valueArtifacts) {
    Preconditions.checkState(
        !(valueArtifacts instanceof NestedSet),
        "NestedSet values should not be added here, since they will be inefficiently collapsed in"
            + " analysis time. Use one of the transitive input methods instead.");
    commandLine.add(arg, value);
    inputs.addAll(valueArtifacts);
    return this;
  }

  /** Adds the given input artifacts without any command line options. */
  public BusyBoxActionBuilder addInputs(Iterable<Artifact> inputs) {
    this.inputs.addAll(inputs);
    return this;
  }

  /** Adds an input artifact if it is non-null */
  public BusyBoxActionBuilder maybeAddInput(
      @CompileTimeConstant String arg, @Nullable Artifact value) {
    if (value != null) {
      addInput(arg, value);
    }
    return this;
  }

  /** Adds an input artifact if it is non-null */
  public BusyBoxActionBuilder maybeAddInput(@Nullable Artifact value) {
    if (value != null) {
      this.inputs.add(value);
    }
    return this;
  }

  /**
   * Adds a series of direct input artifacts if the list containing them is not null or empty.
   *
   * <p>For efficiency, when adding a NestedSet of artifacts, use one of the transitive methods,
   * such as {@link #addTransitiveFlag(String, NestedSet, AndroidDataConverter)} and {@link
   * #addTransitiveInputValues(NestedSet)}, instead.
   */
  public BusyBoxActionBuilder maybeAddInput(
      @CompileTimeConstant String arg, @Nullable Collection<Artifact> values) {
    if (values != null && !values.isEmpty()) {
      commandLine.addExecPaths(arg, values);
      inputs.addAll(values);
    }
    return this;
  }

  /**
   * Adds a series of direct input artifacts if the list containing them is not null or empty.
   *
   * <p>For efficiency, when adding a NestedSet of artifacts, use one of the transitive methods,
   * such as {@link #addTransitiveFlag(String, NestedSet, AndroidDataConverter)} and {@link
   * #addTransitiveInputValues(NestedSet)}, instead.
   *
   * @param value a string representation of the value artifacts
   */
  public BusyBoxActionBuilder maybeAddInput(
      @CompileTimeConstant String arg,
      String value,
      @Nullable Collection<Artifact> valueArtifacts) {
    if (valueArtifacts != null && !valueArtifacts.isEmpty()) {
      addInput(arg, value, valueArtifacts);
    }
    return this;
  }

  /** Adds an output artifact */
  public BusyBoxActionBuilder addOutput(@CompileTimeConstant String arg, Artifact value) {
    Preconditions.checkNotNull(value);
    commandLine.addExecPath(arg, value);
    outputs.add(value);
    return this;
  }

  /** Adds the given output artifacts without adding any command line options. */
  public BusyBoxActionBuilder addOutputs(Iterable<Artifact> outputs) {
    this.outputs.addAll(outputs);
    return this;
  }

  /** Adds an output artifact if it is non-null */
  public BusyBoxActionBuilder maybeAddOutput(
      @CompileTimeConstant String arg, @Nullable Artifact value) {
    if (value != null) {
      return addOutput(arg, value);
    }
    return this;
  }

  /**
   * Adds a series of transitive input artifacts.
   *
   * <p>These artifacts will not be mentioned on the command line - use {@link
   * #addTransitiveFlag(String, NestedSet, AndroidDataConverter)} for that.
   */
  public BusyBoxActionBuilder addTransitiveInputValues(NestedSet<Artifact> values) {
    inputs.addTransitive(values);
    return this;
  }

  /**
   * Adds an efficient flag based on transitive values.
   *
   * <p>The flag will only be specified once, followed by the joined values specified by the
   * converter, for example: --flag value1,value2
   *
   * <p>The values will only be collapsed and turned into a flag at execution time.
   *
   * <p>The values will not be added as inputs - use {@link #addTransitiveInputValues(NestedSet)}
   * for that.
   */
  public <T> BusyBoxActionBuilder addTransitiveFlag(
      @CompileTimeConstant String arg,
      NestedSet<? extends T> transitiveValues,
      AndroidDataConverter<T> converter) {
    commandLine.addAll(arg, converter.getVectorArg(transitiveValues));
    return this;
  }

  /**
   * Adds an efficient flag based on transitive values.
   *
   * <p>Each transitive value, as created using the converter, will be proceeded by the flag, for
   * example: --flag value1 --flag value2
   *
   * <p>The values will only be collapsed and turned into a flag at execution time.
   *
   * <p>The values will not be added as inputs - use {@link #addTransitiveInputValues(NestedSet)}
   * for that.
   */
  public <T> BusyBoxActionBuilder addTransitiveFlagForEach(
      @CompileTimeConstant String arg,
      NestedSet<? extends T> transitiveValues,
      AndroidDataConverter<T> converter) {
    commandLine.addAll(converter.getVectorArgForEach(arg, transitiveValues));
    return this;
  }

  /**
   * Adds an efficient flag and inputs based on transitive values.
   *
   * <p>Each value will be separated on the command line by the ':' character, the option parser's
   * PathListConverter delimiter.
   *
   * <p>Unlike other transitive input methods in this class, this method adds the values to both the
   * command line and the list of inputs.
   */
  public BusyBoxActionBuilder addTransitiveVectoredInput(
      @CompileTimeConstant String arg, NestedSet<Artifact> values) {
    commandLine.addExecPaths(arg, VectorArg.join(":").each(values));
    inputs.addTransitive(values);
    return this;
  }

  /** Adds a flag with a value set to the current target's label */
  public BusyBoxActionBuilder addLabelFlag(@CompileTimeConstant String arg) {
    commandLine.addLabel(arg, dataContext.getLabel());
    return this;
  }

  /** Adds a flag with no arguments to the command line. */
  public BusyBoxActionBuilder addFlag(@CompileTimeConstant String value) {
    commandLine.add(value);
    return this;
  }

  /** Adds a flag with a String value to the command line. */
  public BusyBoxActionBuilder addFlag(@CompileTimeConstant String arg, String value) {
    Preconditions.checkNotNull(value);
    commandLine.add(arg, value);
    return this;
  }

  /** If the condition is true, adds a flag with no arguments to the command line. */
  public BusyBoxActionBuilder maybeAddFlag(@CompileTimeConstant String arg, boolean condition) {
    if (condition) {
      commandLine.add(arg);
    }
    return this;
  }

  /** If the flag is a non-null, non-empty String, adds the flag and value to the command line. */
  public BusyBoxActionBuilder maybeAddFlag(
      @CompileTimeConstant String arg, @Nullable String value) {
    if (value != null && !value.isEmpty()) {
      addFlag(arg, value);
    }
    return this;
  }

  /**
   * Efficiently adds a flag and a list of values to the command line.
   *
   * <p>The values will be joined in execution and separated by commas.
   */
  public BusyBoxActionBuilder addVectoredFlag(
      @CompileTimeConstant String arg, List<String> values) {
    Preconditions.checkNotNull(values);
    commandLine.addAll(arg, VectorArg.join(",").each(values));

    return this;
  }

  /**
   * If the values are not null or empty, efficiently adds a flag with them to the command line.
   *
   * <p>The values will be joined in execution and separated by commas.
   */
  public BusyBoxActionBuilder maybeAddVectoredFlag(
      @CompileTimeConstant String arg, @Nullable List<String> values) {
    if (values != null && !values.isEmpty()) {
      addVectoredFlag(arg, values);
    }
    return this;
  }

  /** Adds aapt to the command line and inputs. */
  public BusyBoxActionBuilder addAapt(AndroidAaptVersion aaptVersion) {
    FilesToRunProvider aapt;
    if (aaptVersion == AndroidAaptVersion.AAPT2) {
      aapt = dataContext.getSdk().getAapt2();
      commandLine.addExecPath("--aapt2", aapt.getExecutable());
    } else {
      aapt = dataContext.getSdk().getAapt();
      commandLine.addExecPath("--aapt", aapt.getExecutable());
    }

    spawnActionBuilder.addTool(aapt);

    return this;
  }

  /** Adds the Android JAR from the SDK to the command line and inputs */
  public BusyBoxActionBuilder addAndroidJar() {
    return addInput("--androidJar", dataContext.getSdk().getAndroidJar());
  }

  /**
   * Builds and registers this action.
   *
   * @param message a progress message (visible in Bazel output), for example "Running tool". The
   *     current label will be appended to this message.
   * @param mnemonic a mnemonic used to indicate the tool being run, for example, "BusyBoxTool".
   */
  public void buildAndRegister(String message, String mnemonic) {
    spawnActionBuilder
        .useDefaultShellEnvironment()
        .addTransitiveInputs(inputs.build())
        .addOutputs(outputs.build())
        .setExecutable(dataContext.getBusybox())
        .setProgressMessage("%s for %s", message, dataContext.getLabel())
        .setMnemonic(mnemonic);

    if (dataContext.isPersistentBusyboxToolsEnabled()) {
      spawnActionBuilder
          .setExecutionInfo(ExecutionRequirements.WORKER_MODE_ENABLED)
          .addCommandLine(commandLine.build(), WORKERS_FORCED_PARAM_FILE_INFO);
    } else {
      spawnActionBuilder.addCommandLine(commandLine.build(), FORCED_PARAM_FILE_INFO);
    }

    dataContext.registerAction(spawnActionBuilder);
  }
}
