// Copyright 2017 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.analysis;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.Aspect;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Represents aspects that should be applied to a configured target as part of {@link Dependency}.
 *
 * <p>One can consider the configured target graph as being a DAG in two dimensions: one is the DAG
 * analogous to the target graph and the other is a DAG between aspects applied to the same
 * configured target. This class represents the latter. The full "aspect dependency graph" is
 * computed when traversing the configured target graph. The analysis of the aspects attached to the
 * same configured target is done by simply unwrapping the graph of {@link AspectDeps} instances.
 *
 * <p>{@link Dependency} encapsulates all information that is needed to analyze an edge between an
 * AspectValue or a ConfiguredTargetValue and their direct dependencies, and {@link
 * AspectCollection} represents an aspect-related part of this information.
 *
 * <p>Analysis arrives to a particular node in target graph with an ordered list of aspects that
 * need to be applied. Some of those aspects should visible to the node in question; some of them
 * are not directly visible, but are visible to other aspects, as specified by {@link
 * com.google.devtools.build.lib.packages.AspectDefinition#getRequiredProvidersForAspects()}.
 *
 * <p>As an example, of all these things in interplay, consider android_binary rule depending on
 * java_proto_library rule depending on proto_library rule; consider further that we analyze the
 * android_binary with some ide_info aspect:
 *
 * <pre>
 *    proto_library(name = "pl") + ide_info_aspect
 *       ^
 *       | [java_proto_aspect]
 *    java_proto_library(name = "jpl") + ide_info_aspect
 *       ^
 *       | [DexArchiveAspect]
 *    android_binary(name = "ab") + ide_info_aspect
 * </pre>
 *
 * ide_info_aspect is interested in java_proto_aspect, but not in DexArchiveAspect.
 *
 * <p>Let's look is the {@link AspectCollection} for a Dependency representing a jpl->pl edge for
 * ide_info_aspect application to target <code>jpl</code>:
 *
 * <ul>
 *   <li>the full list of aspects is [java_proto_aspect, DexArchiveAspect, ide_info_aspect] in this
 *       order (the order is determined by the order in which aspects originate on {@code
 *       ab->...->pl} path).
 *   <li>however, DexArchiveAspect is not visible to either ide_info_aspect or java_proto_aspect, so
 *       the reduced list(and a result of {@link #getUsedAspects()} ) will be [java_proto_aspect,
 *       ide_info_aspect]
 *   <li>both java_proto_aspect and ide_info_aspect will be visible to <code>jpl + ide_info_aspect
 *       </code> node: the former because java_proto_library originates java_proto_aspect, and the
 *       aspect applied to the node sees the same dependencies; and the latter because the aspect
 *       sees itself on all targets it propagates to. So {@link #getUsedAspects()} will return both
 *       of them.
 *   <li>Since ide_info_aspect declared its interest in java_proto_aspect and the latter comes
 *       before it in the order, {@link AspectDeps} for ide_info_aspect will contain
 *       java_proto_aspect (so the application of ide_info_aspect to <code>pl</code> target will see
 *       java_proto_aspect as well).
 * </ul>
 *
 * More details on members of {@link AspectCollection} follow, as well as more examples of aspect
 * visibility rules.
 *
 * <p>{@link AspectDeps} is a class that represents an aspect and all aspects that are directly
 * visible to it.
 *
 * <p>{@link #getUsedAspects()} return all aspects that should be applied to the target, in
 * topological order.
 *
 * <p>In the following scenario, consider rule r<sub>i</sub> sending an aspect a<sub>i</sub> to its
 * dependency:
 *
 * <pre>
 *      [r0]
 *       ^
 *  (a1) |
 *      [r1]
 *  (a2) |
 *      [r2]
 *  (a3) |
 *      [r3]
 * </pre>
 *
 * When a3 is propagated to target r0, the analysis arrives there with a path [a1, a2, a3]. Since we
 * analyse the propagation of aspect a3, the only visible aspect is a3.
 *
 * <p>Let's first assume that aspect a3 wants to see aspects a1 and a2, but aspects a1 and a2 are
 * not interested in each other (according to their {@link
 * com.google.devtools.build.lib.packages.AspectDefinition#getRequiredProvidersForAspects()}).
 *
 * <p>Since a3 is interested in all aspects, the result of {@link #getUsedAspects()} will be [a1,
 * a2, a3], and {@link AspectCollection} will be:
 *
 * <ul>
 *   <li>a3 -> [a1, a2]
 *   <li>a2 -> []
 *   <li>a1 -> []
 * </ul>
 *
 * <p>Now what happens if a3 is interested in a2 but not a1, and a2 is interested in a1? Again, all
 * aspects are transitively interesting to a visible a3, so {@link #getUsedAspects()} will be [a1,
 * a2, a3], but {@link AspectCollection} will now be:
 *
 * <ul>
 *   <li>a3 -> [a2]
 *   <li>a2 -> [a1]
 *   <li>a1 -> []
 * </ul>
 *
 * <p>As a final example, what happens if a3 is interested in a1, and a1 is interested in a2, but a3
 * is not interested in a2? Now the result of {@link #getUsedAspects()} will be [a1, a3]. a1 is
 * interested in a2, but a2 comes later in the path than a1, so a1 does not see it (a1 only started
 * propagating on r1 -> r0 edge, and there is now a2 originating on that path). And {@link
 * AspectCollection} will now be:
 *
 * <ul>
 *   <li>a3 -> [a1]
 *   <li>a1 -> []
 * </ul>
 *
 * Note that is does not matter if a2 is interested in a1 or not - since no one after it in the path
 * is interested in it, a2 is filtered out.
 */
@Immutable
public final class AspectCollection {
  /** aspects that should be visible to a dependency */
  private final ImmutableSet<AspectDeps> usedAspects;

  public static final AspectCollection EMPTY = new AspectCollection(ImmutableSet.<AspectDeps>of());

  private AspectCollection(ImmutableSet<AspectDeps> usedAspects) {
    this.usedAspects = usedAspects;
  }

  public ImmutableSet<AspectDeps> getUsedAspects() {
    return usedAspects;
  }

  public boolean isEmpty() {
    return usedAspects.isEmpty();
  }

  @Override
  public String toString() {
    return "AspectCollection{" + usedAspects + "}";
  }

  @Override
  public int hashCode() {
    return usedAspects.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof AspectCollection)) {
      return false;
    }
    AspectCollection that = (AspectCollection) obj;
    return this.usedAspects.equals(that.usedAspects);
  }

  /**
   * Represents an aspect with all the aspects it depends on (within an {@link AspectCollection}.
   *
   * <p>We preserve the order of aspects to correspond to the order originally specified in the call
   * to {@link AspectCollection#create}, although that is not strictly needed semantically.
   *
   * <p>This data structure cannot be a simple list. Consider the case when four aspects [a1, a2,
   * a3, a4] are attached and a4 is interested in a3, a3 in a2 and a2 in a1.
   *
   * <p>In this case, when analyzing a3, only a2 will be in its direct dependencies (since we don't
   * want to merge in the dependencies of a1), but then a2 would have no way of knowing that a1 was
   * also propagated.
   *
   * <p>(a list of (dependent aspect, visible) pairs would work, though and the code would probably
   * be somewhat simpler)
   */
  @AutoValue
  public abstract static class AspectDeps {
    public abstract AspectDescriptor getAspect();

    public abstract ImmutableList<AspectDeps> getUsedAspects();

    private static AspectDeps create(
        AspectDescriptor aspect, ImmutableList<AspectDeps> usedAspects) {
      return new AutoValue_AspectCollection_AspectDeps(aspect, usedAspects);
    }
  }

  public static AspectCollection createForTests(AspectDescriptor... descriptors) {
    return createForTests(ImmutableSet.copyOf(descriptors));
  }

  public static AspectCollection createForTests(ImmutableSet<AspectDescriptor> descriptors) {
    ImmutableSet.Builder<AspectDeps> depsBuilder = ImmutableSet.builder();
    for (AspectDescriptor descriptor : descriptors) {
      depsBuilder.add(AspectDeps.create(descriptor, ImmutableList.<AspectDeps>of()));
    }
    return new AspectCollection(depsBuilder.build());
  }

  /**
   * Creates an {@link AspectCollection} from an ordered list of aspects and a set of visible
   * aspects.
   *
   * <p>The order of aspects is reverse to the order in which they originated, with the earliest
   * originating occurring last in the list.
   */
  public static AspectCollection create(Iterable<Aspect> aspectPath)
      throws AspectCycleOnPathException {
    LinkedHashMap<AspectDescriptor, Aspect> aspectMap = deduplicateAspects(aspectPath);
    LinkedHashMap<AspectDescriptor, ArrayList<AspectDescriptor>> deps =
        new LinkedHashMap<>();

    // Calculate all needed aspects. Already discovered aspects are in key set of deps.
    // 1) Start from the end of the path. The aspect only sees other aspects that are
    //    before it
    // 2) Otherwise, check whether 'aspect' is visible to or required by any already seen aspects.
    // If it is visible to 'depAspect' or explicitly required by it, add the 'aspect' to a list of
    // aspects visible to 'depAspect'.
    // At the end of this algorithm, key set of 'deps' contains the original aspect list in reverse
    // (since we iterate the original list in reverse).
    //
    // deps[aspect] contains all aspects that 'aspect' needs, in reverse order.
    for (Map.Entry<AspectDescriptor, Aspect> aspect :
        ImmutableList.copyOf(aspectMap.entrySet()).reverse()) {
      for (AspectDescriptor depAspectDescriptor : deps.keySet()) {
        Aspect depAspect = aspectMap.get(depAspectDescriptor);
        if (depAspect
                .getDefinition()
                .getRequiredProvidersForAspects()
                .isSatisfiedBy(aspect.getValue().getDefinition().getAdvertisedProviders())
            || depAspect.getDefinition().requires(aspect.getValue())) {
          deps.get(depAspectDescriptor).add(aspect.getKey());
        }
      }

      deps.put(aspect.getKey(), new ArrayList<>());
    }

    // Calculate the path for every directly required aspect
    HashMap<AspectDescriptor, AspectDeps> aspectPaths = new HashMap<>();
    ImmutableSet.Builder<AspectDeps> result = ImmutableSet.builder();
    for (AspectDescriptor aspect : aspectMap.keySet()) {
      result.add(buildAspectDeps(aspect, aspectPaths, deps));
    }
    return new AspectCollection(result.build());
  }

  /**
   * Deduplicate aspects in path.
   *
   * @throws AspectCycleOnPathException if an aspect occurs twice on the path and
   *         the second occurrence sees a different set of aspects.
   */
  private static LinkedHashMap<AspectDescriptor, Aspect> deduplicateAspects(
      Iterable<Aspect> aspectPath) throws AspectCycleOnPathException {

    LinkedHashMap<AspectDescriptor, Aspect> aspectMap = new LinkedHashMap<>();
    ArrayList<Aspect> seenAspects = new ArrayList<>();
    for (Aspect aspect : aspectPath) {
      if (!aspectMap.containsKey(aspect.getDescriptor())) {
        aspectMap.put(aspect.getDescriptor(), aspect);
        seenAspects.add(aspect);
      } else {
        validateDuplicateAspect(aspect, seenAspects);
      }
    }
    return aspectMap;
  }

  /**
   * Detect inconsistent duplicate occurrence of an aspect on the path. There is a previous
   * occurrence of {@code aspect} in {@code seenAspects}.
   *
   * <p>If in between that previous occurrence and the newly discovered occurrence there is an
   * aspect that is visible to or required by {@code aspect}, then the second occurrence is
   * inconsistent - the set of aspects it sees is different from the first one.
   */
  private static void validateDuplicateAspect(Aspect aspect, ArrayList<Aspect> seenAspects)
      throws AspectCycleOnPathException {
    for (int i = seenAspects.size() - 1; i >= 0; i--) {
      Aspect seenAspect = seenAspects.get(i);
      if (aspect.getDescriptor().equals(seenAspect.getDescriptor())) {
        // This is a previous occurrence of the same aspect.
        return;
      }

      if (aspect
              .getDefinition()
              .getRequiredProvidersForAspects()
              .isSatisfiedBy(seenAspect.getDefinition().getAdvertisedProviders())
          || aspect.getDefinition().requires(seenAspect)) {
        throw new AspectCycleOnPathException(aspect.getDescriptor(), seenAspect.getDescriptor());
      }
    }
  }

  private static AspectDeps buildAspectDeps(AspectDescriptor descriptor,
      HashMap<AspectDescriptor, AspectDeps> aspectPaths,
      LinkedHashMap<AspectDescriptor, ArrayList<AspectDescriptor>> deps) {
    if (aspectPaths.containsKey(descriptor)) {
      return aspectPaths.get(descriptor);
    }

    ImmutableList.Builder<AspectDeps> aspectPathBuilder = ImmutableList.builder();
    ArrayList<AspectDescriptor> depList = deps.get(descriptor);

    // deps[aspect] contains all aspects visible to 'aspect' in reverse order.
    for (int i = depList.size() - 1; i >= 0; i--) {
      aspectPathBuilder.add(buildAspectDeps(depList.get(i), aspectPaths, deps));
    }
    AspectDeps aspectPath = AspectDeps.create(descriptor, aspectPathBuilder.build());
    aspectPaths.put(descriptor, aspectPath);
    return aspectPath;
  }

  /**
   * Signals an inconsistency on aspect path: an aspect occurs twice on the path and the second
   * occurrence sees a different set of aspects.
   *
   * <p>{@link #getAspect()} is the aspect occurring twice, and {@link #getPreviousAspect()} is the
   * aspect that the second occurrence sees but the first does not.
   */
  public static class AspectCycleOnPathException extends Exception {

    private final AspectDescriptor aspect;
    private final AspectDescriptor previousAspect;

    public AspectCycleOnPathException(AspectDescriptor aspect, AspectDescriptor previousAspect) {
      super(String.format("Aspect %s is applied twice, both before and after aspect %s",
          aspect.getDescription(), previousAspect.getDescription()
      ));
      this.aspect = aspect;
      this.previousAspect = previousAspect;
    }

    public AspectDescriptor getAspect() {
      return aspect;
    }

    public AspectDescriptor getPreviousAspect() {
      return previousAspect;
    }
  }
}
