/*
 * Copyright 2014-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.facebook.buck.android;

import com.facebook.buck.jvm.java.CalculateAbiFromClasses;
import com.facebook.buck.jvm.java.HasJavaAbi;
import com.facebook.buck.jvm.java.JavaBuckConfig;
import com.facebook.buck.jvm.java.JavaLibrary;
import com.facebook.buck.jvm.java.JavaLibraryDescription;
import com.facebook.buck.jvm.java.JavaSourceJar;
import com.facebook.buck.jvm.java.JavacOptions;
import com.facebook.buck.jvm.java.JavacOptionsFactory;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.model.Flavored;
import com.facebook.buck.parser.NoSuchBuildTargetException;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.BuildRuleType;
import com.facebook.buck.rules.CellPathResolver;
import com.facebook.buck.rules.Description;
import com.facebook.buck.rules.ImplicitDepsInferringDescription;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.query.Query;
import com.facebook.buck.util.immutables.BuckStyleImmutable;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableSet;
import java.util.Optional;
import org.immutables.value.Value;

public class AndroidLibraryDescription
    implements Description<AndroidLibraryDescriptionArg>,
        Flavored,
        ImplicitDepsInferringDescription<
            AndroidLibraryDescription.AbstractAndroidLibraryDescriptionArg> {
  public static final BuildRuleType TYPE = BuildRuleType.of("android_library");

  private static final Flavor DUMMY_R_DOT_JAVA_FLAVOR =
      AndroidLibraryGraphEnhancer.DUMMY_R_DOT_JAVA_FLAVOR;

  public enum JvmLanguage {
    JAVA,
    KOTLIN,
    SCALA,
  }

  private final JavaBuckConfig javaBuckConfig;
  private final JavacOptions defaultOptions;
  private final AndroidLibraryCompilerFactory compilerFactory;

  public AndroidLibraryDescription(
      JavaBuckConfig javaBuckConfig,
      JavacOptions defaultOptions,
      AndroidLibraryCompilerFactory compilerFactory) {
    this.javaBuckConfig = javaBuckConfig;
    this.defaultOptions = defaultOptions;
    this.compilerFactory = compilerFactory;
  }

  @Override
  public Class<AndroidLibraryDescriptionArg> getConstructorArgType() {
    return AndroidLibraryDescriptionArg.class;
  }

  @Override
  public BuildRule createBuildRule(
      TargetGraph targetGraph,
      BuildRuleParams params,
      BuildRuleResolver resolver,
      CellPathResolver cellRoots,
      AndroidLibraryDescriptionArg args)
      throws NoSuchBuildTargetException {
    if (params.getBuildTarget().getFlavors().contains(JavaLibrary.SRC_JAR)) {
      return new JavaSourceJar(params, args.getSrcs(), args.getMavenCoords());
    }

    SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver);

    boolean hasDummyRDotJavaFlavor =
        params.getBuildTarget().getFlavors().contains(DUMMY_R_DOT_JAVA_FLAVOR);
    if (HasJavaAbi.isClassAbiTarget(params.getBuildTarget())) {
      Preconditions.checkArgument(!hasDummyRDotJavaFlavor);
      BuildTarget libraryTarget = HasJavaAbi.getLibraryTarget(params.getBuildTarget());
      BuildRule libraryRule = resolver.requireRule(libraryTarget);
      return CalculateAbiFromClasses.of(
          params.getBuildTarget(),
          ruleFinder,
          params,
          Preconditions.checkNotNull(libraryRule.getSourcePathToOutput()));
    }

    JavacOptions javacOptions = JavacOptionsFactory.create(defaultOptions, params, resolver, args);

    AndroidLibrary.Builder defaultJavaLibraryBuilder =
        (AndroidLibrary.Builder)
            AndroidLibrary.builder(
                    targetGraph,
                    params,
                    resolver,
                    cellRoots,
                    javaBuckConfig,
                    javacOptions,
                    args,
                    compilerFactory)
                .setArgs(args)
                .setJavacOptions(javacOptions)
                .setTests(args.getTests());

    if (hasDummyRDotJavaFlavor) {
      return defaultJavaLibraryBuilder.buildDummyRDotJava();
    }
    return defaultJavaLibraryBuilder.build();
  }

  @Override
  public boolean hasFlavors(ImmutableSet<Flavor> flavors) {
    return flavors.isEmpty()
        || flavors.equals(ImmutableSet.of(JavaLibrary.SRC_JAR))
        || flavors.equals(ImmutableSet.of(DUMMY_R_DOT_JAVA_FLAVOR));
  }

  @Override
  public void findDepsForTargetFromConstructorArgs(
      BuildTarget buildTarget,
      CellPathResolver cellRoots,
      AbstractAndroidLibraryDescriptionArg constructorArg,
      ImmutableCollection.Builder<BuildTarget> extraDepsBuilder,
      ImmutableCollection.Builder<BuildTarget> targetGraphOnlyDepsBuilder) {
    compilerFactory
        .getCompiler(constructorArg.getLanguage().orElse(JvmLanguage.JAVA))
        .findDepsForTargetFromConstructorArgs(
            buildTarget, cellRoots, constructorArg, extraDepsBuilder, targetGraphOnlyDepsBuilder);
  }

  public interface CoreArg extends JavaLibraryDescription.CoreArg {
    Optional<SourcePath> getManifest();

    Optional<String> getResourceUnionPackage();

    Optional<String> getFinalRName();

    Optional<JvmLanguage> getLanguage();

    Optional<Query> getDepsQuery();

    Optional<Query> getProvidedDepsQuery();
  }

  @BuckStyleImmutable
  @Value.Immutable
  interface AbstractAndroidLibraryDescriptionArg extends CoreArg {}
}

@@ -640,67 +640,8 @@
 d;%0A%0A
-import com.facebook.buck.jvm.java.CalculateAbiFromClasses;%0A
 impo
@@ -682,16 +682,16 @@
 avaAbi;%0A
+
 import c
@@ -1564,61 +1564,8 @@
 th;%0A
-import com.facebook.buck.rules.SourcePathRuleFinder;%0A
 impo
@@ -1713,53 +1713,8 @@
 le;%0A
-import com.google.common.base.Preconditions;%0A
 impo
@@ -3386,83 +3386,8 @@
  %7D%0A%0A
-    SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver);%0A%0A
     
@@ -3503,486 +3503,8 @@
 R);%0A
-    if (HasJavaAbi.isClassAbiTarget(params.getBuildTarget())) %7B%0A      Preconditions.checkArgument(!hasDummyRDotJavaFlavor);%0A      BuildTarget libraryTarget = HasJavaAbi.getLibraryTarget(params.getBuildTarget());%0A      BuildRule libraryRule = resolver.requireRule(libraryTarget);%0A      return CalculateAbiFromClasses.of(%0A          params.getBuildTarget(),%0A          ruleFinder,%0A          params,%0A          Preconditions.checkNotNull(libraryRule.getSourcePathToOutput()));%0A    %7D%0A%0A
     
@@ -3599,17 +3599,16 @@
  args);%0A
-%0A
     Andr
@@ -4131,24 +4131,24 @@
 vaFlavor) %7B%0A
-
       return
@@ -4196,16 +4196,133 @@
 Java();%0A
+    %7D else if (HasJavaAbi.isAbiTarget(params.getBuildTarget())) %7B%0A      return defaultJavaLibraryBuilder.buildAbi();%0A
     %7D%0A  

Move ABI rule construction into the builder