// 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.common.base.Objects;
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.AspectDefinition;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * Represents aspects that should be applied to a target as part of {@link Dependency}.
 *
 * {@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.
 *
 * 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 AspectDefinition#getRequiredProvidersForAspects()}.
 *
 * 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.
 *
 * 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</code> path.
 *   </li>
 *   <li>however, DexArchiveAspect is not visible to either ide_info_aspect or java_proto_aspect,
 *        so the reduced list(and a result of {@link #getAllAspects()}) will be
 *        [java_proto_aspect, ide_info_aspect]
 *   </li>
 *   <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 #getVisibleAspects()} will return both of them.
 *   </li>
 *   <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).
 *   </li>
 * </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>
 *
 * <p>{@link #getVisibleAspects()} returns aspects that should be visible to the node in question.
 * </p>
 *
 * <p>{@link #getAllAspects()} return all aspects that should be applied to the target,
 * in topological order.</p>
 *
 * <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 AspectDefinition#getRequiredProvidersForAspects()}).
 *
 * Since a3 is interested in all aspects, the result of {@link #getAllAspects()} will be
 * [a1, a2, a3], and {@link AspectCollection} will be:
 * <ul>
 *   <li>a3 -> [a1, a2], a3 is visible</li>
 *   <li>a2 -> []</li>
 *   <li>a1 -> []</li>
 * </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 #getAllAspects()}
 * will be [a1, a2, a3], but {@link AspectCollection} will now be:
 * <ul>
 *   <li>a3 -> [a2], a3 is visible</li>
 *   <li>a2 -> [a1]</li>
 *   <li>a1 -> []</li>
 * </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 #getAllAspects()} 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], a3 is visible</li>
 *   <li>a1 -> []</li>
 * </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.
 * </p>
 */
@Immutable
public final class AspectCollection {
  /** all aspects in the path; transitively visible to {@link #visibleAspects} */
  private final ImmutableSet<AspectDescriptor> aspectPath;

  /** aspects that should be visible to a dependency */
  private final ImmutableSet<AspectDeps> visibleAspects;

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


  private AspectCollection(
      ImmutableSet<AspectDescriptor> allAspects,
      ImmutableSet<AspectDeps> visibleAspects) {
    this.aspectPath = allAspects;
    this.visibleAspects = visibleAspects;
  }

  public Iterable<AspectDescriptor> getAllAspects() {
    return aspectPath;
  }

  public ImmutableSet<AspectDeps> getVisibleAspects() {
    return visibleAspects;
  }

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

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

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof AspectCollection)) {
      return false;
    }
    AspectCollection that = (AspectCollection) obj;
    return Objects.equal(aspectPath, that.aspectPath);
  }


  /**
   * Represents an aspect with all the aspects it depends on
   * (within an {@link AspectCollection}.
   *
   * We preserve the order of aspects to correspond to the order in the
   * original {@link AspectCollection#aspectPath}, although that is not
   * strictly needed semantically.
   */
  @Immutable
  public static final class AspectDeps {
    private final AspectDescriptor aspect;
    private final ImmutableList<AspectDeps> dependentAspects;

    private AspectDeps(AspectDescriptor aspect,
        ImmutableList<AspectDeps> dependentAspects) {
      this.aspect = aspect;
      this.dependentAspects = dependentAspects;
    }

    public AspectDescriptor getAspect() {
      return aspect;
    }

    public ImmutableList<AspectDeps> getDependentAspects() {
      return dependentAspects;
    }
  }

  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(new AspectDeps(descriptor, ImmutableList.<AspectDeps>of()));
    }
    return new AspectCollection(descriptors, depsBuilder.build());
  }

  /**
   *  Creates an {@link AspectCollection} from an ordered list of aspects and
   *  a set of visible aspects.
   *
   *  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,
      Set<AspectDescriptor> visibleAspects) throws AspectCycleOnPathException {
    LinkedHashMap<AspectDescriptor, Aspect> aspectMap = deduplicateAspects(aspectPath);

    LinkedHashMap<AspectDescriptor, ArrayList<AspectDescriptor>> deps =
        new LinkedHashMap<>();

    // Calculate all needed aspects (either visible from outside or visible to
    // other needed aspects). Already discovered needed 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) If the 'aspect' is visible from outside, it is needed.
    // 3) Otherwise, check whether 'aspect' is visible to any already needed aspects,
    //    if it is visible to a needed 'depAspect',
    //            add the 'aspect' to a list of aspects visible to 'depAspect'.
    //    if 'aspect' is needed, add it to 'deps'.
    // At the end of this algorithm, key set of 'deps' contains a subset of original
    // aspect list consisting only of needed aspects, 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()) {
      boolean needed = visibleAspects.contains(aspect.getKey());
      for (AspectDescriptor depAspectDescriptor : deps.keySet()) {
        if (depAspectDescriptor.equals(aspect.getKey())) {
          continue;
        }
        Aspect depAspect = aspectMap.get(depAspectDescriptor);
        if (depAspect.getDefinition().getRequiredProvidersForAspects()
            .isSatisfiedBy(aspect.getValue().getDefinition().getAdvertisedProviders())) {
          deps.get(depAspectDescriptor).add(aspect.getKey());
          needed = true;
        }
      }
      if (needed && !deps.containsKey(aspect.getKey())) {
        deps.put(aspect.getKey(), new ArrayList<AspectDescriptor>());
      }
    }

    // Record only the needed aspects from all aspects, in correct order.
    ImmutableList<AspectDescriptor> neededAspects = ImmutableList.copyOf(deps.keySet()).reverse();

    // Calculate visible aspect paths.
    HashMap<AspectDescriptor, AspectDeps> aspectPaths = new HashMap<>();
    ImmutableSet.Builder<AspectDeps> visibleAspectPaths = ImmutableSet.builder();
    for (AspectDescriptor visibleAspect : visibleAspects) {
      visibleAspectPaths.add(buildAspectDeps(visibleAspect, aspectPaths, deps));
    }
    return new AspectCollection(ImmutableSet.copyOf(neededAspects),
        visibleAspectPaths.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}.
   *
   * If in between that previous occurrence and the newly discovered occurrence
   * there is an aspect that is visible to {@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())) {
        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 = new AspectDeps(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;
    }
  }
}
