/*
 * Copyright 2015 Google Inc.
 *
 * 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.googlejavaformat;

import static com.google.common.collect.Iterables.getLast;

import com.google.common.base.MoreObjects;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Iterators;
import com.google.common.collect.Range;
import com.google.googlejavaformat.Output.BreakTag;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * {@link com.google.googlejavaformat.java.JavaInputAstVisitor JavaInputAstVisitor} outputs a
 * sequence of {@link Op}s using {@link OpsBuilder}. This linear sequence is then transformed by
 * {@link DocBuilder} into a tree-structured {@code Doc}. The top-level {@code Doc} is a {@link
 * Level}, which contains a sequence of {@code Doc}s, including other {@link Level}s. Leaf {@code
 * Doc}s are {@link Token}s, representing language-level tokens; {@link Tok}s, which may also
 * represent non-token {@link Input.Tok}s, including comments and other white-space; {@link Space}s,
 * representing single spaces; and {@link Break}s, which represent optional line-breaks.
 */
public abstract class Doc {
  /**
   * Each {@link Break} in a {@link Level} is either {@link FillMode#UNIFIED} or {@link
   * FillMode#INDEPENDENT}.
   */
  public enum FillMode {
    /**
     * If a {@link Level} will not fit on one line, all of its {@code UNIFIED} {@link Break}s will
     * be broken.
     */
    UNIFIED,

    /**
     * If a {@link Level} will not fit on one line, its {@code INDEPENDENT} {@link Break}s will be
     * broken independently of each other, to fill in the {@link Level}.
     */
    INDEPENDENT,

    /**
     * A {@code FORCED} {@link Break} will always be broken, and a {@link Level} it appears in will
     * not fit on one line.
     */
    FORCED
  }

  /** State for writing. */
  public static final class State {
    final int lastIndent;
    final int indent;
    final int column;
    final boolean mustBreak;

    State(int lastIndent, int indent, int column, boolean mustBreak) {
      this.lastIndent = lastIndent;
      this.indent = indent;
      this.column = column;
      this.mustBreak = mustBreak;
    }

    public State(int indent0, int column0) {
      this(indent0, indent0, column0, false);
    }

    State withColumn(int column) {
      return new State(lastIndent, indent, column, mustBreak);
    }

    State withMustBreak(boolean mustBreak) {
      return new State(lastIndent, indent, column, mustBreak);
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this)
          .add("lastIndent", lastIndent)
          .add("indent", indent)
          .add("column", column)
          .add("mustBreak", mustBreak)
          .toString();
    }
  }

  private static final Range<Integer> EMPTY_RANGE = Range.closedOpen(-1, -1);
  private static final DiscreteDomain<Integer> INTEGERS = DiscreteDomain.integers();

  // Memoized width; Float.POSITIVE_INFINITY if contains forced breaks.
  private boolean widthComputed = false;
  private float width = 0.0F;

  // Memoized flat; not defined (and never computed) if contains forced breaks.
  private boolean flatComputed = false;
  private String flat = "";

  // Memoized Range.
  private boolean rangeComputed = false;
  private Range<Integer> range = EMPTY_RANGE;

  /**
   * Return the width of a {@code Doc}, or {@code Float.POSITIVE_INFINITY} if it must be broken.
   *
   * @return the width
   */
  final float getWidth() {
    if (!widthComputed) {
      width = computeWidth();
      widthComputed = true;
    }
    return width;
  }

  /**
   * Return a {@code Doc}'s flat-string value; not defined (and never called) if the (@code Doc}
   * contains forced breaks.
   *
   * @return the flat-string value
   */
  final String getFlat() {
    if (!flatComputed) {
      flat = computeFlat();
      flatComputed = true;
    }
    return flat;
  }

  /**
   * Return the {@link Range} of a {@code Doc}.
   *
   * @return the {@code Doc}'s {@link Range}
   */
  final Range<Integer> range() {
    if (!rangeComputed) {
      range = computeRange();
      rangeComputed = true;
    }
    return range;
  }

  /**
   * Compute the {@code Doc}'s width.
   *
   * @return the width, or {@code Float.POSITIVE_INFINITY} if it must be broken
   */
  abstract float computeWidth();

  /**
   * Compute the {@code Doc}'s flat value. Not defined (and never called) if contains forced breaks.
   *
   * @return the flat value
   */
  abstract String computeFlat();

  /**
   * Compute the {@code Doc}'s {@link Range} of {@link Input.Token}s.
   *
   * @return the {@link Range}
   */
  abstract Range<Integer> computeRange();

  /**
   * Make breaking decisions for a {@code Doc}.
   *
   * @param maxWidth the maximum line width
   * @param state the current output state
   * @return the new output state
   */
  public abstract State computeBreaks(CommentsHelper commentsHelper, int maxWidth, State state);

  /** Write a {@code Doc} to an {@link Output}, after breaking decisions have been made. */
  public abstract void write(Output output);

  /** A {@code Level} inside a {@link Doc}. */
  static final class Level extends Doc {
    private final Indent plusIndent; // The extra indent following breaks.
    private final List<Doc> docs = new ArrayList<>(); // The elements of the level.

    private Level(Indent plusIndent) {
      this.plusIndent = plusIndent;
    }

    /**
     * Factory method for {@code Level}s.
     *
     * @param plusIndent the extra indent inside the {@code Level}
     * @return the new {@code Level}
     */
    static Level make(Indent plusIndent) {
      return new Level(plusIndent);
    }

    /**
     * Add a {@link Doc} to the {@code Level}.
     *
     * @param doc the {@link Doc} to add
     */
    void add(Doc doc) {
      docs.add(doc);
    }

    @Override
    float computeWidth() {
      float thisWidth = 0.0F;
      for (Doc doc : docs) {
        thisWidth += doc.getWidth();
      }
      return thisWidth;
    }

    @Override
    String computeFlat() {
      StringBuilder builder = new StringBuilder();
      for (Doc doc : docs) {
        builder.append(doc.getFlat());
      }
      return builder.toString();
    }

    @Override
    Range<Integer> computeRange() {
      Range<Integer> docRange = EMPTY_RANGE;
      for (Doc doc : docs) {
        docRange = union(docRange, doc.range());
      }
      return docRange;
    }

    // State that needs to be preserved between calculating breaks and
    // writing output.
    // TODO(cushon): represent phases as separate immutable data.

    /** True if the entire {@link Level} fits on one line. */
    boolean oneLine = false;

    /**
     * Groups of {@link Doc}s that are children of the current {@link Level}, separated by {@link
     * Break}s.
     */
    List<List<Doc>> splits = new ArrayList<>();

    /** {@link Break}s between {@link Doc}s in the current {@link Level}. */
    List<Break> breaks = new ArrayList<>();

    @Override
    public State computeBreaks(CommentsHelper commentsHelper, int maxWidth, State state) {
      float thisWidth = getWidth();
      if (state.column + thisWidth <= maxWidth) {
        oneLine = true;
        return state.withColumn(state.column + (int) thisWidth);
      }
      State broken =
          computeBroken(
              commentsHelper, maxWidth, new State(state.indent + plusIndent.eval(), state.column));
      return state.withColumn(broken.column);
    }

    private static void splitByBreaks(List<Doc> docs, List<List<Doc>> splits, List<Break> breaks) {
      splits.clear();
      breaks.clear();
      splits.add(new ArrayList<>());
      for (Doc doc : docs) {
        if (doc instanceof Break) {
          breaks.add((Break) doc);
          splits.add(new ArrayList<>());
        } else {
          getLast(splits).add(doc);
        }
      }
    }

    /** Compute breaks for a {@link Level} that spans multiple lines. */
    private State computeBroken(CommentsHelper commentsHelper, int maxWidth, State state) {
      splitByBreaks(docs, splits, breaks);

      state =
          computeBreakAndSplit(
              commentsHelper, maxWidth, state, /* optBreakDoc= */ Optional.empty(), splits.get(0));

      // Handle following breaks and split.
      for (int i = 0; i < breaks.size(); i++) {
        state =
            computeBreakAndSplit(
                commentsHelper, maxWidth, state, Optional.of(breaks.get(i)), splits.get(i + 1));
      }
      return state;
    }

    /** Lay out a Break-separated group of Docs in the current Level. */
    private static State computeBreakAndSplit(
        CommentsHelper commentsHelper,
        int maxWidth,
        State state,
        Optional<Break> optBreakDoc,
        List<Doc> split) {
      float breakWidth = optBreakDoc.isPresent() ? optBreakDoc.get().getWidth() : 0.0F;
      float splitWidth = getWidth(split);
      boolean shouldBreak =
          (optBreakDoc.isPresent() && optBreakDoc.get().fillMode == FillMode.UNIFIED)
              || state.mustBreak
              || state.column + breakWidth + splitWidth > maxWidth;

      if (optBreakDoc.isPresent()) {
        state = optBreakDoc.get().computeBreaks(state, state.lastIndent, shouldBreak);
      }
      boolean enoughRoom = state.column + splitWidth <= maxWidth;
      state = computeSplit(commentsHelper, maxWidth, split, state.withMustBreak(false));
      if (!enoughRoom) {
        state = state.withMustBreak(true); // Break after, too.
      }
      return state;
    }

    private static State computeSplit(
        CommentsHelper commentsHelper, int maxWidth, List<Doc> docs, State state) {
      for (Doc doc : docs) {
        state = doc.computeBreaks(commentsHelper, maxWidth, state);
      }
      return state;
    }

    @Override
    public void write(Output output) {
      if (oneLine) {
        output.append(getFlat(), range()); // This is defined because width is finite.
      } else {
        writeFilled(output);
      }
    }

    private void writeFilled(Output output) {
      // Handle first split.
      for (Doc doc : splits.get(0)) {
        doc.write(output);
      }
      // Handle following breaks and split.
      for (int i = 0; i < breaks.size(); i++) {
        breaks.get(i).write(output);
        for (Doc doc : splits.get(i + 1)) {
          doc.write(output);
        }
      }
    }

    /**
     * Get the width of a sequence of {@link Doc}s.
     *
     * @param docs the {@link Doc}s
     * @return the width, or {@code Float.POSITIVE_INFINITY} if any {@link Doc} must be broken
     */
    static float getWidth(List<Doc> docs) {
      float width = 0.0F;
      for (Doc doc : docs) {
        width += doc.getWidth();
      }
      return width;
    }

    private static Range<Integer> union(Range<Integer> x, Range<Integer> y) {
      return x.isEmpty() ? y : y.isEmpty() ? x : x.span(y).canonical(INTEGERS);
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this)
          .add("plusIndent", plusIndent)
          .add("docs", docs)
          .toString();
    }
  }

  /** A leaf {@link Doc} for a token. */
  public static final class Token extends Doc implements Op {
    /** Is a Token a real token, or imaginary (e.g., a token generated incorrectly, or an EOF)? */
    public enum RealOrImaginary {
      REAL,
      IMAGINARY;

      boolean isReal() {
        return this == REAL;
      }
    }

    private final Input.Token token;
    private final RealOrImaginary realOrImaginary;
    private final Indent plusIndentCommentsBefore;
    private final Optional<Indent> breakAndIndentTrailingComment;

    private Token(
        Input.Token token,
        RealOrImaginary realOrImaginary,
        Indent plusIndentCommentsBefore,
        Optional<Indent> breakAndIndentTrailingComment) {
      this.token = token;
      this.realOrImaginary = realOrImaginary;
      this.plusIndentCommentsBefore = plusIndentCommentsBefore;
      this.breakAndIndentTrailingComment = breakAndIndentTrailingComment;
    }

    /**
     * How much extra to indent comments before the {@code Token}.
     *
     * @return the extra indent
     */
    Indent getPlusIndentCommentsBefore() {
      return plusIndentCommentsBefore;
    }

    /** Force a line break and indent trailing javadoc or block comments. */
    Optional<Indent> breakAndIndentTrailingComment() {
      return breakAndIndentTrailingComment;
    }

    /**
     * Make a {@code Token}.
     *
     * @param token the {@link Input.Token} to wrap
     * @param realOrImaginary did this {@link Input.Token} appear in the input, or was it generated
     *     incorrectly?
     * @param plusIndentCommentsBefore extra {@code plusIndent} for comments just before this token
     * @return the new {@code Token}
     */
    static Op make(
        Input.Token token,
        Doc.Token.RealOrImaginary realOrImaginary,
        Indent plusIndentCommentsBefore,
        Optional<Indent> breakAndIndentTrailingComment) {
      return new Token(
          token, realOrImaginary, plusIndentCommentsBefore, breakAndIndentTrailingComment);
    }

    /**
     * Return the wrapped {@link Input.Token}.
     *
     * @return the {@link Input.Token}
     */
    Input.Token getToken() {
      return token;
    }

    /**
     * Is the token good? That is, does it match an {@link Input.Token}?
     *
     * @return whether the @code Token} is good
     */
    RealOrImaginary realOrImaginary() {
      return realOrImaginary;
    }

    @Override
    public void add(DocBuilder builder) {
      builder.add(this);
    }

    @Override
    float computeWidth() {
      return token.getTok().length();
    }

    @Override
    String computeFlat() {
      return token.getTok().getOriginalText();
    }

    @Override
    Range<Integer> computeRange() {
      return Range.singleton(token.getTok().getIndex()).canonical(INTEGERS);
    }

    @Override
    public State computeBreaks(CommentsHelper commentsHelper, int maxWidth, State state) {
      String text = token.getTok().getOriginalText();
      return state.withColumn(state.column + text.length());
    }

    @Override
    public void write(Output output) {
      String text = token.getTok().getOriginalText();
      output.append(text, range());
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this)
          .add("token", token)
          .add("realOrImaginary", realOrImaginary)
          .add("plusIndentCommentsBefore", plusIndentCommentsBefore)
          .toString();
    }
  }

  /** A Leaf node in a {@link Doc} for a non-breaking space. */
  static final class Space extends Doc implements Op {
    private static final Space SPACE = new Space();

    private Space() {}

    /**
     * Factor method for {@code Space}.
     *
     * @return the new {@code Space}
     */
    static Space make() {
      return SPACE;
    }

    @Override
    public void add(DocBuilder builder) {
      builder.add(this);
    }

    @Override
    float computeWidth() {
      return 1.0F;
    }

    @Override
    String computeFlat() {
      return " ";
    }

    @Override
    Range<Integer> computeRange() {
      return EMPTY_RANGE;
    }

    @Override
    public State computeBreaks(CommentsHelper commentsHelper, int maxWidth, State state) {
      return state.withColumn(state.column + 1);
    }

    @Override
    public void write(Output output) {
      output.append(" ", range());
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this).toString();
    }
  }

  /** A leaf node in a {@link Doc} for an optional break. */
  public static final class Break extends Doc implements Op {
    private final FillMode fillMode;
    private final String flat;
    private final Indent plusIndent;
    private final Optional<BreakTag> optTag;

    private Break(FillMode fillMode, String flat, Indent plusIndent, Optional<BreakTag> optTag) {
      this.fillMode = fillMode;
      this.flat = flat;
      this.plusIndent = plusIndent;
      this.optTag = optTag;
    }

    /**
     * Make a {@code Break}.
     *
     * @param fillMode the {@link FillMode}
     * @param flat the text when not broken
     * @param plusIndent extra indent if taken
     * @return the new {@code Break}
     */
    public static Break make(FillMode fillMode, String flat, Indent plusIndent) {
      return new Break(fillMode, flat, plusIndent, /* optTag= */ Optional.empty());
    }

    /**
     * Make a {@code Break}.
     *
     * @param fillMode the {@link FillMode}
     * @param flat the text when not broken
     * @param plusIndent extra indent if taken
     * @param optTag an optional tag for remembering whether the break was taken
     * @return the new {@code Break}
     */
    public static Break make(
        FillMode fillMode, String flat, Indent plusIndent, Optional<BreakTag> optTag) {
      return new Break(fillMode, flat, plusIndent, optTag);
    }

    /**
     * Make a forced {@code Break}.
     *
     * @return the new forced {@code Break}
     */
    public static Break makeForced() {
      return make(FillMode.FORCED, "", Indent.Const.ZERO);
    }

    /**
     * Return the {@code Break}'s extra indent.
     *
     * @return the extra indent
     */
    int getPlusIndent() {
      return plusIndent.eval();
    }

    /**
     * Is the {@code Break} forced?
     *
     * @return whether the {@code Break} is forced
     */
    boolean isForced() {
      return fillMode == FillMode.FORCED;
    }

    @Override
    public void add(DocBuilder builder) {
      builder.breakDoc(this);
    }

    @Override
    float computeWidth() {
      return isForced() ? Float.POSITIVE_INFINITY : (float) flat.length();
    }

    @Override
    String computeFlat() {
      return flat;
    }

    @Override
    Range<Integer> computeRange() {
      return EMPTY_RANGE;
    }

    /** Was this break taken? */
    boolean broken;

    /** New indent after this break. */
    int newIndent;

    public State computeBreaks(State state, int lastIndent, boolean broken) {
      if (optTag.isPresent()) {
        optTag.get().recordBroken(broken);
      }

      if (broken) {
        this.broken = true;
        this.newIndent = Math.max(lastIndent + plusIndent.eval(), 0);
        return state.withColumn(newIndent);
      } else {
        this.broken = false;
        this.newIndent = -1;
        return state.withColumn(state.column + flat.length());
      }
    }

    @Override
    public State computeBreaks(CommentsHelper commentsHelper, int maxWidth, State state) {
      // Updating the state for {@link Break}s requires deciding if the break
      // should be taken.
      // TODO(cushon): this hierarchy is wrong, create a separate interface
      // for unbreakable Docs?
      throw new UnsupportedOperationException("Did you mean computeBreaks(State, int, boolean)?");
    }

    @Override
    public void write(Output output) {
      if (broken) {
        output.append("\n", EMPTY_RANGE);
        output.indent(newIndent);
      } else {
        output.append(flat, range());
      }
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this)
          .add("fillMode", fillMode)
          .add("flat", flat)
          .add("plusIndent", plusIndent)
          .add("optTag", optTag)
          .toString();
    }
  }

  /** A leaf node in a {@link Doc} for a non-token. */
  static final class Tok extends Doc implements Op {
    private final Input.Tok tok;

    private Tok(Input.Tok tok) {
      this.tok = tok;
    }

    /**
     * Factory method for a {@code Tok}.
     *
     * @param tok the {@link Input.Tok} to wrap
     * @return the new {@code Tok}
     */
    static Tok make(Input.Tok tok) {
      return new Tok(tok);
    }

    @Override
    public void add(DocBuilder builder) {
      builder.add(this);
    }

    @Override
    float computeWidth() {
      int idx = Newlines.firstBreak(tok.getOriginalText());
      // only count the first line of multi-line block comments
      if (tok.isComment()) {
        if (idx > 0) {
          return idx;
        } else if (tok.isSlashSlashComment() && !tok.getOriginalText().startsWith("// ")) {
          // Account for line comments with missing spaces, see computeFlat.
          return tok.length() + 1;
        } else {
          return tok.length();
        }
      }
      return idx != -1 ? Float.POSITIVE_INFINITY : (float) tok.length();
    }

    @Override
    String computeFlat() {
      // TODO(cushon): commentsHelper.rewrite doesn't get called for spans that fit in a single
      // line. That's fine for multi-line comment reflowing, but problematic for adding missing
      // spaces in line comments.
      if (tok.isSlashSlashComment() && !tok.getOriginalText().startsWith("// ")) {
        return "// " + tok.getOriginalText().substring("//".length());
      }
      return tok.getOriginalText();
    }

    @Override
    Range<Integer> computeRange() {
      return Range.singleton(tok.getIndex()).canonical(INTEGERS);
    }

    String text;

    @Override
    public State computeBreaks(CommentsHelper commentsHelper, int maxWidth, State state) {
      text = commentsHelper.rewrite(tok, maxWidth, state.column);
      int firstLineLength = text.length() - Iterators.getLast(Newlines.lineOffsetIterator(text));
      return state.withColumn(state.column + firstLineLength);
    }

    @Override
    public void write(Output output) {
      output.append(text, range());
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this).add("tok", tok).toString();
    }
  }
}
