// 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 static java.util.Collections.emptyList;

import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.synthesis.SyntheticItems.ContextsForGlobalSynthetics;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

/**
 * Immutable collection of committed items.
 *
 * <p>This structure is to make it easier to pass the items from SyntheticItems to CommittedItems
 * and back while also providing a builder for updating the committed synthetics.
 */
class CommittedSyntheticsCollection {

  static class Builder {
    private final CommittedSyntheticsCollection parent;
    private Map<DexType, List<SyntheticProgramClassReference>> classes = null;
    private Map<DexType, List<SyntheticMethodReference>> methods = null;
    private ImmutableSet.Builder<DexType> newSyntheticInputs = null;
    private Map<DexType, Set<DexType>> globalContexts = null;

    public Builder(CommittedSyntheticsCollection parent) {
      this.parent = parent;
    }

    public Builder addItem(SyntheticDefinition<?, ?, ?> definition) {
      if (definition.isProgramDefinition()) {
        definition.asProgramDefinition().apply(this::addMethod, this::addClass);
      }
      return this;
    }

    public Builder addClass(SyntheticProgramClassDefinition definition) {
      return addClass(definition.toReference());
    }

    public Builder addClass(SyntheticProgramClassReference reference) {
      if (classes == null) {
        classes = new IdentityHashMap<>();
      }
      classes.computeIfAbsent(reference.getHolder(), ignore -> new ArrayList<>()).add(reference);
      return this;
    }

    public Builder addMethod(SyntheticMethodDefinition definition) {
      return addMethod(definition.toReference());
    }

    public Builder addMethod(SyntheticMethodReference reference) {
      if (methods == null) {
        methods = new IdentityHashMap<>();
      }
      methods.computeIfAbsent(reference.getHolder(), ignore -> new ArrayList<>()).add(reference);
      return this;
    }

    public Builder addSyntheticInput(DexType syntheticInput) {
      ensureNewSyntheticInputs().add(syntheticInput);
      return this;
    }

    Builder collectSyntheticInputs() {
      if (classes != null) {
        ensureNewSyntheticInputs().addAll(classes.keySet());
      }
      if (methods != null) {
        ensureNewSyntheticInputs().addAll(methods.keySet());
      }
      return this;
    }

    private ImmutableSet.Builder<DexType> ensureNewSyntheticInputs() {
      if (newSyntheticInputs == null) {
        newSyntheticInputs = ImmutableSet.builder();
      }
      return newSyntheticInputs;
    }

    public Builder addGlobalContexts(ContextsForGlobalSynthetics additionalGlobalContexts) {
      if (!additionalGlobalContexts.isEmpty()) {
        if (globalContexts == null) {
          globalContexts = new IdentityHashMap<>();
        }
        additionalGlobalContexts.forEach(
            (globalType, contexts) ->
                globalContexts
                    .computeIfAbsent(globalType, k -> SetUtils.newIdentityHashSet())
                    .addAll(contexts));
      }
      return this;
    }

    public CommittedSyntheticsCollection build() {
      if (classes == null && methods == null && globalContexts == null) {
        // Adding synthetic inputs implies that an actual synthetic is added too.
        assert newSyntheticInputs == null;
        return parent;
      }
      ImmutableMap<DexType, List<SyntheticProgramClassReference>> allClasses =
          mergeMapOfLists(classes, parent.classes);
      ImmutableMap<DexType, List<SyntheticMethodReference>> allMethods =
          mergeMapOfLists(methods, parent.methods);
      ImmutableSet<DexType> allSyntheticInputs =
          newSyntheticInputs == null ? parent.syntheticInputs : newSyntheticInputs.build();
      ImmutableMap<DexType, Set<DexType>> allGlobalContexts =
          globalContexts == null
              ? parent.globalContexts
              : mergeMapOfSets(globalContexts, parent.globalContexts);
      return new CommittedSyntheticsCollection(
          parent.naming, allMethods, allClasses, allGlobalContexts, allSyntheticInputs);
    }
  }

  private static <T> ImmutableMap<DexType, List<T>> mergeMapOfLists(
      Map<DexType, List<T>> newSynthetics, ImmutableMap<DexType, List<T>> oldSynthetics) {
    if (newSynthetics == null) {
      return oldSynthetics;
    }
    oldSynthetics.forEach(
        (type, elements) ->
            newSynthetics.computeIfAbsent(type, ignore -> new ArrayList<>()).addAll(elements));
    return ImmutableMap.copyOf(newSynthetics);
  }

  private static <T> ImmutableMap<DexType, Set<T>> mergeMapOfSets(
      Map<DexType, Set<T>> newSynthetics, ImmutableMap<DexType, Set<T>> oldSynthetics) {
    if (newSynthetics == null) {
      return oldSynthetics;
    }
    oldSynthetics.forEach(
        (type, elements) ->
            newSynthetics.computeIfAbsent(type, ignore -> new HashSet<>()).addAll(elements));
    return ImmutableMap.copyOf(newSynthetics);
  }

  private final SyntheticNaming naming;

  /** Mapping from synthetic type to its synthetic method item description. */
  private final ImmutableMap<DexType, List<SyntheticMethodReference>> methods;

  /** Mapping from synthetic type to its synthetic class item description. */
  private final ImmutableMap<DexType, List<SyntheticProgramClassReference>> classes;

  /** Mapping from global synthetic type to its synthesizing contexts. */
  private final ImmutableMap<DexType, Set<DexType>> globalContexts;

  /** Set of synthetic types that were present in the input. */
  public final ImmutableSet<DexType> syntheticInputs;

  public CommittedSyntheticsCollection(
      SyntheticNaming naming,
      ImmutableMap<DexType, List<SyntheticMethodReference>> methods,
      ImmutableMap<DexType, List<SyntheticProgramClassReference>> classes,
      ImmutableMap<DexType, Set<DexType>> globalContexts,
      ImmutableSet<DexType> syntheticInputs) {
    this.naming = naming;
    this.methods = methods;
    this.classes = classes;
    this.globalContexts = globalContexts;
    this.syntheticInputs = syntheticInputs;
    assert verifySyntheticInputsSubsetOfSynthetics();
  }

  SyntheticNaming getNaming() {
    return naming;
  }

  private boolean verifySyntheticInputsSubsetOfSynthetics() {
    Set<DexType> synthetics =
        ImmutableSet.<DexType>builder().addAll(methods.keySet()).addAll(classes.keySet()).build();
    syntheticInputs.forEach(
        syntheticInput -> {
          assert synthetics.contains(syntheticInput)
              : "Expected " + syntheticInput.toSourceString() + " to be a synthetic";
        });
    return true;
  }

  public static CommittedSyntheticsCollection empty(SyntheticNaming naming) {
    return new CommittedSyntheticsCollection(
        naming, ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of(), ImmutableSet.of());
  }

  Builder builder() {
    return new Builder(this);
  }

  boolean isEmpty() {
    boolean empty = methods.isEmpty() && classes.isEmpty();
    assert !empty || syntheticInputs.isEmpty();
    return empty;
  }

  public boolean containsType(DexType type) {
    return methods.containsKey(type) || classes.containsKey(type);
  }

  boolean containsTypeOfKind(DexType type, SyntheticKind kind) {
    List<SyntheticProgramClassReference> synthetics = classes.get(type);
    if (synthetics == null) {
      List<SyntheticMethodReference> syntheticMethodReferences = methods.get(type);
      if (syntheticMethodReferences == null) {
        return false;
      }
      for (SyntheticMethodReference syntheticMethodReference : syntheticMethodReferences) {
        if (syntheticMethodReference.getKind() == kind) {
          return true;
        }
      }
      return false;
    }
    for (SyntheticProgramClassReference synthetic : synthetics) {
      if (synthetic.getKind() == kind) {
        return true;
      }
    }
    return false;
  }

  public boolean containsSyntheticInput(DexType type) {
    return syntheticInputs.contains(type);
  }

  public Set<DexType> getContextsForGlobal(DexType globalSynthetic) {
    return globalContexts.get(globalSynthetic);
  }

  public ImmutableMap<DexType, Set<DexType>> getGlobalContexts() {
    return globalContexts;
  }

  public ImmutableMap<DexType, List<SyntheticMethodReference>> getMethods() {
    return methods;
  }

  public ImmutableMap<DexType, List<SyntheticProgramClassReference>> getClasses() {
    return classes;
  }

  public Iterable<SyntheticReference<?, ?, ?>> getItems(DexType type) {
    return Iterables.concat(
        classes.getOrDefault(type, emptyList()), methods.getOrDefault(type, emptyList()));
  }

  public void forEachSyntheticInput(Consumer<DexType> fn) {
    syntheticInputs.forEach(fn);
  }

  public void forEachItem(Consumer<SyntheticReference<?, ?, ?>> fn) {
    methods.values().forEach(r -> r.forEach(fn));
    classes.values().forEach(r -> r.forEach(fn));
  }

  CommittedSyntheticsCollection pruneItems(PrunedItems prunedItems) {
    Set<DexType> removed = prunedItems.getNoLongerSyntheticItems();
    if (removed.isEmpty()) {
      return this;
    }
    Builder builder = CommittedSyntheticsCollection.empty(naming).builder();
    boolean changed = false;
    for (SyntheticMethodReference reference : IterableUtils.flatten(methods.values())) {
      if (removed.contains(reference.getHolder())) {
        changed = true;
      } else {
        builder.addMethod(reference);
      }
    }
    for (SyntheticProgramClassReference reference : IterableUtils.flatten(classes.values())) {
      if (removed.contains(reference.getHolder())) {
        changed = true;
      } else {
        builder.addClass(reference);
      }
    }
    for (DexType syntheticInput : syntheticInputs) {
      if (removed.contains(syntheticInput)) {
        changed = true;
      } else {
        builder.addSyntheticInput(syntheticInput);
      }
    }
    // Global synthetic contexts are only collected for per-file modes which only prune synthetic
    // items, not inputs.
    assert globalContexts.isEmpty()
        || prunedItems.getNoLongerSyntheticItems().size() == prunedItems.getRemovedClasses().size();
    return changed ? builder.build() : this;
  }

  CommittedSyntheticsCollection rewriteWithLens(NonIdentityGraphLens lens) {
    ImmutableSet.Builder<DexType> syntheticInputsBuilder = ImmutableSet.builder();
    return new CommittedSyntheticsCollection(
        naming,
        rewriteItems(methods, lens, syntheticInputsBuilder),
        rewriteItems(classes, lens, syntheticInputsBuilder),
        globalContexts,
        syntheticInputsBuilder.build());
  }

  private <R extends Rewritable<R>> ImmutableMap<DexType, List<R>> rewriteItems(
      Map<DexType, List<R>> items,
      NonIdentityGraphLens lens,
      ImmutableSet.Builder<DexType> syntheticInputsBuilder) {
    Map<DexType, List<R>> rewrittenItems = new IdentityHashMap<>();
    for (R reference : IterableUtils.flatten(items.values())) {
      R rewritten = reference.rewrite(lens);
      if (rewritten != null) {
        rewrittenItems
            .computeIfAbsent(rewritten.getHolder(), ignore -> new ArrayList<>())
            .add(rewritten);
        if (syntheticInputs.contains(reference.getHolder())) {
          syntheticInputsBuilder.add(rewritten.getHolder());
        }
      }
    }
    return ImmutableMap.copyOf(rewrittenItems);
  }

  boolean verifyTypesAreInApp(DexApplication application) {
    assert verifyTypesAreInApp(application, methods.keySet());
    assert verifyTypesAreInApp(application, classes.keySet());
    assert verifyTypesAreInApp(application, syntheticInputs);
    return true;
  }

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