// Copyright 2014 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.packages;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Location;

import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;

/**
 * Support for license and distribution checking.
 */
@Immutable @ThreadSafe
public final class License {

  private final Set<LicenseType> licenseTypes;
  private final Set<Label> exceptions;

  /**
   * The error that's thrown if a build file contains an invalid license string.
   */
  public static class LicenseParsingException extends Exception {
    public LicenseParsingException(String s) {
      super(s);
    }
  }

  /**
   * LicenseType is the basis of the License lattice - stricter licenses should
   * be declared before less-strict licenses in the enum.
   *
   * <p>Note that the order is important for the purposes of finding the least
   * restrictive license.
   */
  public enum LicenseType {
    BY_EXCEPTION_ONLY,
    RESTRICTED,
    RESTRICTED_IF_STATICALLY_LINKED,
    RECIPROCAL,
    NOTICE,
    PERMISSIVE,
    UNENCUMBERED,
    NONE
  }

  /**
   * Gets the least restrictive license type from the list of licenses declared
   * for a target. For the purposes of license checking, the license type set of
   * a declared license can be reduced to its least restrictive member.
   *
   * @param types a collection of license types
   * @return the least restrictive license type
   */
  @VisibleForTesting
  static LicenseType leastRestrictive(Collection<LicenseType> types) {
    return types.isEmpty() ? LicenseType.BY_EXCEPTION_ONLY : Collections.max(types);
  }

  /**
   * An instance of LicenseType.None with no exceptions, used for packages
   * outside of third_party which have no license clause in their BUILD files.
   */
  public static final License NO_LICENSE =
      new License(ImmutableSet.of(LicenseType.NONE), Collections.<Label>emptySet());

  /**
   * A default instance of Distributions which is used for packages which
   * have no "distribs" declaration. If nothing is declared, we opt for the
   * most permissive kind of distribution, which is the internal-only distrib.
   */
  public static final Set<DistributionType> DEFAULT_DISTRIB =
      Collections.singleton(DistributionType.INTERNAL);

  /**
   * The types of distribution that are supported.
   */
  public enum DistributionType {
    INTERNAL,
    WEB,
    CLIENT,
    EMBEDDED
  }

  /**
   * Parses a set of strings declaring distribution types.
   *
   * @param distStrings strings containing distribution declarations from BUILD
   *        files
   * @return a new, unmodifiable set of DistributionTypes
   * @throws LicenseParsingException
   */
  public static Set<DistributionType> parseDistributions(Collection<String> distStrings)
      throws LicenseParsingException {
    if (distStrings.isEmpty()) {
      return Collections.unmodifiableSet(EnumSet.of(DistributionType.INTERNAL));
    } else {
      Set<DistributionType> result = EnumSet.noneOf(DistributionType.class);
      for (String distStr : distStrings) {
        try {
          DistributionType dist = DistributionType.valueOf(distStr.toUpperCase());
          result.add(dist);
        } catch (IllegalArgumentException e) {
          throw new LicenseParsingException("Invalid distribution type '" + distStr + "'");
        }
      }
      return Collections.unmodifiableSet(result);
    }
  }

  private static final Object MARKER = new Object();

  /**
   * The license incompatibility set. This contains the set of
   * (Distribution,License) pairs that should generate errors.
   */
  private static Table<DistributionType, LicenseType, Object> LICENSE_INCOMPATIBILIES =
      createLicenseIncompatibilitySet();

  private static Table<DistributionType, LicenseType, Object> createLicenseIncompatibilitySet() {
    Table<DistributionType, LicenseType, Object> result = HashBasedTable.create();
    result.put(DistributionType.CLIENT, LicenseType.RESTRICTED, MARKER);
    result.put(DistributionType.EMBEDDED, LicenseType.RESTRICTED, MARKER);
    result.put(DistributionType.INTERNAL, LicenseType.BY_EXCEPTION_ONLY, MARKER);
    result.put(DistributionType.CLIENT, LicenseType.BY_EXCEPTION_ONLY, MARKER);
    result.put(DistributionType.WEB, LicenseType.BY_EXCEPTION_ONLY, MARKER);
    result.put(DistributionType.EMBEDDED, LicenseType.BY_EXCEPTION_ONLY, MARKER);
    return ImmutableTable.copyOf(result);
  }

  /**
   * The license warning set. This contains the set of
   * (Distribution,License) pairs that should generate warnings when the user
   * requests verbose license checking.
   */
  private static Table<DistributionType, LicenseType, Object> LICENSE_WARNINGS =
      createLicenseWarningsSet();

  private static Table<DistributionType, LicenseType, Object> createLicenseWarningsSet() {
    Table<DistributionType, LicenseType, Object> result = HashBasedTable.create();
    result.put(DistributionType.CLIENT, LicenseType.RECIPROCAL, MARKER);
    result.put(DistributionType.EMBEDDED, LicenseType.RECIPROCAL, MARKER);
    result.put(DistributionType.CLIENT, LicenseType.NOTICE, MARKER);
    result.put(DistributionType.EMBEDDED, LicenseType.NOTICE, MARKER);
    return ImmutableTable.copyOf(result);
  }

  private License(Set<LicenseType> licenseTypes, Set<Label> exceptions) {
    // Defensive copy is done in .of()
    this.licenseTypes = licenseTypes;
    this.exceptions = exceptions;
  }

  public static License of(Collection<LicenseType> licenses, Collection<Label> exceptions) {
    Set<LicenseType> licenseSet = ImmutableSet.copyOf(licenses);
    Set<Label> exceptionSet = ImmutableSet.copyOf(exceptions);

    if (exceptionSet.isEmpty() && licenseSet.equals(ImmutableSet.of(LicenseType.NONE))) {
      return License.NO_LICENSE;
    }

    return new License(licenseSet, exceptionSet);
  }
  /**
   * Computes a license which can be used to check if a package is compatible
   * with some kinds of distribution. The list of licenses is scanned for the
   * least restrictive, and the exceptions are added.
   *
   * @param licStrings the list of license strings declared for the package
   * @throws LicenseParsingException if there are any parsing problems
   */
  public static License parseLicense(List<String> licStrings) throws LicenseParsingException {
    /*
     * The semantics of comparison for licenses depends on a stable iteration
     * order for both license types and exceptions. For licenseTypes, it will be
     * the comparison order from the enumerated types; for exceptions, it will
     * be lexicographic order achieved using TreeSets.
     */
    Set<LicenseType> licenseTypes = EnumSet.noneOf(LicenseType.class);
    Set<Label> exceptions = Sets.newTreeSet();
    for (String str : licStrings) {
      if (str.startsWith("exception=")) {
        try {
          Label label = Label.parseAbsolute(str.substring("exception=".length()));
          exceptions.add(label);
        } catch (LabelSyntaxException e) {
          throw new LicenseParsingException(e.getMessage());
        }
      } else {
        try {
          licenseTypes.add(LicenseType.valueOf(str.toUpperCase()));
        } catch (IllegalArgumentException e) {
          throw new LicenseParsingException("invalid license type: '" + str + "'");
        }
      }
    }

    return License.of(licenseTypes, exceptions);
  }

  /**
   * Checks if this license is compatible with distributing a particular target
   * in some set of distribution modes.
   *
   * @param dists the modes of distribution
   * @param target the target which is being checked, and which will be used for
   *        checking exceptions
   * @param licensedTarget the target which declared the license being checked.
   * @param eventHandler a reporter where any licensing issues discovered should be
   *        reported
   * @param staticallyLinked whether the target is statically linked under this command
   * @return true if the license is compatible with the distributions
   */
  public boolean checkCompatibility(Set<DistributionType> dists,
      Target target, Label licensedTarget, EventHandler eventHandler,
      boolean staticallyLinked) {
    Location location = (target instanceof Rule) ? ((Rule) target).getLocation() : null;

    LicenseType leastRestrictiveLicense;
    if (licenseTypes.contains(LicenseType.RESTRICTED_IF_STATICALLY_LINKED)) {
      Set<LicenseType> tempLicenses = EnumSet.copyOf(licenseTypes);
      tempLicenses.remove(LicenseType.RESTRICTED_IF_STATICALLY_LINKED);
      if (staticallyLinked) {
        tempLicenses.add(LicenseType.RESTRICTED);
      } else {
        tempLicenses.add(LicenseType.UNENCUMBERED);
      }
      leastRestrictiveLicense = leastRestrictive(tempLicenses);
    } else {
      leastRestrictiveLicense = leastRestrictive(licenseTypes);
    }
    for (DistributionType dt : dists) {
      if (LICENSE_INCOMPATIBILIES.contains(dt, leastRestrictiveLicense)) {
        if (!exceptions.contains(target.getLabel())) {
          eventHandler.handle(Event.error(location, "Build target '" + target.getLabel()
              + "' is not compatible with license '" + this + "' from target '"
                  + licensedTarget + "'"));
          return false;
        }
      } else if (LICENSE_WARNINGS.contains(dt, leastRestrictiveLicense)) {
        eventHandler.handle(
            Event.warn(location, "Build target '" + target
                + "' has a potential licensing issue "
                + "with a '" + this + "' license from target '" + licensedTarget + "'"));
      }
    }
    return true;
  }

  /**
   * @return an immutable set of {@link LicenseType}s contained in this {@code
   *         License}
   */
  public Set<LicenseType> getLicenseTypes() {
    return licenseTypes;
  }

  /**
   * @return an immutable set of {@link Label}s that describe exceptions to the
   *         {@code License}
   */
  public Set<Label> getExceptions() {
    return exceptions;
  }

  /**
   * A simple toString implementation which generates a canonical form of the
   * license. (The order of license types is guaranteed to be canonical by
   * EnumSet, and the order of exceptions is guaranteed to be lexicographic
   * order by TreeSet.)
   */
  @Override
  public String toString() {
    if (exceptions.isEmpty()) {
      return licenseTypes.toString().toLowerCase();
    } else {
      return licenseTypes.toString().toLowerCase() + " with exceptions " + exceptions;
    }
  }

  /**
   * A simple equals implementation leveraging the support built into Set that
   * delegates to its contents.
   */
  @Override
  public boolean equals(Object o) {
    return o == this ||
        o instanceof License &&
        ((License) o).licenseTypes.equals(this.licenseTypes) &&
        ((License) o).exceptions.equals(this.exceptions);
  }

  /**
   * A simple hashCode implementation leveraging the support built into Set that
   * delegates to its contents.
   */
  @Override
  public int hashCode() {
    return licenseTypes.hashCode() * 43 + exceptions.hashCode();
  }
}
