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

import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.synthesis.SyntheticFinalization.Result;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;

public class SyntheticItems implements SyntheticDefinitionsProvider {

  static final int INVALID_ID_AFTER_SYNTHETIC_FINALIZATION = -1;

  /**
   * The internal synthetic class separator is only used for representing synthetic items during
   * compilation. In particular, this separator must never be used to write synthetic classes to the
   * final compilation result.
   */
  public static final String INTERNAL_SYNTHETIC_CLASS_SEPARATOR = "-$$InternalSynthetic";

  /**
   * The external synthetic class separator is used when writing classes. It may appear in types
   * during compilation as the output of a compilation may be the input to another.
   */
  public static final String EXTERNAL_SYNTHETIC_CLASS_SEPARATOR = "-$$ExternalSynthetic";

  /** Method prefix when generating synthetic methods in a class. */
  static final String INTERNAL_SYNTHETIC_METHOD_PREFIX = "m";

  public static boolean verifyNotInternalSynthetic(DexType type) {
    assert !type.toDescriptorString().contains(SyntheticItems.INTERNAL_SYNTHETIC_CLASS_SEPARATOR);
    return true;
  }

  /** Globally incremented id for the next internal synthetic class. */
  private int nextSyntheticId;

  /**
   * Thread safe collection of synthesized classes that are not yet committed to the application.
   * TODO(b/158159959): Remove legacy support.
   */
  private final Map<DexType, DexProgramClass> legacyPendingClasses = new ConcurrentHashMap<>();

  /**
   * Immutable set of synthetic types in the application (eg, committed). TODO(b/158159959): Remove
   * legacy support.
   */
  private final ImmutableSet<DexType> legacySyntheticTypes;

  /** Thread safe collection of synthetic items not yet committed to the application. */
  private final ConcurrentHashMap<DexType, SyntheticDefinition> pendingDefinitions =
      new ConcurrentHashMap<>();

  /** Mapping from synthetic type to its synthetic description. */
  private final ImmutableMap<DexType, SyntheticReference> nonLecacySyntheticItems;

  // Only for use from initial AppInfo/AppInfoWithClassHierarchy create functions. */
  public static SyntheticItems createInitialSyntheticItems() {
    return new SyntheticItems(0, ImmutableSet.of(), ImmutableMap.of());
  }

  // Only for conversion to a mutable synthetic items collection.
  SyntheticItems(CommittedItems commit) {
    this(commit.nextSyntheticId, commit.legacySyntheticTypes, commit.syntheticItems);
  }

  private SyntheticItems(
      int nextSyntheticId,
      ImmutableSet<DexType> legacySyntheticTypes,
      ImmutableMap<DexType, SyntheticReference> nonLecacySyntheticItems) {
    this.nextSyntheticId = nextSyntheticId;
    this.legacySyntheticTypes = legacySyntheticTypes;
    this.nonLecacySyntheticItems = nonLecacySyntheticItems;
    assert nonLecacySyntheticItems.keySet().stream()
        .noneMatch(
            t -> t.toDescriptorString().endsWith(getSyntheticDescriptorSuffix(nextSyntheticId)));
    assert Sets.intersection(nonLecacySyntheticItems.keySet(), legacySyntheticTypes).isEmpty();
  }

  // Internal synthetic id creation helpers.

  private synchronized int getNextSyntheticId() {
    if (nextSyntheticId == INVALID_ID_AFTER_SYNTHETIC_FINALIZATION) {
      throw new InternalCompilerError(
          "Unexpected attempt to synthesize classes after synthetic finalization.");
    }
    return nextSyntheticId++;
  }

  private static DexType hygienicType(
      DexItemFactory factory, int syntheticId, SynthesizingContext context) {
    String contextDesc = context.type.toDescriptorString();
    String prefix = contextDesc.substring(0, contextDesc.length() - 1);
    String syntheticDesc = prefix + getSyntheticDescriptorSuffix(syntheticId);
    return factory.createType(syntheticDesc);
  }

  private static String getSyntheticDescriptorSuffix(int syntheticId) {
    return INTERNAL_SYNTHETIC_CLASS_SEPARATOR + syntheticId + ";";
  }

  // Predicates and accessors.

  @Override
  public DexClass definitionFor(DexType type, Function<DexType, DexClass> baseDefinitionFor) {
    DexProgramClass pending = legacyPendingClasses.get(type);
    if (pending == null) {
      SyntheticDefinition item = pendingDefinitions.get(type);
      if (item != null) {
        pending = item.getHolder();
      }
    }
    if (pending != null) {
      assert baseDefinitionFor.apply(type) == null
          : "Pending synthetic definition also present in the active program: " + type;
      return pending;
    }
    return baseDefinitionFor.apply(type);
  }

  public boolean hasPendingSyntheticClasses() {
    return !legacyPendingClasses.isEmpty() || !pendingDefinitions.isEmpty();
  }

  public Collection<DexProgramClass> getPendingSyntheticClasses() {
    List<DexProgramClass> pending =
        new ArrayList<>(pendingDefinitions.size() + legacyPendingClasses.size());
    for (SyntheticDefinition item : pendingDefinitions.values()) {
      pending.add(item.getHolder());
    }
    pending.addAll(legacyPendingClasses.values());
    return Collections.unmodifiableList(pending);
  }

  private boolean isCommittedSynthetic(DexType type) {
    return nonLecacySyntheticItems.containsKey(type) || legacySyntheticTypes.contains(type);
  }

  public boolean isPendingSynthetic(DexType type) {
    return pendingDefinitions.containsKey(type) || legacyPendingClasses.containsKey(type);
  }

  public boolean isSyntheticClass(DexType type) {
    return isCommittedSynthetic(type)
        || isPendingSynthetic(type)
        // TODO(b/158159959): Remove usage of name-based identification.
        || type.isD8R8SynthesizedClassType();
  }

  public boolean isSyntheticClass(DexProgramClass clazz) {
    return isSyntheticClass(clazz.type);
  }

  public Collection<DexProgramClass> getLegacyPendingClasses() {
    return Collections.unmodifiableCollection(legacyPendingClasses.values());
  }

  private SynthesizingContext getSynthesizingContext(DexProgramClass context) {
    SyntheticDefinition pendingItemContext = pendingDefinitions.get(context.type);
    if (pendingItemContext != null) {
      return pendingItemContext.getContext();
    }
    SyntheticReference committedItemContext = nonLecacySyntheticItems.get(context.type);
    return committedItemContext != null
        ? committedItemContext.getContext()
        : new SynthesizingContext(context.type, context.origin);
  }

  // Addition and creation of synthetic items.

  // TODO(b/158159959): Remove the usage of this direct class addition (and name-based id).
  public void addLegacySyntheticClass(DexProgramClass clazz) {
    assert clazz.type.isD8R8SynthesizedClassType();
    assert !isCommittedSynthetic(clazz.type);
    DexProgramClass previous = legacyPendingClasses.put(clazz.type, clazz);
    assert previous == null || previous == clazz;
  }

  /** Create a single synthetic method item. */
  public ProgramMethod createMethod(
      DexProgramClass context, DexItemFactory factory, Consumer<SyntheticMethodBuilder> fn) {
    // Obtain the outer synthesizing context in the case the context itself is synthetic.
    // The is to ensure a flat input-type -> synthetic-item mapping.
    SynthesizingContext outerContext = getSynthesizingContext(context);
    DexType type = hygienicType(factory, getNextSyntheticId(), outerContext);
    DexProgramClass clazz =
        new SyntheticClassBuilder(type, outerContext, factory).addMethod(fn).build();
    ProgramMethod method = new ProgramMethod(clazz, clazz.methods().iterator().next());
    addPendingDefinition(new SyntheticMethodDefinition(outerContext, method));
    return method;
  }

  private void addPendingDefinition(SyntheticDefinition definition) {
    pendingDefinitions.put(definition.getHolder().getType(), definition);
  }

  // Commit of the synthetic items to a new fully populated application.

  public CommittedItems commit(DexApplication application) {
    return commitPrunedClasses(application, Collections.emptySet());
  }

  public CommittedItems commitPrunedClasses(
      DexApplication application, Set<DexType> removedClasses) {
    return commit(
        application,
        removedClasses,
        legacyPendingClasses,
        legacySyntheticTypes,
        pendingDefinitions,
        nonLecacySyntheticItems,
        nextSyntheticId);
  }

  public CommittedItems commitRewrittenWithLens(
      DexApplication application, NonIdentityGraphLens lens) {
    // Rewrite the previously committed synthetic types.
    ImmutableSet<DexType> rewrittenLegacyTypes = lens.rewriteTypes(this.legacySyntheticTypes);
    ImmutableMap.Builder<DexType, SyntheticReference> rewrittenItems = ImmutableMap.builder();
    for (SyntheticReference reference : nonLecacySyntheticItems.values()) {
      SyntheticReference rewritten = reference.rewrite(lens);
      rewrittenItems.put(rewritten.getHolder(), rewritten);
    }
    // No pending item should need rewriting.
    assert legacyPendingClasses.keySet().equals(lens.rewriteTypes(legacyPendingClasses.keySet()));
    assert pendingDefinitions.keySet().equals(lens.rewriteTypes(pendingDefinitions.keySet()));
    return commit(
        application,
        Collections.emptySet(),
        legacyPendingClasses,
        rewrittenLegacyTypes,
        pendingDefinitions,
        rewrittenItems.build(),
        nextSyntheticId);
  }

  private static CommittedItems commit(
      DexApplication application,
      Set<DexType> removedClasses,
      Map<DexType, DexProgramClass> legacyPendingClasses,
      ImmutableSet<DexType> legacySyntheticTypes,
      ConcurrentHashMap<DexType, SyntheticDefinition> pendingDefinitions,
      ImmutableMap<DexType, SyntheticReference> syntheticItems,
      int nextSyntheticId) {
    // Legacy synthetics must already have been committed.
    assert verifyClassesAreInApp(application, legacyPendingClasses.values());
    // Add the set of legacy definitions to the synthetic types.
    ImmutableSet<DexType> mergedLegacyTypes = legacySyntheticTypes;
    if (!legacyPendingClasses.isEmpty() || !removedClasses.isEmpty()) {
      ImmutableSet.Builder<DexType> legacyBuilder = ImmutableSet.builder();
      filteredAdd(legacySyntheticTypes, removedClasses, legacyBuilder);
      filteredAdd(legacyPendingClasses.keySet(), removedClasses, legacyBuilder);
      mergedLegacyTypes = legacyBuilder.build();
    }
    // The set of synthetic items is the union of the previous types plus the pending additions.
    ImmutableMap<DexType, SyntheticReference> mergedItems;
    ImmutableList<DexType> additions;
    DexApplication amendedApplication;
    if (pendingDefinitions.isEmpty()) {
      mergedItems = filteredCopy(syntheticItems, removedClasses);
      additions = ImmutableList.of();
      amendedApplication = application;
    } else {
      DexApplication.Builder<?> appBuilder = application.builder();
      ImmutableMap.Builder<DexType, SyntheticReference> itemsBuilder = ImmutableMap.builder();
      ImmutableList.Builder<DexType> additionsBuilder = ImmutableList.builder();
      for (SyntheticDefinition definition : pendingDefinitions.values()) {
        if (removedClasses.contains(definition.getHolder().getType())) {
          continue;
        }
        SyntheticReference reference = definition.toReference();
        itemsBuilder.put(reference.getHolder(), reference);
        additionsBuilder.add(definition.getHolder().getType());
        appBuilder.addProgramClass(definition.getHolder());
      }
      filteredAdd(syntheticItems, removedClasses, itemsBuilder);
      mergedItems = itemsBuilder.build();
      additions = additionsBuilder.build();
      amendedApplication = appBuilder.build();
    }
    return new CommittedItems(
        nextSyntheticId, amendedApplication, mergedLegacyTypes, mergedItems, additions);
  }

  private static void filteredAdd(
      Set<DexType> input, Set<DexType> excludeSet, Builder<DexType> result) {
    if (excludeSet.isEmpty()) {
      result.addAll(input);
    } else {
      for (DexType type : input) {
        if (!excludeSet.contains(type)) {
          result.add(type);
        }
      }
    }
  }

  private static ImmutableMap<DexType, SyntheticReference> filteredCopy(
      ImmutableMap<DexType, SyntheticReference> syntheticItems, Set<DexType> removedClasses) {
    if (removedClasses.isEmpty()) {
      return syntheticItems;
    }
    ImmutableMap.Builder<DexType, SyntheticReference> builder = ImmutableMap.builder();
    filteredAdd(syntheticItems, removedClasses, builder);
    return builder.build();
  }

  private static void filteredAdd(
      ImmutableMap<DexType, SyntheticReference> syntheticItems,
      Set<DexType> removedClasses,
      ImmutableMap.Builder<DexType, SyntheticReference> builder) {
    if (removedClasses.isEmpty()) {
      builder.putAll(syntheticItems);
    } else {
      syntheticItems.forEach(
          (t, r) -> {
            if (!removedClasses.contains(t)) {
              builder.put(t, r);
            }
          });
    }
  }

  private static boolean verifyClassesAreInApp(
      DexApplication app, Collection<DexProgramClass> classes) {
    for (DexProgramClass clazz : classes) {
      assert app.programDefinitionFor(clazz.type) != null : "Missing synthetic: " + clazz.type;
    }
    return true;
  }

  // Finalization of synthetic items.

  public Result computeFinalSynthetics(AppView<?> appView) {
    assert !hasPendingSyntheticClasses();
    return new SyntheticFinalization(
            appView.options(), legacySyntheticTypes, nonLecacySyntheticItems)
        .computeFinalSynthetics(appView);
  }
}
