// Copyright (c) 2022, 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.desugar.desugaredlibrary.test;

import static com.android.tools.r8.ToolHelper.DESUGARED_JDK_11_LIB_JAR;
import static com.android.tools.r8.ToolHelper.DESUGARED_JDK_8_LIB_JAR;
import static com.android.tools.r8.ToolHelper.DESUGARED_LIB_RELEASES_DIR;
import static com.android.tools.r8.ToolHelper.getUndesugaredJdk11LibJarForTesting;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.CustomConversionVersion.LATEST;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.CustomConversionVersion.LEGACY;

import com.android.tools.r8.L8TestBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Set;

public class LibraryDesugaringSpecification {

  public static Descriptor JDK8_DESCRIPTOR = new Descriptor(24, 26, -1, 26, 24);
  public static Descriptor JDK11_DESCRIPTOR = new Descriptor(24, 30, -1, 30, -1);
  public static Descriptor EMPTY_DESCRIPTOR_24 = new Descriptor(-1, -1, -1, 24, -1);
  public static Descriptor JDK11_PATH_DESCRIPTOR = new Descriptor(24, 30, 26, 32, -1);
  public static Descriptor JDK11_LEGACY_DESCRIPTOR = new Descriptor(24, 10000, -1, 10000, 24);

  private static class Descriptor {
    // Above this level emulated interface are not *entirely* desugared.
    private final int emulatedInterfaceDesugaring;
    // Above this level java.time is not *entirely* desugared.
    private final int timeDesugaring;
    // Above this level java.nio.file is not *entirely* desugared.
    private final int nioFileDesugaring;
    // Above this level no desugaring is required.
    private final int anyDesugaring;
    // Above this level java.function is used, below j$.function is used.
    private final int jDollarFunction;

    private Descriptor(
        int emulatedInterfaceDesugaring,
        int timeDesugaring,
        int nioFileDesugaring,
        int anyDesugaring,
        int jDollarFunction) {
      this.emulatedInterfaceDesugaring = emulatedInterfaceDesugaring;
      this.timeDesugaring = timeDesugaring;
      this.nioFileDesugaring = nioFileDesugaring;
      this.anyDesugaring = anyDesugaring;
      this.jDollarFunction = jDollarFunction;
    }

    public int getEmulatedInterfaceDesugaring() {
      return emulatedInterfaceDesugaring;
    }

    public int getTimeDesugaring() {
      return timeDesugaring;
    }

    public int getNioFileDesugaring() {
      return nioFileDesugaring;
    }

    public int getAnyDesugaring() {
      return anyDesugaring;
    }

    public int getJDollarFunction() {
      return jDollarFunction;
    }
  }

  public enum CustomConversionVersion {
    LEGACY,
    LATEST
  }

  // Main head specifications.
  public static LibraryDesugaringSpecification JDK8 =
      new LibraryDesugaringSpecification(
          "JDK8",
          DESUGARED_JDK_8_LIB_JAR,
          "desugar_jdk_libs.json",
          AndroidApiLevel.P,
          JDK8_DESCRIPTOR,
          LEGACY);
  public static LibraryDesugaringSpecification JDK11 =
      new LibraryDesugaringSpecification(
          "JDK11",
          getUndesugaredJdk11LibJarForTesting(),
          "jdk11/desugar_jdk_libs.json",
          AndroidApiLevel.R,
          JDK11_DESCRIPTOR,
          LATEST);
  public static LibraryDesugaringSpecification JDK11_MINIMAL =
      new LibraryDesugaringSpecification(
          "JDK11_MINIMAL",
          getUndesugaredJdk11LibJarForTesting(),
          "jdk11/desugar_jdk_libs_minimal.json",
          AndroidApiLevel.R,
          EMPTY_DESCRIPTOR_24,
          LATEST);
  public static LibraryDesugaringSpecification JDK11_PATH =
      new LibraryDesugaringSpecification(
          "JDK11_PATH",
          getUndesugaredJdk11LibJarForTesting(),
          "jdk11/desugar_jdk_libs_path.json",
          AndroidApiLevel.R,
          JDK11_PATH_DESCRIPTOR,
          LATEST);

  // Legacy specifications.
  public static LibraryDesugaringSpecification JDK11_PATH_ALTERNATIVE_3 =
      new LibraryDesugaringSpecification(
          "JDK11_PATH_ALTERNATIVE_3",
          getUndesugaredJdk11LibJarForTesting(),
          "jdk11/desugar_jdk_libs_path_alternative_3.json",
          AndroidApiLevel.R,
          JDK11_PATH_DESCRIPTOR,
          LATEST);
  public static LibraryDesugaringSpecification JDK11_CHM_ONLY =
      new LibraryDesugaringSpecification(
          "JDK11_CHM_ONLY",
          getUndesugaredJdk11LibJarForTesting(),
          "jdk11/chm_only_desugar_jdk_libs.json",
          AndroidApiLevel.R,
          EMPTY_DESCRIPTOR_24,
          LATEST);
  public static LibraryDesugaringSpecification JDK11_LEGACY =
      new LibraryDesugaringSpecification(
          "JDK11_LEGACY",
          // The legacy specification is not using the undesugared JAR.
          DESUGARED_JDK_11_LIB_JAR,
          "jdk11/desugar_jdk_libs_legacy.json",
          AndroidApiLevel.R,
          JDK11_LEGACY_DESCRIPTOR,
          LEGACY);
  public static final LibraryDesugaringSpecification RELEASED_1_0_9 =
      new LibraryDesugaringSpecification("1.0.9", AndroidApiLevel.P);
  public static final LibraryDesugaringSpecification RELEASED_1_0_10 =
      new LibraryDesugaringSpecification("1.0.10", AndroidApiLevel.P);
  public static final LibraryDesugaringSpecification RELEASED_1_1_0 =
      new LibraryDesugaringSpecification("1.1.0", AndroidApiLevel.P);
  public static final LibraryDesugaringSpecification RELEASED_1_1_1 =
      new LibraryDesugaringSpecification("1.1.1", AndroidApiLevel.P);
  public static final LibraryDesugaringSpecification RELEASED_1_1_5 =
      new LibraryDesugaringSpecification("1.1.5", AndroidApiLevel.P);

  private final String name;
  private final Set<Path> desugarJdkLibs;
  private final Path specification;
  private final Set<Path> libraryFiles;
  private final Descriptor descriptor;
  private final String extraKeepRules;

  public LibraryDesugaringSpecification(
      String name,
      Path desugarJdkLibs,
      String specificationPath,
      AndroidApiLevel androidJarLevel,
      Descriptor descriptor,
      CustomConversionVersion legacy) {
    this(
        name,
        ImmutableSet.of(desugarJdkLibs, ToolHelper.getDesugarLibConversions(legacy)),
        Paths.get("src/library_desugar/" + specificationPath),
        ImmutableSet.of(ToolHelper.getAndroidJar(androidJarLevel)),
        descriptor,
        "");
  }

  // This can be used to build custom specifications for testing purposes.
  public LibraryDesugaringSpecification(
      String name,
      Set<Path> desugarJdkLibs,
      Path specification,
      Set<Path> libraryFiles,
      Descriptor descriptor,
      String extraKeepRules) {
    this.name = name;
    this.desugarJdkLibs = desugarJdkLibs;
    this.specification = specification;
    this.libraryFiles = libraryFiles;
    this.descriptor = descriptor;
    this.extraKeepRules = extraKeepRules;
  }

  private LibraryDesugaringSpecification(String version, AndroidApiLevel androidJarLevel) {
    this(
        "RELEASED_" + version,
        ImmutableSet.of(
            Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar_jdk_libs.jar"),
            Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar_jdk_libs_configuration.jar")),
        Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar.json"),
        ImmutableSet.of(ToolHelper.getAndroidJar(androidJarLevel)),
        JDK8_DESCRIPTOR,
        "");
  }

  @Override
  public String toString() {
    return name;
  }

  public Set<Path> getDesugarJdkLibs() {
    return desugarJdkLibs;
  }

  public Path getSpecification() {
    return specification;
  }

  public Set<Path> getLibraryFiles() {
    return libraryFiles;
  }

  public Descriptor getDescriptor() {
    return descriptor;
  }

  public String getExtraKeepRules() {
    return extraKeepRules;
  }

  public void configureL8TestBuilder(L8TestBuilder l8TestBuilder) {
    configureL8TestBuilder(l8TestBuilder, false, "");
  }

  public void configureL8TestBuilder(
      L8TestBuilder l8TestBuilder, boolean l8Shrink, String keepRule) {
    l8TestBuilder
        .addProgramFiles(getDesugarJdkLibs())
        .addLibraryFiles(getLibraryFiles())
        .setDesugaredLibrarySpecification(getSpecification())
        .applyIf(
            l8Shrink,
            builder -> {
              if (keepRule != null && !keepRule.trim().isEmpty()) {
                String totalKeepRules = keepRule + "\n" + getExtraKeepRules();
                builder.addGeneratedKeepRules(totalKeepRules);
              }
            },
            L8TestBuilder::setDebug);
  }

  public static List<LibraryDesugaringSpecification> getReleased() {
    return ImmutableList.of(
        RELEASED_1_0_9, RELEASED_1_0_10, RELEASED_1_1_0, RELEASED_1_1_1, RELEASED_1_1_5);
  }

  public static List<LibraryDesugaringSpecification> getJdk8Jdk11() {
    return ImmutableList.of(JDK8, JDK11);
  }

  public boolean hasEmulatedInterfaceDesugaring(TestParameters parameters) {
    return parameters.getApiLevel().getLevel() < descriptor.getEmulatedInterfaceDesugaring();
  }

  public boolean hasTimeDesugaring(TestParameters parameters) {
    return parameters.getApiLevel().getLevel() < descriptor.getTimeDesugaring();
  }

  public boolean hasNioFileDesugaring(TestParameters parameters) {
    return hasNioFileDesugaring(parameters.getApiLevel());
  }

  public boolean hasNioFileDesugaring(AndroidApiLevel apiLevel) {
    return apiLevel.getLevel() < descriptor.getNioFileDesugaring();
  }

  public boolean hasNioChannelDesugaring(TestParameters parameters) {
    return hasNioFileDesugaring(parameters) && parameters.getApiLevel().getLevel() < 24;
  }

  public boolean usesPlatformFileSystem(TestParameters parameters) {
    return parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V8_1_0);
  }

  public boolean hasAnyDesugaring(TestParameters parameters) {
    return hasAnyDesugaring(parameters.getApiLevel());
  }

  public boolean hasAnyDesugaring(AndroidApiLevel apiLevel) {
    return apiLevel.getLevel() < descriptor.getAnyDesugaring();
  }

  public boolean hasJDollarFunction(TestParameters parameters) {
    return parameters.getApiLevel().getLevel() < descriptor.getJDollarFunction();
  }

  public String functionPrefix(TestParameters parameters) {
    return hasJDollarFunction(parameters) ? "j$" : "java";
  }
}
