// 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.exec;

import static java.util.stream.Collectors.joining;

import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.flogger.GoogleLogger;
import com.google.devtools.build.lib.actions.ActionContext;
import com.google.devtools.build.lib.actions.DynamicStrategyRegistry;
import com.google.devtools.build.lib.actions.SandboxedSpawnStrategy;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.SpawnStrategy;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Reporter;
import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.server.FailureDetails.ExecutionOptions.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.RegexFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

/**
 * Registry that collects spawn strategies and rules about their applicability and makes them
 * available for querying through various registry interfaces.
 *
 * <p>An instance of this registry can be created using its {@linkplain Builder builder}, which is
 * available to Blaze modules during server startup.
 */
public final class SpawnStrategyRegistry
    implements DynamicStrategyRegistry, ActionContext, RemoteLocalFallbackRegistry {
  private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();

  private final ImmutableListMultimap<String, SpawnStrategy> mnemonicToStrategies;
  private final ImmutableListMultimap<RegexFilter, SpawnStrategy> filterToStrategies;
  private final ImmutableList<? extends SpawnStrategy> defaultStrategies;
  private final ImmutableMultimap<String, SandboxedSpawnStrategy> mnemonicToRemoteDynamicStrategies;
  private final ImmutableMultimap<String, SandboxedSpawnStrategy> mnemonicToLocalDynamicStrategies;
  @Nullable private final AbstractSpawnStrategy remoteLocalFallbackStrategy;

  private SpawnStrategyRegistry(
      ImmutableListMultimap<String, SpawnStrategy> mnemonicToStrategies,
      ImmutableListMultimap<RegexFilter, SpawnStrategy> filterToStrategies,
      ImmutableList<? extends SpawnStrategy> defaultStrategies,
      ImmutableMultimap<String, SandboxedSpawnStrategy> mnemonicToRemoteDynamicStrategies,
      ImmutableMultimap<String, SandboxedSpawnStrategy> mnemonicToLocalDynamicStrategies,
      @Nullable AbstractSpawnStrategy remoteLocalFallbackStrategy) {
    this.mnemonicToStrategies = mnemonicToStrategies;
    this.filterToStrategies = filterToStrategies;
    this.defaultStrategies = defaultStrategies;
    this.mnemonicToRemoteDynamicStrategies = mnemonicToRemoteDynamicStrategies;
    this.mnemonicToLocalDynamicStrategies = mnemonicToLocalDynamicStrategies;
    this.remoteLocalFallbackStrategy = remoteLocalFallbackStrategy;
    logger.atInfo().log("Default strategies: %s", defaultStrategies);
    logger.atInfo().log("Filter strategies: %s", filterToStrategies);
    logger.atInfo().log("Mnemonic strategies: %s", mnemonicToStrategies);
    logger.atInfo().log("Remote strategies: %s", mnemonicToRemoteDynamicStrategies);
    logger.atInfo().log("Local strategies: %s", mnemonicToLocalDynamicStrategies);
    logger.atInfo().log("Fallback strategies: %s", remoteLocalFallbackStrategy);
  }

  /**
   * Returns the strategies applying to the given spawn, in priority order.
   *
   * <p>Which strategies are returned is based on the precedence as documented on the construction
   * methods of {@linkplain Builder this registry's builder}.
   *
   * <p>If the reason for selecting the context is worth mentioning to the user, logs a message
   * using the given {@link Reporter}.
   */
  @VisibleForTesting
  public List<? extends SpawnStrategy> getStrategies(Spawn spawn, EventHandler reporter) {
    // Don't override test strategies by --strategy_regexp for backwards compatibility.
    if (spawn.getResourceOwner() != null && !"TestRunner".equals(spawn.getMnemonic())) {
      String description = spawn.getResourceOwner().getProgressMessage();
      if (description != null) {
        for (Map.Entry<RegexFilter, Collection<SpawnStrategy>> filterStrategies :
            filterToStrategies.asMap().entrySet()) {
          if (filterStrategies.getKey().isIncluded(description)) {
            // TODO(schmitt): Why is this done here and not after running canExec?
            reporter.handle(
                Event.progress(description + " with context " + filterStrategies.getValue()));
            return ImmutableList.copyOf(filterStrategies.getValue());
          }
        }
      }
    }
    if (mnemonicToStrategies.containsKey(spawn.getMnemonic())) {
      return mnemonicToStrategies.get(spawn.getMnemonic());
    }
    return defaultStrategies;
  }

  @Override
  public void notifyUsedDynamic(ActionContext.ActionContextRegistry actionContextRegistry) {
    for (SandboxedSpawnStrategy strategy : mnemonicToLocalDynamicStrategies.values()) {
      strategy.usedContext(actionContextRegistry);
    }
    for (SandboxedSpawnStrategy strategy : mnemonicToRemoteDynamicStrategies.values()) {
      strategy.usedContext(actionContextRegistry);
    }
  }

  @Override
  public List<SandboxedSpawnStrategy> getDynamicSpawnActionContexts(
      Spawn spawn, DynamicMode dynamicMode) {
    ImmutableMultimap<String, SandboxedSpawnStrategy> mnemonicToDynamicStrategies =
        dynamicMode == DynamicStrategyRegistry.DynamicMode.REMOTE
            ? mnemonicToRemoteDynamicStrategies
            : mnemonicToLocalDynamicStrategies;
    return ImmutableList.<SandboxedSpawnStrategy>builder()
        .addAll(mnemonicToDynamicStrategies.get(spawn.getMnemonic()))
        .addAll(mnemonicToDynamicStrategies.get(""))
        .build();
  }

  @Nullable
  @Override
  public AbstractSpawnStrategy getRemoteLocalFallbackStrategy() {
    return remoteLocalFallbackStrategy;
  }

  /**
   * Notifies all (non-dynamic) strategies stored in this registry that they are {@linkplain
   * SpawnStrategy#usedContext used}.
   */
  public void notifyUsed(ActionContext.ActionContextRegistry actionContextRegistry) {
    for (SpawnStrategy strategy : filterToStrategies.values()) {
      strategy.usedContext(actionContextRegistry);
    }
    for (SpawnStrategy strategy : mnemonicToStrategies.values()) {
      strategy.usedContext(actionContextRegistry);
    }
    for (SpawnStrategy strategy : defaultStrategies) {
      strategy.usedContext(actionContextRegistry);
    }
    if (remoteLocalFallbackStrategy != null) {
      remoteLocalFallbackStrategy.usedContext(actionContextRegistry);
    }
  }

  /**
   * Records the list of all spawn strategies that can be returned by the various query methods of
   * this registry to the given reporter.
   */
  void writeSpawnStrategiesTo(Reporter reporter) {
    for (Map.Entry<String, Collection<SpawnStrategy>> entry :
        mnemonicToStrategies.asMap().entrySet()) {
      reporter.handle(
          Event.info(
              String.format(
                  "MnemonicToStrategyImplementations: \"%s\" = [%s]",
                  entry.getKey(), toImplementationNames(entry.getValue()))));
    }

    for (Map.Entry<RegexFilter, Collection<SpawnStrategy>> entry :
        filterToStrategies.asMap().entrySet()) {
      Collection<SpawnStrategy> value = entry.getValue();
      reporter.handle(
          Event.info(
              String.format(
                  "FilterToStrategyImplementations: \"%s\" = [%s]",
                  entry.getKey(), toImplementationNames(value))));
    }

    reporter.handle(
        Event.info(
            String.format(
                "DefaultStrategyImplementations: [%s]", toImplementationNames(defaultStrategies))));

    if (remoteLocalFallbackStrategy != null) {
      reporter.handle(
          Event.info(
              String.format(
                  "RemoteLocalFallbackImplementation: [%s]",
                  remoteLocalFallbackStrategy.getClass().getSimpleName())));
    }

    for (Map.Entry<String, Collection<SandboxedSpawnStrategy>> entry :
        mnemonicToRemoteDynamicStrategies.asMap().entrySet()) {
      reporter.handle(
          Event.info(
              String.format(
                  "MnemonicToRemoteDynamicStrategyImplementations: \"%s\" = [%s]",
                  entry.getKey(), toImplementationNames(entry.getValue()))));
    }

    for (Map.Entry<String, Collection<SandboxedSpawnStrategy>> entry :
        mnemonicToLocalDynamicStrategies.asMap().entrySet()) {
      reporter.handle(
          Event.info(
              String.format(
                  "MnemonicToLocalDynamicStrategyImplementations: \"%s\" = [%s]",
                  entry.getKey(), toImplementationNames(entry.getValue()))));
    }
  }

  private String toImplementationNames(Collection<?> strategies) {
    return strategies.stream()
        .map(strategy -> strategy.getClass().getSimpleName())
        .collect(joining(", "));
  }

  /** Returns a new {@link Builder} suitable for creating instances of SpawnStrategyRegistry. */
  public static Builder builder() {
    return new Builder();
  }

  /**
   * Builder collecting the strategies and restrictions thereon for a {@link SpawnStrategyRegistry}.
   *
   * <p>To {@linkplain SpawnStrategyRegistry#getStrategies match a strategy to a spawn} it needs to
   * be both {@linkplain #registerStrategy registered} and its registered command-line identifier
   * has to match {@linkplain #addDescriptionFilter a filter on the spawn's progress message},
   * {@linkplain #addMnemonicFilter a filter on the spawn's mnemonic} or be part of the default
   * strategies (see below).
   *
   * <p><strong>Default strategies</strong> are either {@linkplain #setDefaultStrategies set
   * explicitly} or, if {@link #setDefaultStrategies} is not called on this builder, comprised of
   * all registered strategies, in registration order (i.e. the earliest strategy registered will be
   * first in the list of strategies returned by {@link SpawnStrategyRegistry#getStrategies}).
   */
  public static final class Builder {

    private ImmutableList<String> explicitDefaultStrategies = ImmutableList.of();
    // TODO(schmitt): Using a list and autovalue so as to be able to reverse order while legacy sort
    //  is supported. Can be converted to same as mnemonics once legacy behavior is removed.
    private final List<FilterAndIdentifiers> filterAndIdentifiers = new ArrayList<>();
    private final HashMap<String, SpawnStrategy> identifierToStrategy = new HashMap<>();
    private final ArrayList<SpawnStrategy> strategiesInRegistrationOrder = new ArrayList<>();

    // Using List values here rather than multimaps as there is no need for the latter's
    // functionality: The values are always replaced as a whole, no adding/creation required.
    private final HashMap<String, List<String>> mnemonicToIdentifiers = new HashMap<>();
    private final HashMap<String, List<String>> mnemonicToRemoteIdentifiers = new HashMap<>();
    private final HashMap<String, List<String>> mnemonicToLocalIdentifiers = new HashMap<>();
    @Nullable private String remoteLocalFallbackStrategyIdentifier;

    /**
     * Adds a filter limiting any spawn whose {@linkplain
     * com.google.devtools.build.lib.actions.ActionExecutionMetadata#getProgressMessage() owner's
     * progress message} matches the regular expression to only use strategies with the given
     * command-line identifiers, in order.
     *
     * <p>If multiple filters match the same spawn (including an identical filter) the order of last
     * applicable filter registered by this method will be used.
     */
    public Builder addDescriptionFilter(RegexFilter filter, List<String> identifiers) {
      filterAndIdentifiers.add(
          new AutoValue_SpawnStrategyRegistry_FilterAndIdentifiers(
              filter, ImmutableList.copyOf(identifiers)));
      return this;
    }

    /**
     * Adds a filter limiting any spawn whose {@linkplain Spawn#getMnemonic() mnemonic}
     * (case-sensitively) matches the given mnemonic to only use strategies with the given
     * command-line identifiers, in order.
     *
     * <p>If the same mnemonic is registered multiple times the last such call will take precedence.
     *
     * <p>Note that if a spawn matches a {@linkplain #addDescriptionFilter registered description
     * filter} that filter will take precedence over any mnemonic-based filters.
     */
    // last one wins
    public Builder addMnemonicFilter(String mnemonic, List<String> identifiers) {
      mnemonicToIdentifiers.put(mnemonic, identifiers);
      return this;
    }

    /**
     * Registers a strategy implementation with this collector, distinguishing it from other
     * strategies with the given command-line identifiers (of which at least one is required).
     *
     * <p>If multiple strategies are registered with the same command-line identifier the last one
     * so registered will take precedence.
     */
    public Builder registerStrategy(SpawnStrategy strategy, List<String> commandlineIdentifiers) {
      Preconditions.checkArgument(
          commandlineIdentifiers.size() >= 1, "At least one commandLineIdentifier must be given");
      for (String identifier : commandlineIdentifiers) {
        identifierToStrategy.put(identifier, strategy);
      }
      strategiesInRegistrationOrder.add(strategy);
      return this;
    }

    public Builder registerStrategy(SpawnStrategy strategy, String... commandlineIdentifiers) {
      return registerStrategy(strategy, ImmutableList.copyOf(commandlineIdentifiers));
    }

    /**
     * Explicitly sets the identifiers of default strategies to use if a spawn matches no filters.
     *
     * <p>Note that if this method is not called on the builder, all registered strategies are
     * considered default strategies, in registration order. See also the {@linkplain Builder class
     * documentation}.
     */
    public Builder setDefaultStrategies(List<String> defaultStrategies) {
      // Ensure there are actual strategies and the contents are not empty.
      Preconditions.checkArgument(!defaultStrategies.isEmpty());
      Preconditions.checkArgument(
          defaultStrategies.stream().anyMatch(strategy -> !"".equals(strategy)));
      this.explicitDefaultStrategies = ImmutableList.copyOf(defaultStrategies);
      return this;
    }

    /**
     * Reset the default strategies (see {@link #setDefaultStrategies}) to the reverse of the order
     * they were registered in.
     */
    public Builder resetDefaultStrategies() {
      this.explicitDefaultStrategies = ImmutableList.of();
      return this;
    }

    /**
     * Sets the strategy names to use in the remote branch of dynamic execution for a set of action
     * mnemonics.
     *
     * <p>During execution, each strategy is {@linkplain SpawnStrategy#canExec(Spawn,
     * ActionContextRegistry) asked} whether it can execute a given Spawn. The first strategy in the
     * list that says so will get the job.
     */
    public Builder addDynamicRemoteStrategies(Map<String, List<String>> strategies) {
      mnemonicToRemoteIdentifiers.putAll(strategies);
      return this;
    }

    /**
     * Sets the strategy names to use in the local branch of dynamic execution for a number of
     * action mnemonics.
     *
     * <p>During execution, each strategy is {@linkplain SpawnStrategy#canExec(Spawn,
     * ActionContextRegistry) asked} whether it can execute a given Spawn. The first strategy in the
     * list that says so will get the job.
     */
    public Builder addDynamicLocalStrategies(Map<String, List<String>> strategies) {
      mnemonicToLocalIdentifiers.putAll(strategies);
      return this;
    }

    /**
     * Sets the commandline identifier of the strategy to be used when falling back from remote to
     * local execution.
     *
     * <p>Note that this is an optional setting, if not provided {@link
     * SpawnStrategyRegistry#getRemoteLocalFallbackStrategy()} will return {@code null}. If the
     * value <b>is</b> provided it must match the commandline identifier of a registered strategy
     * (at {@linkplain #build build} time).
     */
    public Builder setRemoteLocalFallbackStrategyIdentifier(String commandlineIdentifier) {
      this.remoteLocalFallbackStrategyIdentifier = commandlineIdentifier;
      return this;
    }

    /**
     * Finalizes the construction of the registry.
     *
     * @throws AbruptExitException if a strategy command-line identifier was used in a filter or the
     *     default strategies but no strategy for that identifier was registered
     */
    public SpawnStrategyRegistry build() throws AbruptExitException {
      List<FilterAndIdentifiers> orderedFilterAndIdentifiers = Lists.reverse(filterAndIdentifiers);

      ListMultimap<RegexFilter, SpawnStrategy> filterToStrategies = LinkedListMultimap.create();
      for (FilterAndIdentifiers filterAndIdentifier : orderedFilterAndIdentifiers) {
        RegexFilter filter = filterAndIdentifier.filter();
        if (!filterToStrategies.containsKey(filter)) {
          filterToStrategies.putAll(
              filter, toStrategies(filterAndIdentifier.identifiers(), filter));
        }
      }

      ImmutableListMultimap.Builder<String, SpawnStrategy> mnemonicToStrategies =
          new ImmutableListMultimap.Builder<>();
      for (Map.Entry<String, List<String>> entry : mnemonicToIdentifiers.entrySet()) {
        mnemonicToStrategies.putAll(
            entry.getKey(), toStrategies(entry.getValue(), "mnemonic " + entry.getKey()));
      }

      ImmutableListMultimap.Builder<String, SandboxedSpawnStrategy> mnemonicToLocalStrategies =
          new ImmutableListMultimap.Builder<>();
      for (Map.Entry<String, List<String>> entry : mnemonicToLocalIdentifiers.entrySet()) {
        mnemonicToLocalStrategies.putAll(
            entry.getKey(),
            toSandboxedStrategies(entry.getValue(), "local mnemonic " + entry.getKey()));
      }

      ImmutableListMultimap.Builder<String, SandboxedSpawnStrategy> mnemonicToRemoteStrategies =
          new ImmutableListMultimap.Builder<>();
      for (Map.Entry<String, List<String>> entry : mnemonicToRemoteIdentifiers.entrySet()) {
        mnemonicToRemoteStrategies.putAll(
            entry.getKey(),
            toSandboxedStrategies(entry.getValue(), "remote mnemonic " + entry.getKey()));
      }

      AbstractSpawnStrategy remoteLocalFallbackStrategy = null;
      if (remoteLocalFallbackStrategyIdentifier != null) {
        SpawnStrategy strategy =
            toStrategy("remote fallback strategy", remoteLocalFallbackStrategyIdentifier);
        if (!(strategy instanceof AbstractSpawnStrategy)) {
          // TODO(schmitt): Check if all strategies can use the same base and remove check if so.
          throw createExitException(
              String.format(
                  "'%s' was requested for the remote fallback strategy but is not an"
                      + " abstract spawn strategy (which is required for remote"
                      + " fallback execution).",
                  strategy.getClass().getSimpleName()),
              Code.REMOTE_FALLBACK_STRATEGY_NOT_ABSTRACT_SPAWN);
        }

        remoteLocalFallbackStrategy = (AbstractSpawnStrategy) strategy;
      }

      ImmutableList<? extends SpawnStrategy> defaultStrategies;
      if (explicitDefaultStrategies.isEmpty()) {
        // Use the strategies as registered, in reverse order.
        defaultStrategies = ImmutableList.copyOf(Lists.reverse(strategiesInRegistrationOrder));
      } else {
        defaultStrategies = toStrategies(explicitDefaultStrategies, "default strategies");
      }

      return new SpawnStrategyRegistry(
          mnemonicToStrategies.build(),
          ImmutableListMultimap.copyOf(filterToStrategies),
          defaultStrategies,
          mnemonicToRemoteStrategies.build(),
          mnemonicToLocalStrategies.build(),
          remoteLocalFallbackStrategy);
    }

    private ImmutableList<? extends SpawnStrategy> toStrategies(
        List<String> identifiers, Object requestName) throws AbruptExitException {
      ImmutableList.Builder<SpawnStrategy> strategies = ImmutableList.builder();
      for (String identifier : identifiers) {
        if (identifier.isEmpty()) {
          continue;
        }
        strategies.add(toStrategy(requestName, identifier));
      }
      return strategies.build();
    }

    private SpawnStrategy toStrategy(Object requestName, String identifier)
        throws AbruptExitException {
      SpawnStrategy strategy = identifierToStrategy.get(identifier);
      if (strategy == null) {
        throw createExitException(
            String.format(
                "'%s' was requested for %s but no strategy with that identifier was registered. "
                    + "Valid values are: [%s]",
                identifier, requestName, Joiner.on(", ").join(identifierToStrategy.keySet())),
            Code.STRATEGY_NOT_FOUND);
      }
      return strategy;
    }

    private Iterable<? extends SandboxedSpawnStrategy> toSandboxedStrategies(
        List<String> identifiers, Object requestName) throws AbruptExitException {
      Iterable<? extends SpawnStrategy> strategies = toStrategies(identifiers, requestName);
      for (SpawnStrategy strategy : strategies) {
        if (!(strategy instanceof SandboxedSpawnStrategy)) {
          throw createExitException(
              String.format(
                  "'%s' was requested for %s but is not a sandboxed strategy (which is required for"
                      + " dynamic execution).",
                  strategy.getClass().getSimpleName(), requestName),
              Code.DYNAMIC_STRATEGY_NOT_SANDBOXED);
        }
      }

      @SuppressWarnings("unchecked") // Each element of the iterable was checked to fulfil this.
      Iterable<? extends SandboxedSpawnStrategy> sandboxedStrategies =
          (Iterable<? extends SandboxedSpawnStrategy>) strategies;
      return sandboxedStrategies;
    }
  }

  private static AbruptExitException createExitException(String message, Code detailedCode) {
    return new AbruptExitException(
        DetailedExitCode.of(
            FailureDetail.newBuilder()
                .setMessage(message)
                .setExecutionOptions(
                    FailureDetails.ExecutionOptions.newBuilder().setCode(detailedCode))
                .build()));
  }

  @AutoValue
  abstract static class FilterAndIdentifiers {

    abstract RegexFilter filter();

    abstract ImmutableList<String> identifiers();
  }
}
