// Copyright 2014 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.util;

import static com.google.common.base.StandardSystemProperty.JAVA_IO_TMPDIR;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.devtools.build.lib.shell.Command;
import com.google.devtools.build.lib.vfs.Path;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Implements OS aware {@link Command} builder. At this point only Linux, Mac
 * and Windows XP are supported.
 *
 * <p>Builder will also apply heuristic to identify trivial cases where
 * unix-like command lines could be automatically converted into the
 * Windows-compatible form.
 *
 * <p>TODO(bazel-team): (2010) Some of the code here is very similar to the
 * {@link com.google.devtools.build.lib.shell.Shell} class. This should be looked at.
 */
public final class CommandBuilder {

  private static final ImmutableList<String> SHELLS = ImmutableList.of("/bin/sh", "/bin/bash");

  private static final Splitter ARGV_SPLITTER = Splitter.on(CharMatcher.anyOf(" \t"));

  private final OS system;
  private final List<String> argv = new ArrayList<>();
  private final Map<String, String> env = new HashMap<>();
  private File workingDir = null;
  private boolean useShell = false;

  public CommandBuilder() {
    this(OS.getCurrent());
  }

  @VisibleForTesting
  CommandBuilder(OS system) {
    this.system = system;
  }

  public CommandBuilder addArg(String arg) {
    Preconditions.checkNotNull(arg, "Argument must not be null");
    argv.add(arg);
    return this;
  }

  public CommandBuilder addArgs(Iterable<String> args) {
    Preconditions.checkArgument(!Iterables.contains(args, null), "Arguments must not be null");
    Iterables.addAll(argv, args);
    return this;
  }

  public CommandBuilder addArgs(String... args) {
    return addArgs(Arrays.asList(args));
  }

  public CommandBuilder addEnv(Map<String, String> env) {
    Preconditions.checkNotNull(env);
    this.env.putAll(env);
    return this;
  }

  public CommandBuilder emptyEnv() {
    env.clear();
    return this;
  }

  public CommandBuilder setEnv(Map<String, String> env) {
    emptyEnv();
    addEnv(env);
    return this;
  }

  public CommandBuilder setWorkingDir(Path path) {
    Preconditions.checkNotNull(path);
    workingDir = path.getPathFile();
    return this;
  }

  public CommandBuilder useTempDir() {
    workingDir = new File(JAVA_IO_TMPDIR.value());
    return this;
  }

  public CommandBuilder useShell(boolean useShell) {
    this.useShell = useShell;
    return this;
  }

  private boolean argvStartsWithSh() {
    return argv.size() >= 2 && SHELLS.contains(argv.get(0)) && "-c".equals(argv.get(1));
  }

  private String[] transformArgvForLinux() {
    // If command line already starts with "/bin/sh -c", ignore useShell attribute.
    if (useShell && !argvStartsWithSh()) {
      // c.g.io.base.shell.Shell.shellify() actually concatenates argv into the space-separated
      // string here. Not sure why, but we will do the same.
      return new String[] { "/bin/sh", "-c", Joiner.on(' ').join(argv) };
    }
    return argv.toArray(new String[argv.size()]);
  }

  private String[] transformArgvForWindows() {
    List<String> modifiedArgv;
    // Heuristic: replace "/bin/sh -c" with something more appropriate for Windows.
    if (argvStartsWithSh()) {
      useShell = true;
      modifiedArgv = Lists.newArrayList(argv.subList(2, argv.size()));
    } else {
      modifiedArgv = Lists.newArrayList(argv);
    }

    if (!modifiedArgv.isEmpty()) {
      // args can contain whitespace, so figure out the first word
      String argv0 = modifiedArgv.get(0);
      String command = ARGV_SPLITTER.split(argv0).iterator().next();

      // Automatically enable CMD.EXE use if we are executing something else besides "*.exe" file.
      // When use CMD.EXE to invoke a bat/cmd file, the file path must have '\' instead of '/'
      if (!command.toLowerCase().endsWith(".exe")) {
        useShell = true;
        modifiedArgv.set(0, argv0.replace('/', '\\'));
      }
    } else {
      // This is degenerate "/bin/sh -c" case. We ensure that Windows behavior is identical
      // to the Linux - call shell that will do nothing.
      useShell = true;
    }
    if (useShell) {
      // /S - strip first and last quotes and execute everything else as is.
      // /E:ON - enable extended command set.
      // /V:ON - enable delayed variable expansion
      // /D - ignore AutoRun registry entries.
      // /C - execute command. This must be the last option before the command itself.
      return new String[] { "CMD.EXE", "/S", "/E:ON", "/V:ON", "/D", "/C",
          Joiner.on(' ').join(modifiedArgv) };
    } else {
      return modifiedArgv.toArray(new String[argv.size()]);
    }
  }

  public Command build() {
    Preconditions.checkState(system != OS.UNKNOWN, "Unidentified operating system");
    Preconditions.checkNotNull(workingDir, "Working directory must be set");
    Preconditions.checkState(!argv.isEmpty(), "At least one argument is expected");

    return new Command(
        system == OS.WINDOWS ? transformArgvForWindows() : transformArgvForLinux(),
        env, workingDir);
  }
}
