// 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.errors.Unreachable;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestParametersBuilder {

  // Static computation of VMs configured as available by the testing invocation.
  private static final List<TestRuntime> availableRuntimes =
      getAvailableRuntimes().collect(Collectors.toList());

  // Predicate describing which test parameters are applicable to the test.
  // Built via the methods found below. Default to no applicable parameters, i.e., the emtpy set.
  private Predicate<TestParameters> filter = param -> 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) {
    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();
  }

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

  /** 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(vm -> startInclusive.lessThanOrEqual(vm));
  }

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

  /** 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 starting from and including {@param startInclusive}. */
  public TestParametersBuilder withDexRuntimesStartingFromIncluding(DexVm.Version startInclusive) {
    return withDexRuntimeFilter(vm -> startInclusive.isOlderThanOrEqual(vm));
  }

  /** 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));
  }

  public TestParametersCollection build() {
    return new TestParametersCollection(
        getAvailableRuntimes()
            .map(TestParameters::new)
            .filter(filter)
            .collect(Collectors.toList()));
  }

  // Public method to check that the CF runtime coincides with the system runtime.
  public static boolean isSystemJdk(CfVm vm) {
    String version = System.getProperty("java.version");
    switch (vm) {
      case JDK8:
        return version.startsWith("1.8.");
      case JDK9:
        return version.startsWith("9.");
    }
    throw new Unreachable();
  }

  // Currently the only supported VM is the system VM. This should be extended to start supporting
  // the checked in versions too, making it possible to run tests on more than one JDK at a time.
  private static boolean isSupportedJdk(CfVm vm) {
    return isSystemJdk(vm);
  }

  private static Stream<TestRuntime> getAvailableRuntimes() {
    String runtimesProperty = System.getProperty("runtimes");
    Stream<TestRuntime> runtimes;
    if (runtimesProperty != null) {
      runtimes =
          Arrays.stream(runtimesProperty.split(":"))
              .filter(s -> !s.isEmpty())
              .map(
                  name -> {
                    TestRuntime runtime = TestRuntime.fromName(name);
                    if (runtime != null) {
                      return runtime;
                    }
                    throw new RuntimeException("Unexpected runtime property name: " + name);
                  });
    } else {
      runtimes =
          Stream.concat(
              Stream.of(NoneRuntime.getInstance()),
              Stream.concat(
                  Arrays.stream(TestRuntime.CfVm.values()).map(CfRuntime::new),
                  Arrays.stream(DexVm.Version.values()).map(DexRuntime::new)));
    }
    // TODO(b/127785410) Support multiple VMs at the same time.
    return runtimes.filter(runtime -> !runtime.isCf() || isSupportedJdk(runtime.asCf().getVm()));
  }

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