package org.robolectric.gradle;

import static org.gradle.api.internal.artifacts.ArtifactAttributes.ARTIFACT_FORMAT;

import com.android.build.gradle.internal.dependency.ExtractAarTransform;
import com.google.common.base.Joiner;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.compile.JavaCompile;

/** Resolve aar dependencies into jars for non-Android projects. */
public class AarDepsPlugin implements Plugin<Project> {
  @Override
  public void apply(Project project) {
    project
        .getDependencies()
        .registerTransform(
            reg -> {
              reg.getFrom().attribute(ARTIFACT_FORMAT, "aar");
              reg.getTo().attribute(ARTIFACT_FORMAT, "jar");
              reg.artifactTransform(ClassesJarExtractor.class);
            });

    project.afterEvaluate(
        p ->
            project
                .getConfigurations()
                .forEach(
                    c -> {
                      // I suspect we're meant to use the org.gradle.usage attribute, but this
                      // works.
                      if (c.getName().endsWith("Classpath")) {
                        c.attributes(cfgAttrs -> cfgAttrs.attribute(ARTIFACT_FORMAT, "jar"));
                      }
                    }));

    // warn if any AARs do make it through somehow; there must be a gradle configuration
    // that isn't matched above.
    project
        .getTasks()
        .withType(JavaCompile.class)
        .all(
            t -> {
              t.doFirst(
                  task -> {
                    List<File> aarFiles = findAarFiles(t.getClasspath());
                    if (!aarFiles.isEmpty()) {
                      throw new IllegalStateException(
                          "AARs on classpath: " + Joiner.on("\n  ").join(aarFiles));
                    }
                  });
            });
  }

  private List<File> findAarFiles(FileCollection files) {
    List<File> bad = new ArrayList<>();
    for (File file : files.getFiles()) {
      if (file.getName().toLowerCase().endsWith(".aar")) {
        bad.add(file);
      }
    }
    return bad;
  }

  static class ClassesJarExtractor extends ExtractAarTransform {
    @Override
    public List<File> transform(File input) {
      List<File> out = super.transform(input);
      File classesJar = new File(out.get(0), "jars/classes.jar");
      // jar needs a quasi-unique name or IntelliJ Gradle/Android plugins get confused...
      File renamed = new File(classesJar.getParent(), input.getName().replace(".aar", ".jar"));
      classesJar.renameTo(renamed);
      return Collections.singletonList(renamed);
    }
  }
}

/** Resolve aar dependencies into jars for non-Android projects. */
package org.robolectric.gradle;

import static org.gradle.api.internal.artifacts.ArtifactAttributes.ARTIFACT_FORMAT;

import com.android.build.gradle.internal.dependency.ExtractAarTransform;
import com.google.common.base.Joiner;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.compile.JavaCompile;

/** Resolve aar dependencies<SUF>*/
public class AarDepsPlugin implements Plugin<Project> {
  @Override
  public void apply(Project project) {
    project
        .getDependencies()
        .registerTransform(
            reg -> {
              reg.getFrom().attribute(ARTIFACT_FORMAT, "aar");
              reg.getTo().attribute(ARTIFACT_FORMAT, "jar");
              reg.artifactTransform(ClassesJarExtractor.class);
            });

    project.afterEvaluate(
        p ->
            project
                .getConfigurations()
                .forEach(
                    c -> {
                      // I suspect we're meant to use the org.gradle.usage attribute, but this
                      // works.
                      if (c.getName().endsWith("Classpath")) {
                        c.attributes(cfgAttrs -> cfgAttrs.attribute(ARTIFACT_FORMAT, "jar"));
                      }
                    }));

    // warn if any AARs do make it through somehow; there must be a gradle configuration
    // that isn't matched above.
    project
        .getTasks()
        .withType(JavaCompile.class)
        .all(
            t -> {
              t.doFirst(
                  task -> {
                    List<File> aarFiles = findAarFiles(t.getClasspath());
                    if (!aarFiles.isEmpty()) {
                      throw new IllegalStateException(
                          "AARs on classpath: " + Joiner.on("\n  ").join(aarFiles));
                    }
                  });
            });
  }

  private List<File> findAarFiles(FileCollection files) {
    List<File> bad = new ArrayList<>();
    for (File file : files.getFiles()) {
      if (file.getName().toLowerCase().endsWith(".aar")) {
        bad.add(file);
      }
    }
    return bad;
  }

  static class ClassesJarExtractor extends ExtractAarTransform {
    @Override
    public List<File> transform(File input) {
      List<File> out = super.transform(input);
      File classesJar = new File(out.get(0), "jars/classes.jar");
      // jar needs a quasi-unique name or IntelliJ Gradle/Android plugins get confused...
      File renamed = new File(classesJar.getParent(), input.getName().replace(".aar", ".jar"));
      classesJar.renameTo(renamed);
      return Collections.singletonList(renamed);
    }
  }
}
