// Copyright (c) 2021, 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.ir.desugar.desugaredlibrary.legacyspecification;

import com.android.tools.r8.StringResource;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.SemanticVersion;
import com.android.tools.r8.utils.StringDiagnostic;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

public class LegacyDesugaredLibrarySpecificationParser {

  public static final int MAX_SUPPORTED_VERSION = 4;
  public static final SemanticVersion MIN_SUPPORTED_VERSION = new SemanticVersion(1, 0, 9);

  static final String CONFIGURATION_FORMAT_VERSION_KEY = "configuration_format_version";
  static final String VERSION_KEY = "version";
  static final String GROUP_ID_KEY = "group_id";
  static final String ARTIFACT_ID_KEY = "artifact_id";
  static final String REQUIRED_COMPILATION_API_LEVEL_KEY = "required_compilation_api_level";
  static final String SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY =
      "synthesized_library_classes_package_prefix";

  static final String COMMON_FLAGS_KEY = "common_flags";
  static final String LIBRARY_FLAGS_KEY = "library_flags";
  static final String PROGRAM_FLAGS_KEY = "program_flags";

  static final String API_LEVEL_BELOW_OR_EQUAL_KEY = "api_level_below_or_equal";
  static final String WRAPPER_CONVERSION_KEY = "wrapper_conversion";
  static final String CUSTOM_CONVERSION_KEY = "custom_conversion";
  static final String REWRITE_PREFIX_KEY = "rewrite_prefix";
  static final String RETARGET_LIB_MEMBER_KEY = "retarget_lib_member";
  static final String EMULATE_INTERFACE_KEY = "emulate_interface";
  static final String DONT_REWRITE_KEY = "dont_rewrite";
  static final String DONT_RETARGET_LIB_MEMBER_KEY = "dont_retarget_lib_member";
  static final String BACKPORT_KEY = "backport";
  static final String SHRINKER_CONFIG_KEY = "shrinker_config";
  static final String SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY = "support_all_callbacks_from_library";

  private final DexItemFactory dexItemFactory;
  private final Reporter reporter;
  private final boolean libraryCompilation;
  private final int minAPILevel;

  private Origin origin;
  private JsonObject jsonConfig;

  public LegacyDesugaredLibrarySpecificationParser(
      DexItemFactory dexItemFactory,
      Reporter reporter,
      boolean libraryCompilation,
      int minAPILevel) {
    this.dexItemFactory = dexItemFactory;
    this.reporter = reporter;
    this.minAPILevel = minAPILevel;
    this.libraryCompilation = libraryCompilation;
  }

  public DexItemFactory dexItemFactory() {
    return dexItemFactory;
  }

  public Reporter reporter() {
    return reporter;
  }

  public JsonObject getJsonConfig() {
    return jsonConfig;
  }

  public Origin getOrigin() {
    assert origin != null;
    return origin;
  }

  JsonElement required(JsonObject json, String key) {
    if (!json.has(key)) {
      throw reporter.fatalError(
          new StringDiagnostic(
              "Invalid desugared library configuration. Expected required key '" + key + "'",
              origin));
    }
    return json.get(key);
  }

  public LegacyDesugaredLibrarySpecification parse(StringResource stringResource) {
    return parse(stringResource, builder -> {});
  }

  public LegacyDesugaredLibrarySpecification parse(
      StringResource stringResource, Consumer<LegacyTopLevelFlags.Builder> topLevelFlagAmender) {
    String jsonConfigString = parseJson(stringResource);

    LegacyTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString, topLevelFlagAmender);

    LegacyRewritingFlags legacyRewritingFlags = parseRewritingFlags();

    LegacyDesugaredLibrarySpecification config =
        new LegacyDesugaredLibrarySpecification(
            topLevelFlags, legacyRewritingFlags, libraryCompilation);
    origin = null;
    return config;
  }

  String parseJson(StringResource stringResource) {
    setOrigin(stringResource);
    String jsonConfigString;
    try {
      jsonConfigString = stringResource.getString();
      JsonParser parser = new JsonParser();
      jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
    } catch (Exception e) {
      throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
    }
    return jsonConfigString;
  }

  void setOrigin(StringResource stringResource) {
    origin = stringResource.getOrigin();
    assert origin != null;
  }

  private LegacyRewritingFlags parseRewritingFlags() {
    LegacyRewritingFlags.Builder builder =
        LegacyRewritingFlags.builder(dexItemFactory, reporter, origin);
    JsonElement commonFlags = required(jsonConfig, COMMON_FLAGS_KEY);
    JsonElement libraryFlags = required(jsonConfig, LIBRARY_FLAGS_KEY);
    JsonElement programFlags = required(jsonConfig, PROGRAM_FLAGS_KEY);
    parseFlagsList(commonFlags.getAsJsonArray(), builder);
    parseFlagsList(
        libraryCompilation ? libraryFlags.getAsJsonArray() : programFlags.getAsJsonArray(),
        builder);
    return builder.build();
  }

  LegacyTopLevelFlags parseTopLevelFlags(
      String jsonConfigString, Consumer<LegacyTopLevelFlags.Builder> topLevelFlagAmender) {
    LegacyTopLevelFlags.Builder builder = LegacyTopLevelFlags.builder();

    builder.setJsonSource(jsonConfigString);

    JsonElement formatVersionElement = required(jsonConfig, CONFIGURATION_FORMAT_VERSION_KEY);
    int formatVersion = formatVersionElement.getAsInt();
    if (formatVersion > MAX_SUPPORTED_VERSION) {
      throw reporter.fatalError(
          new StringDiagnostic(
              "Unsupported desugared library configuration version, please upgrade the D8/R8"
                  + " compiler.",
              origin));
    }

    String version = required(jsonConfig, VERSION_KEY).getAsString();
    SemanticVersion semanticVersion = SemanticVersion.parse(version);
    if (!semanticVersion.isNewerOrEqual(MIN_SUPPORTED_VERSION)) {
      throw reporter.fatalError(
          new StringDiagnostic(
              "Unsupported desugared library version: "
                  + version
                  + ", please upgrade the desugared library to at least version "
                  + MIN_SUPPORTED_VERSION
                  + ".",
              origin));
    }

    String groupID = required(jsonConfig, GROUP_ID_KEY).getAsString();
    String artifactID = required(jsonConfig, ARTIFACT_ID_KEY).getAsString();
    String identifier = String.join(":", groupID, artifactID, version);
    builder.setDesugaredLibraryIdentifier(identifier);
    builder.setSynthesizedLibraryClassesPackagePrefix(
        required(jsonConfig, SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY).getAsString());

    int required_compilation_api_level =
        required(jsonConfig, REQUIRED_COMPILATION_API_LEVEL_KEY).getAsInt();
    builder.setRequiredCompilationAPILevel(
        AndroidApiLevel.getAndroidApiLevel(required_compilation_api_level));
    if (jsonConfig.has(SHRINKER_CONFIG_KEY)) {
      JsonArray jsonKeepRules = jsonConfig.get(SHRINKER_CONFIG_KEY).getAsJsonArray();
      List<String> extraKeepRules = new ArrayList<>(jsonKeepRules.size());
      for (JsonElement keepRule : jsonKeepRules) {
        extraKeepRules.add(keepRule.getAsString());
      }
      builder.setExtraKeepRules(extraKeepRules);
    }

    if (jsonConfig.has(SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY)) {
      boolean supportAllCallbacksFromLibrary =
          jsonConfig.get(SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY).getAsBoolean();
      builder.setSupportAllCallbacksFromLibrary(supportAllCallbacksFromLibrary);
    }

    topLevelFlagAmender.accept(builder);

    return builder.build();
  }

  private void parseFlagsList(JsonArray jsonFlags, LegacyRewritingFlags.Builder builder) {
    for (JsonElement jsonFlagSet : jsonFlags) {
      JsonObject flag = jsonFlagSet.getAsJsonObject();
      int api_level_below_or_equal = required(flag, API_LEVEL_BELOW_OR_EQUAL_KEY).getAsInt();
      if (minAPILevel <= api_level_below_or_equal) {
        parseFlags(flag, builder);
      }
    }
  }

  void parseFlags(JsonObject jsonFlagSet, LegacyRewritingFlags.Builder builder) {
    if (jsonFlagSet.has(REWRITE_PREFIX_KEY)) {
      for (Map.Entry<String, JsonElement> rewritePrefix :
          jsonFlagSet.get(REWRITE_PREFIX_KEY).getAsJsonObject().entrySet()) {
        builder.putRewritePrefix(rewritePrefix.getKey(), rewritePrefix.getValue().getAsString());
      }
    }
    if (jsonFlagSet.has(RETARGET_LIB_MEMBER_KEY)) {
      for (Map.Entry<String, JsonElement> retarget :
          jsonFlagSet.get(RETARGET_LIB_MEMBER_KEY).getAsJsonObject().entrySet()) {
        builder.putRetargetCoreLibMember(retarget.getKey(), retarget.getValue().getAsString());
      }
    }
    if (jsonFlagSet.has(BACKPORT_KEY)) {
      for (Map.Entry<String, JsonElement> backport :
          jsonFlagSet.get(BACKPORT_KEY).getAsJsonObject().entrySet()) {
        builder.putBackportCoreLibraryMember(backport.getKey(), backport.getValue().getAsString());
      }
    }
    if (jsonFlagSet.has(EMULATE_INTERFACE_KEY)) {
      for (Map.Entry<String, JsonElement> itf :
          jsonFlagSet.get(EMULATE_INTERFACE_KEY).getAsJsonObject().entrySet()) {
        builder.putEmulateLibraryInterface(itf.getKey(), itf.getValue().getAsString());
      }
    }
    if (jsonFlagSet.has(CUSTOM_CONVERSION_KEY)) {
      for (Map.Entry<String, JsonElement> conversion :
          jsonFlagSet.get(CUSTOM_CONVERSION_KEY).getAsJsonObject().entrySet()) {
        builder.putCustomConversion(conversion.getKey(), conversion.getValue().getAsString());
      }
    }
    if (jsonFlagSet.has(WRAPPER_CONVERSION_KEY)) {
      for (JsonElement wrapper : jsonFlagSet.get(WRAPPER_CONVERSION_KEY).getAsJsonArray()) {
        builder.addWrapperConversion(wrapper.getAsString());
      }
    }
    if (jsonFlagSet.has(DONT_REWRITE_KEY)) {
      JsonArray dontRewrite = jsonFlagSet.get(DONT_REWRITE_KEY).getAsJsonArray();
      for (JsonElement rewrite : dontRewrite) {
        builder.addDontRewriteInvocation(rewrite.getAsString());
      }
    }
    if (jsonFlagSet.has(DONT_RETARGET_LIB_MEMBER_KEY)) {
      JsonArray dontRetarget = jsonFlagSet.get(DONT_RETARGET_LIB_MEMBER_KEY).getAsJsonArray();
      for (JsonElement rewrite : dontRetarget) {
        builder.addDontRetargetLibMember(rewrite.getAsString());
      }
    }
  }
}
