// 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.Entry;
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 (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.
   *
   * {@link #getAspect()} is the aspect occuring 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;
    }
  }
}
