// Copyright 2018 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.lib.starlarkbuildapi.java;

import com.google.devtools.build.docgen.annot.DocCategory;
import com.google.devtools.build.docgen.annot.StarlarkConstructor;
import com.google.devtools.build.lib.collect.nestedset.Depset;
import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
import com.google.devtools.build.lib.starlarkbuildapi.FileApi;
import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi;
import com.google.devtools.build.lib.starlarkbuildapi.core.StructApi;
import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcInfoApi;
import com.google.devtools.build.lib.starlarkbuildapi.java.JavaPluginInfoApi.JavaPluginDataApi;
import javax.annotation.Nullable;
import net.starlark.java.annot.Param;
import net.starlark.java.annot.ParamType;
import net.starlark.java.annot.StarlarkBuiltin;
import net.starlark.java.annot.StarlarkMethod;
import net.starlark.java.eval.EvalException;
import net.starlark.java.eval.NoneType;
import net.starlark.java.eval.Sequence;
import net.starlark.java.eval.StarlarkThread;

/** Info object encapsulating all information by java rules. */
@StarlarkBuiltin(
    name = "JavaInfo",
    doc = "A provider encapsulating information about Java and Java-like targets.",
    category = DocCategory.PROVIDER)
public interface JavaInfoApi<
        FileT extends FileApi,
        JavaOutputT extends JavaOutputApi<FileT>,
        JavaPluginDataT extends JavaPluginDataApi>
    extends StructApi, JavaPluginInfoApi<FileT, JavaPluginDataT, JavaOutputT> {

  @StarlarkMethod(
      name = "transitive_runtime_jars",
      doc = "Returns a transitive set of Jars required on the target's runtime classpath.",
      structField = true)
  Depset getTransitiveRuntimeJars();

  @StarlarkMethod(
      name = "transitive_compile_time_jars",
      doc = "Returns the transitive set of Jars required to build the target.",
      structField = true)
  Depset getTransitiveCompileTimeJars();

  @StarlarkMethod(
      name = "compile_jars",
      doc =
          "Returns the Jars required by this target directly at compile time. They can be"
              + " interface jars (ijar or hjar), regular jars or both, depending on whether rule"
              + " implementations chose to create interface jars or not.",
      structField = true)
  Depset getCompileTimeJars();

  @StarlarkMethod(
      name = "full_compile_jars",
      doc =
          "Returns the regular, full compile time Jars required by this target directly. They can"
              + " be <ul><li> the corresponding regular Jars of the interface Jars returned by"
              + " <code><a class=\"anchor\""
              + " href=\"JavaInfo.html#compile_jars\">JavaInfo.compile_jars</a></code></li><li>"
              + " the regular (full) Jars returned by <code><a class=\"anchor\""
              + " href=\"JavaInfo.html#compile_jars\">JavaInfo.compile_jars</a></code></li></ul>"
              + "<p>Note: <code><a class=\"anchor\""
              + " href=\"JavaInfo.html#compile_jars\">JavaInfo.compile_jars</a></code> can return"
              + " a mix of interface Jars and regular Jars.<p>Only use this method if interface"
              + " Jars don't work with your rule set(s) (e.g. some Scala targets) If you're"
              + " working with Java-only targets it's preferable to use interface Jars via"
              + " <code><a class=\"anchor\""
              + " href=\"JavaInfo.html#compile_jars\">JavaInfo.compile_jars</a></code></li>",
      structField = true)
  Depset getFullCompileTimeJars();

  @StarlarkMethod(
      name = "source_jars",
      doc =
          "Returns a list of Jars with all the source files (including those generated by"
              + " annotations) of the target  itself, i.e. NOT including the sources of the"
              + " transitive dependencies.",
      structField = true)
  Sequence<FileT> getSourceJars();

  @StarlarkMethod(
      name = "outputs",
      doc =
          "Returns information about outputs of this Java/Java-like target. Deprecated: use"
              + " java_outputs.",
      structField = true,
      allowReturnNones = true)
  @Nullable
  @Deprecated
  JavaRuleOutputJarsProviderApi<?> getOutputJars();

  @StarlarkMethod(
      name = "annotation_processing",
      structField = true,
      allowReturnNones = true,
      doc =
          "Returns information about annotation processors applied on this Java/Java-like target."
              + "<p>Deprecated: Please use <code>plugins</code> instead (which returns information "
              + "about annotation processors to be applied by consuming targets).")
  @Nullable
  JavaAnnotationProcessingApi<?> getGenJarsProvider();

  @StarlarkMethod(
      name = "compilation_info",
      structField = true,
      allowReturnNones = true,
      doc = "Returns compilation information for this Java/Java-like target.")
  @Nullable
  JavaCompilationInfoProviderApi<?> getCompilationInfoProvider();

  @StarlarkMethod(
      name = "runtime_output_jars",
      doc = "Returns a list of runtime Jars created by this Java/Java-like target.",
      structField = true)
  Sequence<FileT> getRuntimeOutputJars();

  @StarlarkMethod(
      name = "transitive_deps",
      doc =
          "Deprecated: Please use <code><a class=\"anchor\" "
              + "href=\"JavaInfo.html#transitive_compile_time_jars\">JavaInfo.transitive_compile_time_jars</a></code>"
              + " instead. It returns the same value.",
      structField = true)
  Depset /*<FileT>*/ getTransitiveDeps();

  @StarlarkMethod(
      name = "transitive_runtime_deps",
      doc =
          "Deprecated: please use <code><a class=\"anchor\""
              + " href=\"JavaInfo.html#transitive_runtime_jars\">JavaInfo.transitive_runtime_jars"
              + "</a></code> instead. It returns the same value",
      structField = true)
  Depset /*<FileT>*/ getTransitiveRuntimeDeps();

  @StarlarkMethod(
      name = "transitive_source_jars",
      doc =
          "Returns the Jars containing source files of the current target and all of its"
              + " transitive dependencies.",
      structField = true)
  Depset /*<FileT>*/ getTransitiveSourceJars();

  @StarlarkMethod(
      name = "transitive_native_libraries",
      structField = true,
      doc = "Returns the transitive set of CC native libraries required by the target.")
  Depset /*<LibraryToLink>*/ getTransitiveNativeLibrariesForStarlark();

  @StarlarkMethod(
      name = "cc_link_params_info",
      structField = true,
      doc = "C++ libraries to be linked into Java targets.",
      enableOnlyWithFlag = BuildLanguageOptions.EXPERIMENTAL_GOOGLE_LEGACY_API)
  CcInfoApi<FileT> getCcLinkParamInfo();

  @StarlarkMethod(
      name = "module_flags_info",
      doc = "Returns the Java module flag configuration.",
      structField = true)
  JavaModuleFlagsProviderApi getJavaModuleFlagsInfo();

  /** Provider class for {@link JavaInfoApi} objects. */
  @StarlarkBuiltin(name = "Provider", documented = false, doc = "")
  interface JavaInfoProviderApi extends ProviderApi {

    @StarlarkMethod(
        name = "JavaInfo",
        doc = "The <code>JavaInfo</code> constructor.",
        parameters = {
          @Param(
              name = "output_jar",
              named = true,
              doc =
                  "The jar that was created as a result of a compilation "
                      + "(e.g. javac, scalac, etc)."),
          @Param(
              name = "compile_jar",
              allowedTypes = {
                @ParamType(type = FileApi.class),
                @ParamType(type = NoneType.class),
              },
              named = true,
              doc =
                  "A jar that is added as the compile-time dependency in lieu of "
                      + "<code>output_jar</code>. Typically this is the ijar produced by "
                      + "<code><a class=\"anchor\" href=\"java_common.html#run_ijar\">"
                      + "run_ijar</a></code>. "
                      + "If you cannot use ijar, consider instead using the output of "
                      + "<code><a class=\"anchor\" href=\"java_common.html#stamp_jar\">"
                      + "stamp_ijar</a></code>. If you do not wish to use either, "
                      + "you can simply pass <code>output_jar</code>. "
                      + "There are a couple of special cases when this parameter may be set to "
                      + "<code>None</code>, for example adding a jar with resources or when used in"
                      + " a terminal rule like <code>java_binary</code>."),
          @Param(
              name = "source_jar",
              allowedTypes = {
                @ParamType(type = FileApi.class),
                @ParamType(type = NoneType.class),
              },
              named = true,
              defaultValue = "None",
              doc =
                  "The source jar that was used to create the output jar. "
                      + "Use <code><a class=\"anchor\" href=\"java_common.html#pack_sources\">"
                      + "pack_sources</a></code> to produce this source jar."),
          @Param(
              name = "compile_jdeps",
              allowedTypes = {
                @ParamType(type = FileApi.class),
                @ParamType(type = NoneType.class),
              },
              named = true,
              defaultValue = "None",
              doc =
                  "jdeps information about compile time dependencies to be consumed by"
                      + " JavaCompileAction. This should be a binary proto encoded using the"
                      + " deps.proto protobuf included with Bazel.  If available this file is"
                      + " typically produced by a header compiler."),
          @Param(
              name = "generated_class_jar",
              allowedTypes = {
                @ParamType(type = FileApi.class),
                @ParamType(type = NoneType.class),
              },
              named = true,
              defaultValue = "None",
              doc =
                  "A jar file containing class files compiled from sources generated during"
                      + " annotation processing."),
          @Param(
              name = "generated_source_jar",
              allowedTypes = {
                @ParamType(type = FileApi.class),
                @ParamType(type = NoneType.class),
              },
              named = true,
              defaultValue = "None",
              doc = "The source jar that was created as a result of annotation processing."),
          @Param(
              name = "native_headers_jar",
              allowedTypes = {
                @ParamType(type = FileApi.class),
                @ParamType(type = NoneType.class),
              },
              named = true,
              defaultValue = "None",
              doc =
                  "A jar containing CC header files supporting native method implementation"
                      + " (typically output of javac -h)."),
          @Param(
              name = "manifest_proto",
              allowedTypes = {
                @ParamType(type = FileApi.class),
                @ParamType(type = NoneType.class),
              },
              named = true,
              defaultValue = "None",
              doc =
                  "Manifest information for the rule output (if available). This should be a"
                      + " binary proto encoded using the manifest.proto protobuf included with"
                      + " Bazel.  IDEs and other tools can use this information for more efficient"
                      + " processing."),
          @Param(
              name = "neverlink",
              named = true,
              defaultValue = "False",
              doc = "If true only use this library for compilation and not at runtime."),
          @Param(
              name = "deps",
              allowedTypes = {@ParamType(type = Sequence.class, generic1 = JavaInfoApi.class)},
              named = true,
              defaultValue = "[]",
              doc = "Compile time dependencies that were used to create the output jar."),
          @Param(
              name = "runtime_deps",
              allowedTypes = {@ParamType(type = Sequence.class, generic1 = JavaInfoApi.class)},
              named = true,
              defaultValue = "[]",
              doc = "Runtime dependencies that are needed for this library."),
          @Param(
              name = "exports",
              allowedTypes = {@ParamType(type = Sequence.class, generic1 = JavaInfoApi.class)},
              named = true,
              defaultValue = "[]",
              doc =
                  "Libraries to make available for users of this library. See also <a"
                      + " class=\"anchor\""
                      + " href=\"$BE_ROOT/java.html#java_library.exports\">"
                      + "java_library.exports</a>."),
          @Param(
              name = "exported_plugins",
              named = true,
              allowedTypes = {
                @ParamType(type = Sequence.class, generic1 = JavaPluginInfoApi.class)
              },
              defaultValue = "[]",
              doc = "A list of exported plugins. Optional."),
          @Param(
              name = "jdeps",
              allowedTypes = {
                @ParamType(type = FileApi.class),
                @ParamType(type = NoneType.class),
              },
              named = true,
              defaultValue = "None",
              doc =
                  "jdeps information for the rule output (if available). This should be a binary"
                      + " proto encoded using the deps.proto protobuf included with Bazel.  If"
                      + " available this file is typically produced by a compiler. IDEs and other"
                      + " tools can use this information for more efficient processing."),
          @Param(
              name = "native_libraries",
              allowedTypes = {@ParamType(type = Sequence.class, generic1 = CcInfoApi.class)},
              named = true,
              defaultValue = "[]",
              doc = "CC native library dependencies that are needed for this library."),
        },
        selfCall = true,
        useStarlarkThread = true)
    @StarlarkConstructor
    JavaInfoApi<?, ?, ?> javaInfo(
        FileApi outputJarApi,
        Object compileJarApi,
        Object sourceJarApi,
        Object compileJdepsApi,
        Object generatedClassJarApi,
        Object generatedSourceJarApi,
        Object nativeHeadersJarApi,
        Object manifestProtoApi,
        Boolean neverlink,
        Sequence<?> deps,
        Sequence<?> runtimeDeps,
        Sequence<?> exports,
        Sequence<?> exportedPlugins,
        Object jdepsApi,
        Sequence<?> nativeLibraries,
        StarlarkThread thread)
        throws EvalException;
  }
}
