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

  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());
  }
}
