// 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.query2.query.output;

import com.google.common.base.Ascii;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.LabelPrinter;
import com.google.devtools.build.lib.packages.License;
import com.google.devtools.build.lib.packages.RawAttributeMapper;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.packages.TriState;
import com.google.devtools.build.lib.query2.engine.OutputFormatterCallback;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment;
import com.google.devtools.build.lib.query2.engine.SynchronizedDelegatingOutputFormatterCallback;
import com.google.devtools.build.lib.query2.engine.ThreadSafeOutputFormatterCallback;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.BiPredicate;
import net.starlark.java.eval.Printer;
import net.starlark.java.eval.StarlarkThread;

/**
 * An output formatter that prints the generating rules using the syntax of the BUILD files. If
 * multiple targets are generated by the same rule, it is printed only once.
 */
public class BuildOutputFormatter extends AbstractUnorderedFormatter {

  /**
   * Generic interface for determining the possible values for a given attribute on a given rule, as
   * precisely as the implementation knows. For example, cquery knows which branch a <code>select
   * </code> takes, while query doesn't.
   */
  public interface AttributeReader {
    Iterable<Object> getPossibleValues(Rule rule, Attribute attr);
  }

  /**
   * Generic logic for formatting a target BUILD-style.
   *
   * <p>This logic is implementation-agnostic. So it can be shared across query, cquery, and other
   * implementations.
   */
  public static class TargetOutputter {
    private final Writer writer;
    private final BiPredicate<Rule, Attribute> preserveSelect;
    private final String lineTerm;
    private final LabelPrinter labelPrinter;
    private final Set<Label> printed = CompactHashSet.create();

    /**
     * @param writer where to write output
     * @param preserveSelect a predicate that determines if the given attribute on the given rule is
     *     a <code>select</code> that should be output as-is (without figuring out which branch it
     *     takes). This is useful for implementations that can't evaluate <code>select</code>.
     * @param lineTerm character to add to the end of each line
     */
    public TargetOutputter(
        Writer writer,
        BiPredicate<Rule, Attribute> preserveSelect,
        String lineTerm,
        LabelPrinter labelPrinter) {
      this.writer = writer;
      this.preserveSelect = preserveSelect;
      this.lineTerm = lineTerm;
      this.labelPrinter = labelPrinter;
    }

    /** Outputs a given target in BUILD-style syntax. */
    public void output(Target target, AttributeReader attrReader) throws IOException {
      Rule rule = target.getAssociatedRule();
      if (rule == null || printed.contains(rule.getLabel())) {
        return;
      }
      outputRule(rule, attrReader, writer);
      printed.add(rule.getLabel());
    }

    /** Outputs a given rule in BUILD-style syntax. Made visible for Modquery command. */
    public void outputRule(Rule rule, AttributeReader attrReader, Writer writer)
        throws IOException {
      // TODO(b/151151653): display the filenames in root-relative form.
      // This is an incompatible change, but Blaze users (and their editors)
      // must already be equipped to handle relative paths as all compiler
      // error messages are execroot-relative.

      writer.append("# ").append(rule.getLocation().toString()).append(lineTerm);
      writer.append(rule.getRuleClass()).append("(").append(lineTerm);
      writer.append("  name = \"").append(rule.getName()).append("\",").append(lineTerm);

      for (Attribute attr : rule.getAttributes()) {
        // Ignore the "name" attribute here, as we already print it above.
        // This is not strictly necessary, but convention has it that the
        // name attribute is printed first.
        if ("name".equals(attr.getName())) {
          continue;
        }
        if (preserveSelect.test(rule, attr)) {
          writer
              .append("  ")
              .append(attr.getPublicName())
              .append(" = ")
              .append(reconstructSelect(rule, attr))
              .append(",")
              .append(lineTerm);
          continue;
        }
        if (!rule.isAttributeValueExplicitlySpecified(attr)) {
          continue; // Don't print default values.
        }

        Iterable<Object> values = attrReader.getPossibleValues(rule, attr);
        if (Iterables.size(values) != 1) {
          // Computed defaults that depend on configurable attributes can have multiple values.
          continue;
        }
        writer
            .append("  ")
            .append(attr.getPublicName())
            .append(" = ")
            .append(outputRawAttrValue(Iterables.getOnlyElement(values)))
            .append(",")
            .append(lineTerm);
      }
      writer.append(")").append(lineTerm);

      // Display the instantiation stack, if any.
      appendStack(
          String.format("# Rule %s instantiated at (most recent call last):", rule.getName()),
          rule.reconstructCallStack());

      // Display the stack of the rule class definition, if any.
      appendStack(
          String.format("# Rule %s defined at (most recent call last):", rule.getRuleClass()),
          rule.getRuleClassObject().getCallStack());

      // TODO(adonovan): also list inputs and outputs of the rule.

      writer.append(lineTerm);
    }

    private void appendStack(String title, List<StarlarkThread.CallStackEntry> stack)
        throws IOException {
      // For readability, ensure columns line up.
      int maxLocLen = 0;
      for (StarlarkThread.CallStackEntry fr : stack) {
        maxLocLen = Math.max(maxLocLen, fr.location.toString().length());
      }
      if (maxLocLen > 0) {
        writer.append(title).append(lineTerm);
        for (StarlarkThread.CallStackEntry fr : stack) {
          String loc = fr.location.toString(); // TODO(b/151151653): display root-relative
          // Java's String.format doesn't support
          // right-padding with %*s, so we must loop.
          writer.append("#   ").append(loc);
          for (int i = loc.length(); i < maxLocLen; i++) {
            writer.append(' ');
          }
          writer.append(" in ").append(fr.name).append(lineTerm);
        }
      }
    }

    /** Outputs the given attribute value BUILD-style. Does not support selects. */
    private String outputRawAttrValue(Object value) {
      if (value instanceof License) {
        List<String> licenseTypes = new ArrayList<>();
        for (License.LicenseType licenseType : ((License) value).getLicenseTypes()) {
          licenseTypes.add(Ascii.toLowerCase(licenseType.toString()));
        }
        value = licenseTypes;
      } else if (value instanceof TriState) {
        value = ((TriState) value).toInt();
      }
      return new Printer() {
        // Print labels in their canonical form.
        @Override
        public Printer repr(Object o) {
          return super.repr(o instanceof Label ? labelPrinter.toString((Label) o) : o);
        }
      }.repr(value).toString();
    }

    /**
     * Outputs a <code>select</code> BUILD-style without trying to resolve which branch it takes.
     */
    private String reconstructSelect(Rule rule, Attribute attr) {
      List<String> selectors = new ArrayList<>();
      RawAttributeMapper attributeMap = RawAttributeMapper.of(rule);
      for (BuildType.Selector<?> selector :
          ((BuildType.SelectorList<?>) attributeMap.getRawAttributeValue(rule, attr))
              .getSelectors()) {
        if (selector.isUnconditional()) {
          selectors.add(outputRawAttrValue(Preconditions.checkNotNull(selector.getDefault())));
        } else {
          selectors.add(String.format("select(%s)", outputRawAttrValue(selector.mapCopy())));
        }
      }
      return String.join(" + ", selectors);
    }
  }

  /** Query's implementation. */
  @Override
  public OutputFormatterCallback<Target> createPostFactoStreamCallback(
      OutputStream out, final QueryOptions options, LabelPrinter labelPrinter) {
    return new BuildOutputFormatterCallback(out, options.getLineTerminator(), labelPrinter);
  }

  @Override
  public ThreadSafeOutputFormatterCallback<Target> createStreamCallback(
      OutputStream out, QueryOptions options, QueryEnvironment<?> env) {
    return new SynchronizedDelegatingOutputFormatterCallback<>(
        createPostFactoStreamCallback(out, options, env.getLabelPrinter()));
  }

  /** BuildOutputFormatter callback for Query. Made visible for ModQuery. */
  public static class BuildOutputFormatterCallback extends TextOutputFormatterCallback<Target> {
    private final TargetOutputter targetOutputter;

    BuildOutputFormatterCallback(OutputStream out, String lineTerm, LabelPrinter labelPrinter) {
      super(out);
      this.targetOutputter =
          new TargetOutputter(
              writer,
              (rule, attr) -> RawAttributeMapper.of(rule).isConfigurable(attr.getName()),
              lineTerm,
              labelPrinter);
    }

    @Override
    public void processOutput(Iterable<Target> partialResult) throws IOException {
      for (Target target : partialResult) {
        targetOutputter.output(
            target,
            // Multiple possible values are ignored by the outputter.
            (rule, attr) ->
                PossibleAttributeValues.forRuleAndAttribute(
                    rule, attr, /*mayTreatMultipleAsNone=*/ true));
      }
    }
  }

  @Override
  public String getName() {
    return "build";
  }
}
