// Copyright (c) 2017, 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.debug;

import com.android.tools.r8.KotlinCompilerTool;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.Pair;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class ContinuousSteppingTest extends DebugTestBase {

  private static final String MAIN_METHOD_NAME = "main";

  // A list of self-contained jars to process (which do not depend on other jar files).
  private static List<Pair<Path, Predicate<Version>>> listOfJars() {
    return new ConfigListBuilder()
        .add(DebugTestBase.DEBUGGEE_JAR, ContinuousSteppingTest::allVersions)
        .add(DebugTestBase.DEBUGGEE_JAVA8_JAR, ContinuousSteppingTest::allVersions)
        .addAll(
            findAllJarsIn(Paths.get(ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR)),
            ContinuousSteppingTest::fromAndroidN)
        // TODO(b/79911828) Investigate timeout issues for Android O examples.
        //  .addAll(findAllJarsIn(Paths.get(ToolHelper.EXAMPLES_ANDROID_O_BUILD_DIR)),
        //      ContinuousSteppingTest::fromAndroidO)
        .build();
  }

  private final String mainClass;
  private final Path jarPath;

  private static class ConfigListBuilder {

    private final Builder<Pair<Path, Predicate<Version>>> builder = ImmutableList.builder();

    public ConfigListBuilder add(Path path, Predicate<Version> predicate) {
      builder.add(new Pair<>(path, predicate));
      return this;
    }

    public ConfigListBuilder addAll(List<Path> paths, Predicate<Version> predicate) {
      for (Path path : paths) {
        add(path, predicate);
      }
      return this;
    }

    public ConfigListBuilder addAllKotlinDebugJars(
        TemporaryFolder temp, Predicate<Version> predicate) {
      KotlinCompileMemoizer compiledJars =
          KotlinTestBase.getCompileMemoizer(
                  KotlinTestBase.getKotlinFilesInResource("debug"),
                  CfRuntime.getCheckedInJdk9(),
                  temp)
              .configure(KotlinCompilerTool::includeRuntime);
      for (KotlinTestParameters kotlinParameter :
          TestBase.getKotlinTestParameters().withAllCompilersAndTargetVersions().build()) {
        add(compiledJars.getForConfiguration(kotlinParameter), predicate);
      }
      return this;
    }

    public List<Pair<Path, Predicate<Version>>> build() {
      return builder.build();
    }
  }

  public static boolean allVersions(Version dexVmVersion) {
    return true;
  }

  public static boolean fromAndroidN(Version dexVmVersion) {
    return dexVmVersion.isNewerThanOrEqual(Version.V7_0_0);
  }

  private static List<Path> findAllJarsIn(Path root) {
    try {
      return Files.walk(root)
          .filter(p -> p.toFile().getPath().endsWith(FileUtils.JAR_EXTENSION))
          .collect(Collectors.toList());
    } catch (IOException e) {
      return Collections.emptyList();
    }
  }

  @Parameters(name = "{0} from {1}")
  public static Collection<Object[]> getData() throws IOException {
    List<Object[]> testCases = new ArrayList<>();
    for (Pair<Path, Predicate<Version>> pair : listOfJars()) {
      if (pair.getSecond().test(ToolHelper.getDexVm().getVersion())) {
        Path jarPath = pair.getFirst();
        List<String> mainClasses = getAllMainClassesFromJar(jarPath);
        for (String className : mainClasses) {
          testCases.add(new Object[]{className, jarPath});
        }
      }
    }
    return testCases;
  }

  private static final Function<Path, DebugTestConfig> compiledJars =
      memoizeFunction(path -> new D8DebugTestConfig().compileAndAdd(getStaticTemp(), path));

  public ContinuousSteppingTest(String mainClass, Path jarPath) {
    this.mainClass = mainClass;
    this.jarPath = jarPath;
  }

  @Test
  public void testContinuousSingleStep() throws Throwable {
    DebugTestConfig config = compiledJars.apply(jarPath);
    assert config != null;
    runContinuousTest(mainClass, config, MAIN_METHOD_NAME);
  }

  // Returns a list of classes with a "public static void main(String[])" method in the given jar
  // file.
  private static List<String> getAllMainClassesFromJar(Path pathToJar) throws IOException {
    JarInputStream jarInputStream = new JarInputStream(Files.newInputStream(pathToJar,
        StandardOpenOption.READ));
    final URL url = pathToJar.toUri().toURL();
    assert pathToJar.toFile().exists();
    assert pathToJar.toFile().isFile();
    List<String> mainClasses = new ArrayList<>();
    ClassLoader loader = new URLClassLoader(new URL[]{url},
        Thread.currentThread().getContextClassLoader());

    try {
      JarEntry entry;
      while ((entry = jarInputStream.getNextJarEntry()) != null) {
        String entryName = entry.getName();
        if (entryName.endsWith(FileUtils.CLASS_EXTENSION)) {
          String className =
              entryName.substring(0, entryName.length() - FileUtils.CLASS_EXTENSION.length());
          className = className.replace(DescriptorUtils.DESCRIPTOR_PACKAGE_SEPARATOR,
              DescriptorUtils.JAVA_PACKAGE_SEPARATOR);
          try {
            Class<?> cls = loader.loadClass(className);
            if (cls != null) {
              long mainMethodsCount = Arrays.stream(cls.getMethods())
                  .filter(ContinuousSteppingTest::isMainMethod)
                  .count();
              if (mainMethodsCount == 1) {
                // Add class to the list
                mainClasses.add(className);
              }
            }
          } catch (Throwable e) {
            System.out.println(
                "Could not load class " + className + " from " + pathToJar.toFile().getPath());
            return Collections.emptyList();
          }
        }
      }
    } finally {
      jarInputStream.close();
    }
    return mainClasses;
  }

  private static boolean isMainMethod(Method m) {
    return Modifier.isStatic(m.getModifiers())
        && m.getReturnType() == void.class
        && m.getName().equals(MAIN_METHOD_NAME)
        && m.getParameterCount() == 1
        && m.getParameterTypes()[0] == String[].class;
  }
}
