// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;

import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.TestRuntime.DexRuntime;
import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestParametersBuilder {

  // Predicate describing which test parameters are applicable to the test.
  // Built via the methods found below. Defaults to no applicable parameters, i.e., the emtpy set.
  private Predicate<TestParameters> filter = param -> false;
  private boolean hasDexRuntimeFilter = false;

  private TestParametersBuilder() {}

  public static TestParametersBuilder builder() {
    return new TestParametersBuilder();
  }

  private TestParametersBuilder withFilter(Predicate<TestParameters> predicate) {
    filter = filter.or(predicate);
    return this;
  }

  private TestParametersBuilder withCfRuntimeFilter(Predicate<CfVm> predicate) {
    return withFilter(p -> p.isCfRuntime() && predicate.test(p.getRuntime().asCf().getVm()));
  }

  private TestParametersBuilder withDexRuntimeFilter(Predicate<DexVm.Version> predicate) {
    hasDexRuntimeFilter = true;
    return withFilter(
        p -> p.isDexRuntime() && predicate.test(p.getRuntime().asDex().getVm().getVersion()));
  }

  public TestParametersBuilder withNoneRuntime() {
    return withFilter(p -> p.getRuntime() == NoneRuntime.getInstance());
  }

  public TestParametersBuilder withAllRuntimes() {
    return withCfRuntimes().withDexRuntimes();
  }

  public TestParametersBuilder withAllRuntimesAndApiLevels() {
    return withCfRuntimes().withDexRuntimes().withAllApiLevels();
  }

  /** Add specific runtime if available. */
  public TestParametersBuilder withCfRuntime(CfVm runtime) {
    return withCfRuntimeFilter(vm -> vm == runtime);
  }

  /**
   * Test using the same runtime as the test is executing under.
   *
   * <p>This should only be used when there is an explicit dependency in the test that requires the
   * host and test to be the same. For example, it could be to fork a subprocess using the same
   * runtime.
   */
  public TestParametersBuilder withSystemRuntime() {
    return withCfRuntimeFilter(TestParametersBuilder::isSystemJdk);
  }

  /**
   * Test using the default DEX VM.
   *
   * <p>Generally tests should rather use withDexRuntimes(), but if a test really only needs to be
   * tested on a single DEX runtime this can be used instead. The test should not have any
   * requirements as to which VM it is as the default will change and may not track latest.
   */
  public TestParametersBuilder withDefaultDexRuntime() {
    return withDexRuntime(DexRuntime.getDefaultDexRuntime().getVersion());
  }

  /**
   * Test using the default CF VM.
   *
   * <p>Generally tests should rather use withCfRuntimes(), but if a test really only needs to be
   * tested on a single CF runtime this can be used instead. The test should not have any
   * requirements as to which VM it is as the default will change and may not track latest.
   */
  public TestParametersBuilder withDefaultCfRuntime() {
    return withCfRuntime(CfRuntime.getDefaultCfRuntime().getVm());
  }

  /** Add all available CF runtimes. */
  public TestParametersBuilder withCfRuntimes() {
    return withCfRuntimeFilter(vm -> true);
  }

  /** Add all available CF runtimes between {@param startInclusive} and {@param endInclusive}. */
  public TestParametersBuilder withCfRuntimes(CfVm startInclusive, CfVm endInclusive) {
    return withCfRuntimeFilter(
        vm -> startInclusive.lessThanOrEqual(vm) && vm.lessThanOrEqual(endInclusive));
  }

  /** Add all available CF runtimes starting from and including {@param startInclusive}. */
  public TestParametersBuilder withCfRuntimesStartingFromIncluding(CfVm startInclusive) {
    return withCfRuntimeFilter(startInclusive::lessThanOrEqual);
  }

  /** Add all available CF runtimes starting from and excluding {@param startExcluding}. */
  public TestParametersBuilder withCfRuntimesStartingFromExcluding(CfVm startExcluding) {
    return withCfRuntimeFilter(startExcluding::lessThan);
  }

  /** Add all available CF runtimes ending at and including {@param endInclusive}. */
  public TestParametersBuilder withCfRuntimesEndingAtIncluding(CfVm endInclusive) {
    return withCfRuntimeFilter(vm -> vm.lessThanOrEqual(endInclusive));
  }

  /** Add all available CF runtimes ending at and excluding {@param endExclusive}. */
  public TestParametersBuilder withCfRuntimesEndingAtExcluding(CfVm endExclusive) {
    return withCfRuntimeFilter(vm -> vm.lessThan(endExclusive));
  }

  /** Add all available DEX runtimes. */
  public TestParametersBuilder withDexRuntimes() {
    return withDexRuntimeFilter(vm -> true);
  }

  /** Add specific runtime if available. */
  public TestParametersBuilder withDexRuntime(DexVm.Version runtime) {
    return withDexRuntimeFilter(vm -> vm == runtime);
  }

  /** Add all available CF runtimes between {@param startInclusive} and {@param endInclusive}. */
  public TestParametersBuilder withDexRuntimes(
      DexVm.Version startInclusive, DexVm.Version endInclusive) {
    return withDexRuntimeFilter(
        vm -> startInclusive.isOlderThanOrEqual(vm) && vm.isOlderThanOrEqual(endInclusive));
  }

  /** Add all available DEX runtimes that support native multidex. */
  public TestParametersBuilder withNativeMultidexDexRuntimes() {
    return withDexRuntimesStartingFromIncluding(DexVm.Version.V5_1_1);
  }

  /** Add all available DEX runtimes that do not support native multidex. */
  public TestParametersBuilder withMainDexRuntimes() {
    return withDexRuntimesEndingAtExcluding(DexVm.Version.V5_1_1);
  }

  /** Add all available DEX runtimes starting from and including {@param startInclusive}. */
  public TestParametersBuilder withDexRuntimesStartingFromIncluding(DexVm.Version startInclusive) {
    return withDexRuntimeFilter(startInclusive::isOlderThanOrEqual);
  }

  /** Add all available DEX runtimes starting from and excluding {@param startExcluding}. */
  public TestParametersBuilder withDexRuntimesStartingFromExcluding(DexVm.Version startExcluding) {
    return withDexRuntimeFilter(
        vm -> vm != startExcluding && startExcluding.isOlderThanOrEqual(vm));
  }

  /** Add all available DEX runtimes ending at and including {@param endInclusive}. */
  public TestParametersBuilder withDexRuntimesEndingAtIncluding(DexVm.Version endInclusive) {
    return withDexRuntimeFilter(vm -> vm.isOlderThanOrEqual(endInclusive));
  }

  /** Add all available DEX runtimes ending at and excluding {@param endExclusive}. */
  public TestParametersBuilder withDexRuntimesEndingAtExcluding(DexVm.Version endExclusive) {
    return withDexRuntimeFilter(vm -> vm != endExclusive && vm.isOlderThanOrEqual(endExclusive));
  }

  /**
   * API level configuration.
   *
   * <p>Currently enabling API level config will by default configure each DEX VM to be configured
   * with two parameters, one running at the highest api-level supported by the VM and one at the
   * lowest supported by the compiler (i.e., B).
   */
  private static final AndroidApiLevel lowestCompilerApiLevel = AndroidApiLevel.B;

  private boolean enableApiLevels = false;
  private boolean enableApiLevelsForCf = false;

  private Predicate<AndroidApiLevel> apiLevelFilter = param -> false;
  private List<AndroidApiLevel> explicitApiLevels = new ArrayList<>();
  private List<TestRuntime> customRuntimes = new ArrayList<>();

  private TestParametersBuilder withApiFilter(Predicate<AndroidApiLevel> filter) {
    enableApiLevels = true;
    apiLevelFilter = apiLevelFilter.or(filter);
    return this;
  }

  public TestParametersBuilder withAllApiLevels() {
    return withApiFilter(api -> true);
  }

  public TestParametersBuilder enableApiLevelsForCf() {
    enableApiLevelsForCf = true;
    return this;
  }

  public TestParametersBuilder withAllApiLevelsAlsoForCf() {
    return withAllApiLevels().enableApiLevelsForCf();
  }

  public TestParametersBuilder withApiLevel(AndroidApiLevel api) {
    explicitApiLevels.add(api);
    return withApiFilter(api::equals);
  }

  public TestParametersBuilder withApiLevelsStartingAtIncluding(AndroidApiLevel startInclusive) {
    return withApiFilter(api -> startInclusive.getLevel() <= api.getLevel());
  }

  public TestParametersBuilder withApiLevelsStartingAtExcluding(AndroidApiLevel startExclusive) {
    return withApiFilter(api -> startExclusive.getLevel() < api.getLevel());
  }

  public TestParametersBuilder withApiLevelsEndingAtIncluding(AndroidApiLevel endInclusive) {
    return withApiFilter(api -> api.getLevel() <= endInclusive.getLevel());
  }

  public TestParametersBuilder withApiLevelsEndingAtExcluding(AndroidApiLevel endExclusive) {
    return withApiFilter(api -> api.getLevel() < endExclusive.getLevel());
  }

  public TestParametersBuilder withApiLevelsWithoutNativeMultiDex() {
    return withApiLevelsEndingAtExcluding(AndroidApiLevel.L);
  }

  public TestParametersBuilder withCustomRuntime(TestRuntime runtime) {
    assert getUnfilteredAvailableRuntimes().noneMatch(r -> r == runtime);
    customRuntimes.add(runtime);
    return this;
  }

  public TestParametersCollection build() {
    assert !enableApiLevels || enableApiLevelsForCf || hasDexRuntimeFilter;
    List<TestParameters> availableParameters =
        getAvailableRuntimes()
            .flatMap(this::createParameters)
            .filter(filter)
            .collect(Collectors.toList());
    List<TestParameters> customParameters =
        customRuntimes.stream().flatMap(this::createParameters).collect(Collectors.toList());
    availableParameters.addAll(customParameters);
    return new TestParametersCollection(availableParameters);
  }

  public Stream<TestParameters> createParameters(TestRuntime runtime) {
    if (!enableApiLevels) {
      return Stream.of(new TestParameters(runtime));
    }
    if (runtime.isCf() && !enableApiLevelsForCf) {
      return Stream.of(new TestParameters(runtime));
    }
    List<AndroidApiLevel> sortedApiLevels =
        AndroidApiLevel.getAndroidApiLevelsSorted().stream()
            .filter(apiLevelFilter)
            .collect(Collectors.toList());
    if (sortedApiLevels.isEmpty()) {
      return Stream.of();
    }
    AndroidApiLevel vmLevel = runtime.maxSupportedApiLevel();
    AndroidApiLevel lowestApplicable = sortedApiLevels.get(0);
    if (vmLevel.getLevel() < lowestApplicable.getLevel()) {
      return Stream.of();
    }
    if (sortedApiLevels.size() > 1) {
      for (int i = sortedApiLevels.size() - 1; i >= 0; i--) {
        AndroidApiLevel highestApplicable = sortedApiLevels.get(i);
        if (highestApplicable.getLevel() <= vmLevel.getLevel()
            && lowestApplicable != highestApplicable) {
          Set<AndroidApiLevel> set = new TreeSet<>();
          set.add(lowestApplicable);
          set.add(highestApplicable);
          for (AndroidApiLevel explicitApiLevel : explicitApiLevels) {
            if (explicitApiLevel.getLevel() <= vmLevel.getLevel()) {
              set.add(explicitApiLevel);
            }
          }
          return set.stream().map(api -> new TestParameters(runtime, api));
        }
      }
    }
    return Stream.of(new TestParameters(runtime, lowestApplicable));
  }

  // Public method to check that the CF runtime coincides with the system runtime.
  public static boolean isSystemJdk(CfVm vm) {
    TestRuntime systemRuntime = TestRuntime.getSystemRuntime();
    return systemRuntime.isCf() && systemRuntime.asCf().getVm().equals(vm);
  }

  public static boolean isRuntimesPropertySet() {
    return getRuntimesProperty() != null;
  }

  public static String getRuntimesProperty() {
    return System.getProperty("runtimes");
  }

  private static Stream<TestRuntime> getUnfilteredAvailableRuntimes() {
    // The runtimes are built in a linked hash map to ensure a deterministic order and avoid
    // duplicates.
    LinkedHashMap<TestRuntime, TestRuntime> runtimes = new LinkedHashMap<>();
    // Place the none-runtime first.
    NoneRuntime noneRuntime = NoneRuntime.getInstance();
    runtimes.putIfAbsent(noneRuntime, noneRuntime);
    // Then the checked in runtimes (CF and DEX).
    for (TestRuntime checkedInRuntime : TestRuntime.getCheckedInRuntimes()) {
      runtimes.putIfAbsent(checkedInRuntime, checkedInRuntime);
    }
    // Then finally the system runtime. It will likely be the same as a checked in and adding it
    // makes the overall order more stable.
    TestRuntime systemRuntime = TestRuntime.getSystemRuntime();
    runtimes.putIfAbsent(systemRuntime, systemRuntime);
    return runtimes.values().stream();
  }

  private static Stream<TestRuntime> getAvailableRuntimes() {
    if (isRuntimesPropertySet()) {
      String[] runtimeFilters = getRuntimesProperty().split(":");
      return getUnfilteredAvailableRuntimes()
          .filter(
              runtime ->
                  Arrays.stream(runtimeFilters).anyMatch(filter -> runtime.name().equals(filter)));
    }
    return getUnfilteredAvailableRuntimes();
  }

  public static List<CfVm> getAvailableCfVms() {
    return getAvailableRuntimes()
        .filter(TestRuntime::isCf)
        .map(runtime -> runtime.asCf().getVm())
        .collect(Collectors.toList());
  }

  public static List<DexVm> getAvailableDexVms() {
    return getAvailableRuntimes()
        .filter(TestRuntime::isDex)
        .map(runtime -> runtime.asDex().getVm())
        .collect(Collectors.toList());
  }
}
