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

import com.android.tools.r8.ArchiveClassFileProvider;
import com.android.tools.r8.ArchiveProgramResourceProvider;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.R8;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.Version;
import com.android.tools.r8.origin.ArchiveEntryOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.StringDiagnostic;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class R8ApiUsageSample {

  private static final Origin origin =
      new Origin(Origin.root()) {
        @Override
        public String part() {
          return "R8ApiUsageSample";
        }
      };

  private static final DiagnosticsHandler handler = new D8DiagnosticsHandler();

  /**
   * Example invocation:
   *
   * <pre>
   *   java -jar r8-api-uses.jar \
   *     --output path/to/output/dir \
   *     --min-api minApiLevel \
   *     --lib path/to/library.jar \
   *     path/to/input{1,2,3}.{jar,class}
   * </pre>
   */
  public static void main(String[] args) {
    // Check version API
    checkVersionApi();
    // Parse arguments with the commandline parser to make use of its API.
    R8Command.Builder cmd = R8Command.parse(args, origin);
    CompilationMode mode = cmd.getMode();
    Path temp = cmd.getOutputPath();
    int minApiLevel = cmd.getMinApiLevel();
    // The Builder API does not provide access to the concrete paths
    // (everything is put into providers) so manually parse them here.
    List<Path> libraries = new ArrayList<>(1);
    List<Path> mainDexList = new ArrayList<>(1);
    List<Path> mainDexRules = new ArrayList<>(1);
    List<Path> pgConf = new ArrayList<>(1);
    List<Path> inputs = new ArrayList<>(args.length);
    for (int i = 0; i < args.length; i++) {
      if (args[i].equals("--lib")) {
        libraries.add(Paths.get(args[++i]));
      } else if (args[i].equals("--main-dex-list")) {
        mainDexList.add(Paths.get(args[++i]));
      } else if (args[i].equals("--main-dex-rules")) {
        mainDexRules.add(Paths.get(args[++i]));
      } else if (args[i].equals("--pg-conf")) {
        pgConf.add(Paths.get(args[++i]));
      } else if (isArchive(args[i]) || isClassFile(args[i])) {
        inputs.add(Paths.get(args[i]));
      }
    }
    if (!Files.exists(temp) || !Files.isDirectory(temp)) {
      throw new RuntimeException("Must supply a temp/output directory");
    }
    if (inputs.isEmpty()) {
      throw new RuntimeException("Must supply program inputs");
    }
    if (libraries.isEmpty()) {
      throw new RuntimeException("Must supply library inputs");
    }
    if (mainDexList.isEmpty()) {
      throw new RuntimeException("Must supply main-dex-list inputs");
    }
    if (mainDexRules.isEmpty()) {
      throw new RuntimeException("Must supply main-dex-rules inputs");
    }
    if (pgConf.isEmpty()) {
      throw new RuntimeException("Must supply pg-conf inputs");
    }

    useProgramFileList(CompilationMode.DEBUG, minApiLevel, libraries, inputs);
    useProgramFileList(CompilationMode.RELEASE, minApiLevel, libraries, inputs);
    useProgramData(minApiLevel, libraries, inputs);
    useProgramResourceProvider(minApiLevel, libraries, inputs);
    useLibraryResourceProvider(minApiLevel, libraries, inputs);
    useMainDexListFiles(minApiLevel, libraries, inputs, mainDexList);
    useMainDexClasses(minApiLevel, libraries, inputs, mainDexList);
    useMainDexRulesFiles(minApiLevel, libraries, inputs, mainDexRules);
    useMainDexRules(minApiLevel, libraries, inputs, mainDexRules);
    useProguardConfigFiles(minApiLevel, libraries, inputs, mainDexList, pgConf);
    useProguardConfigLines(minApiLevel, libraries, inputs, mainDexList, pgConf);
    useVArgVariants(minApiLevel, libraries, inputs, mainDexList, mainDexRules, pgConf);
    useProguardConfigConsumers(minApiLevel, libraries, inputs, pgConf);
  }

  private static class InMemoryStringConsumer implements StringConsumer {
    public String value = null;

    @Override
    public void accept(String string, DiagnosticsHandler handler) {
      value = string;
    }
  }

  private static void useProguardConfigConsumers(
      int minApiLevel, Collection<Path> libraries, Collection<Path> inputs, List<Path> pgConf) {
    InMemoryStringConsumer usageConsumer = new InMemoryStringConsumer();
    InMemoryStringConsumer seedsConsumer = new InMemoryStringConsumer();
    InMemoryStringConsumer configConsumer = new InMemoryStringConsumer();
    try {
      R8.run(
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries)
              .addProgramFiles(inputs)
              .addProguardConfigurationFiles(pgConf)
              .setProguardUsageConsumer(usageConsumer)
              .setProguardSeedsConsumer(seedsConsumer)
              .setProguardConfigurationConsumer(configConsumer)
              .build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exception", e);
    }
    if (usageConsumer.value == null) {
      throw new RuntimeException("Expected usage info but had none");
    }
    if (seedsConsumer.value == null) {
      throw new RuntimeException("Expected seeds info but had none");
    }
    if (configConsumer.value == null) {
      throw new RuntimeException("Expected config info but had none");
    }
  }

  // Check API support for compiling Java class-files from the file system.
  private static void useProgramFileList(
      CompilationMode mode, int minApiLevel, Collection<Path> libraries, Collection<Path> inputs) {
    try {
      R8.run(
          R8Command.builder(handler)
              .setMode(mode)
              .setMinApiLevel(minApiLevel)
              .setDisableTreeShaking(true)
              .setDisableMinification(true)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries)
              .addProgramFiles(inputs)
              .build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    }
  }

  // Check API support for compiling Java class-files from byte content.
  private static void useProgramData(
      int minApiLevel, Collection<Path> libraries, Collection<Path> inputs) {
    try {
      R8Command.Builder builder =
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setDisableTreeShaking(true)
              .setDisableMinification(true)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries);
      for (ClassFileContent classfile : readClassFiles(inputs)) {
        builder.addClassProgramData(classfile.data, classfile.origin);
      }
      R8.run(builder.build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    } catch (IOException e) {
      throw new RuntimeException("Unexpected IO exception", e);
    }
  }

  // Check API support for compiling Java class-files from a program provider abstraction.
  private static void useProgramResourceProvider(
      int minApiLevel, Collection<Path> libraries, Collection<Path> inputs) {
    try {
      R8Command.Builder builder =
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setDisableTreeShaking(true)
              .setDisableMinification(true)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries);
      for (Path input : inputs) {
        if (isArchive(input)) {
          builder.addProgramResourceProvider(
              ArchiveProgramResourceProvider.fromArchive(
                  input, ArchiveProgramResourceProvider::includeClassFileEntries));
        } else {
          builder.addProgramResourceProvider(
              new ProgramResourceProvider() {
                @Override
                public Collection<ProgramResource> getProgramResources() throws ResourceException {
                  return Collections.singleton(ProgramResource.fromFile(Kind.CF, input));
                }
              });
        }
      }
      R8.run(builder.build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    }
  }

  private static void useLibraryResourceProvider(
      int minApiLevel, Collection<Path> libraries, Collection<Path> inputs) {
    try {
      R8Command.Builder builder =
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setDisableTreeShaking(true)
              .setDisableMinification(true)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addProgramFiles(inputs);
      for (Path library : libraries) {
        builder.addLibraryResourceProvider(new ArchiveClassFileProvider(library));
      }
      R8.run(builder.build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    } catch (IOException e) {
      throw new RuntimeException("Unexpected IO exception", e);
    }
  }

  private static void useMainDexListFiles(
      int minApiLevel,
      Collection<Path> libraries,
      Collection<Path> inputs,
      Collection<Path> mainDexList) {
    try {
      R8.run(
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setDisableTreeShaking(true)
              .setDisableMinification(true)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries)
              .addProgramFiles(inputs)
              .addMainDexListFiles(mainDexList)
              .build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    }
  }

  private static void useMainDexClasses(
      int minApiLevel,
      Collection<Path> libraries,
      Collection<Path> inputs,
      Collection<Path> mainDexList) {
    try {
      List<String> mainDexClasses = new ArrayList<>(1);
      for (Path path : mainDexList) {
        for (String line : Files.readAllLines(path)) {
          String entry = line.trim();
          if (entry.isEmpty() || entry.startsWith("#") || !entry.endsWith(".class")) {
            continue;
          }
          mainDexClasses.add(entry.replace(".class", "").replace("/", "."));
        }
      }
      R8.run(
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setDisableTreeShaking(true)
              .setDisableMinification(true)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries)
              .addProgramFiles(inputs)
              .addMainDexClasses(mainDexClasses)
              .build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    } catch (IOException e) {
      throw new RuntimeException("Unexpected IO exception", e);
    }
  }

  private static void useMainDexRulesFiles(
      int minApiLevel,
      Collection<Path> libraries,
      Collection<Path> inputs,
      Collection<Path> mainDexRules) {
    try {
      R8.run(
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setDisableTreeShaking(true)
              .setDisableMinification(true)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries)
              .addProgramFiles(inputs)
              .addMainDexRulesFiles(mainDexRules)
              .build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    }
  }

  private static void useMainDexRules(
      int minApiLevel,
      Collection<Path> libraries,
      Collection<Path> inputs,
      Collection<Path> mainDexRulesFiles) {
    try {
      R8Command.Builder builder =
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setDisableTreeShaking(true)
              .setDisableMinification(true)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries)
              .addProgramFiles(inputs);
      for (Path mainDexRulesFile : mainDexRulesFiles) {
        builder.addMainDexRules(
            Files.readAllLines(mainDexRulesFile), new PathOrigin(mainDexRulesFile));
      }
      R8.run(builder.build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    } catch (IOException e) {
      throw new RuntimeException("Unexpected IO exception", e);
    }
  }

  private static void useProguardConfigFiles(
      int minApiLevel,
      Collection<Path> libraries,
      Collection<Path> inputs,
      Collection<Path> mainDexList,
      List<Path> pgConf) {
    try {
      R8.run(
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries)
              .addProgramFiles(inputs)
              .addMainDexListFiles(mainDexList)
              .addProguardConfigurationFiles(pgConf)
              .build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    }
  }

  private static void useProguardConfigLines(
      int minApiLevel,
      Collection<Path> libraries,
      Collection<Path> inputs,
      Collection<Path> mainDexList,
      List<Path> pgConf) {
    try {
      R8Command.Builder builder =
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries)
              .addProgramFiles(inputs)
              .addMainDexListFiles(mainDexList);
      for (Path file : pgConf) {
        builder.addProguardConfiguration(Files.readAllLines(file), new PathOrigin(file));
      }
      R8.run(builder.build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    } catch (IOException e) {
      throw new RuntimeException("Unexpected IO exception", e);
    }
  }

  // Check API support for all the varg variants.
  private static void useVArgVariants(
      int minApiLevel,
      List<Path> libraries,
      List<Path> inputs,
      List<Path> mainDexList,
      List<Path> mainDexRules,
      List<Path> pgConf) {
    try {
      R8.run(
          R8Command.builder(handler)
              .setMinApiLevel(minApiLevel)
              .setProgramConsumer(new EnsureOutputConsumer())
              .addLibraryFiles(libraries.get(0))
              .addLibraryFiles(libraries.stream().skip(1).toArray(Path[]::new))
              .addProgramFiles(inputs.get(0))
              .addProgramFiles(inputs.stream().skip(1).toArray(Path[]::new))
              .addMainDexListFiles(mainDexList.get(0))
              .addMainDexListFiles(mainDexList.stream().skip(1).toArray(Path[]::new))
              .addMainDexRulesFiles(mainDexRules.get(0))
              .addMainDexRulesFiles(mainDexRules.stream().skip(1).toArray(Path[]::new))
              .addProguardConfigurationFiles(pgConf.get(0))
              .addProguardConfigurationFiles(pgConf.stream().skip(1).toArray(Path[]::new))
              .build());
    } catch (CompilationFailedException e) {
      throw new RuntimeException("Unexpected compilation exceptions", e);
    }
  }

  // Helpers for tests.
  // Some of this reimplements stuff in R8 utils, but that is not public API and we should not
  // rely on it.

  private static List<ClassFileContent> readClassFiles(Collection<Path> files) throws IOException {
    List<ClassFileContent> classfiles = new ArrayList<>();
    for (Path file : files) {
      if (isArchive(file)) {
        Origin zipOrigin = new PathOrigin(file);
        ZipInputStream zip = new ZipInputStream(Files.newInputStream(file), StandardCharsets.UTF_8);
        ZipEntry entry;
        while (null != (entry = zip.getNextEntry())) {
          String name = entry.getName();
          if (isClassFile(name)) {
            Origin origin = new ArchiveEntryOrigin(name, zipOrigin);
            classfiles.add(new ClassFileContent(origin, readBytes(zip)));
          }
        }
      } else if (isClassFile(file)) {
        classfiles.add(new ClassFileContent(new PathOrigin(file), Files.readAllBytes(file)));
      }
    }
    return classfiles;
  }

  private static byte[] readBytes(InputStream stream) throws IOException {
    try (ByteArrayOutputStream bytes = new ByteArrayOutputStream()) {
      byte[] buffer = new byte[0xffff];
      for (int length; (length = stream.read(buffer)) != -1; ) {
        bytes.write(buffer, 0, length);
      }
      return bytes.toByteArray();
    }
  }

  private static boolean isClassFile(Path file) {
    return isClassFile(file.toString());
  }

  private static boolean isClassFile(String file) {
    file = file.toLowerCase();
    return file.endsWith(".class");
  }

  private static boolean isArchive(Path file) {
    return isArchive(file.toString());
  }

  private static boolean isArchive(String file) {
    file = file.toLowerCase();
    return file.endsWith(".zip") || file.endsWith(".jar");
  }

  private static class ClassFileContent {
    final Origin origin;
    final byte[] data;

    public ClassFileContent(Origin origin, byte[] data) {
      this.origin = origin;
      this.data = data;
    }
  }

  private static class EnsureOutputConsumer implements DexIndexedConsumer {
    boolean hasOutput = false;

    @Override
    public synchronized void accept(
        int fileIndex, byte[] data, Set<String> descriptors, DiagnosticsHandler handler) {
      hasOutput = true;
    }

    @Override
    public void finished(DiagnosticsHandler handler) {
      if (!hasOutput) {
        handler.error(new StringDiagnostic("Expected to produce output but had none"));
      }
    }
  }

  private static void checkVersionApi() {
    if (Version.getVersionString() == null) {
      throw new RuntimeException("Expected getVersionString API");
    }
    if (Version.getMajorVersion() < -1) {
      throw new RuntimeException("Expected getMajorVersion API");
    }
    if (Version.getMinorVersion() < -1) {
      throw new RuntimeException("Expected getMinorVersion API");
    }
    if (Version.getPatchVersion() < -1) {
      throw new RuntimeException("Expected getPatchVersion API");
    }
    if (Version.getPreReleaseString() == null && false) {
      throw new RuntimeException("Expected getPreReleaseString API");
    }
    if (Version.isDevelopmentVersion() && false) {
      throw new RuntimeException("Expected isDevelopmentVersion API");
    }
  }
}
