// Copyright 2017-2020 The Verible Authors.
//
// 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.

#include "common/formatting/tree_unwrapper.h"

#include <algorithm>
#include <functional>
#include <iterator>
#include <memory>
#include <vector>

#include "common/formatting/format_token.h"
#include "common/formatting/token_partition_tree.h"
#include "common/formatting/unwrapped_line.h"
#include "common/text/concrete_syntax_tree.h"
#include "common/text/symbol.h"
#include "common/text/text_structure.h"
#include "common/text/token_info.h"
#include "common/text/token_stream_view.h"
#include "common/util/logging.h"
#include "common/util/value_saver.h"
#include "common/util/vector_tree.h"

namespace verible {

void TreeUnwrapper::VerifyFullTreeFormatTokenRanges() const {
  verible::VerifyFullTreeFormatTokenRanges(unwrapped_lines_,
                                           preformatted_tokens_.begin());
}

TreeUnwrapper::TreeUnwrapper(
    const TextStructureView& view,
    const preformatted_tokens_type& preformatted_tokens)
    : text_structure_view_(view),
      preformatted_tokens_(preformatted_tokens),
      next_unfiltered_token_(text_structure_view_.TokenStream().begin()),
      unwrapped_lines_(UnwrappedLine(current_indentation_spaces_,
                                     preformatted_tokens_.begin(),
                                     PartitionPolicyEnum::kAlwaysExpand)),
      // The "top-most" UnwrappedLine spans the entire file, so the first
      // unwrapped line should be a considered a partition (child) thereof.
      // This acts like 'pushing' the first child onto a stack.
      active_unwrapped_lines_(unwrapped_lines_.NewChild(UnwrappedLine(
          current_indentation_spaces_,
          unwrapped_lines_.Value().TokensRange().begin()
          // TODO(fangism): set partition policy here?
          ))) {
  // Every new unwrapped line will be initially empty, but the range
  // will point to the correct starting position in the preformatted_tokens_
  // array, and be able to 'extend' into the array of preformatted_tokens_.
}

const TokenPartitionTree* TreeUnwrapper::Unwrap() {
  // Collect tokens that appear before first syntax tree leaf, e.g. comments.
  CollectLeadingFilteredTokens();

  // Traverse the concrete syntax tree to build up token partitions.
  ABSL_DIE_IF_NULL(text_structure_view_.SyntaxTree())->Accept(this);

  // After traversing the ConcreteSyntaxTree, collect possible tokens filtered
  // after the right-most leaf until the end-of-file.
  CollectTrailingFilteredTokens();

  // No action needed to close out the most recent UnwrappedLine.
  if (!preformatted_tokens_.empty()) {
    const auto iter = CurrentFormatTokenIterator() - 1;
    const auto back = preformatted_tokens_.end() - 1;
    // Ensure that we have spanned the last significant token (used for
    // formatting).  It is possible that unfiltered tokens include trailing
    // newlines after the last leaf, which is why the iterators may not
    // necessarily line up exactly.
    CHECK(iter >= back) << "missing " << std::distance(iter, back)
                        << " format tokens at the end.  got: " << *iter->token
                        << " vs. " << *back->token;
  }

  {
    // This 'pops' the tree node stack once more to balance the initial
    // child 'push' that was done in the constructor's initialization
    // of active_unwrapped_lines_.
    active_unwrapped_lines_ = active_unwrapped_lines_->Parent();
    // Confirm that tree visitation is balanced.
    CHECK_EQ(active_unwrapped_lines_, &unwrapped_lines_);
    FinishUnwrappedLine();
  }

  VerifyFullTreeFormatTokenRanges();

  return &unwrapped_lines_;
}

std::vector<UnwrappedLine> TreeUnwrapper::FullyPartitionedUnwrappedLines()
    const {
  // If a node of the ExpandedTree<UnwrappedLine> has children,
  // visit only the node's children.
  std::vector<UnwrappedLine> result;
  unwrapped_lines_.ApplyPostOrder([&result](const TokenPartitionTree& node) {
    if (node.Children().empty()) {
      result.push_back(node.Value());
    }
  });

  // Filter out trailing blank UnwrappedLines.
  while (!result.empty() && result.back().IsEmpty()) {
    result.pop_back();
  }
  return result;
}

TokenSequence::const_iterator TreeUnwrapper::NextUnfilteredToken() const {
  const auto& origin_tokens = text_structure_view_.TokenStream();
  CHECK(next_unfiltered_token_ >= origin_tokens.begin());
  CHECK(next_unfiltered_token_ <= origin_tokens.end());
  return next_unfiltered_token_;
}

TreeUnwrapper::preformatted_tokens_type::const_iterator
TreeUnwrapper::CurrentFormatTokenIterator() const {
  // Caution to caller: this could return preformatted_tokens_.end()
  return CurrentUnwrappedLine().TokensRange().end();
}

UnwrappedLine& TreeUnwrapper::CurrentUnwrappedLine() {
  return ABSL_DIE_IF_NULL(CurrentTokenPartition())->Value();
}

const UnwrappedLine& TreeUnwrapper::CurrentUnwrappedLine() const {
  return ABSL_DIE_IF_NULL(CurrentTokenPartition())->Value();
}

void TreeUnwrapper::RemoveTrailingEmptyPartitions(TokenPartitionTree* node) {
  auto& children = node->Children();
  while (!children.empty() && children.back().Value().IsEmpty()) {
    children.pop_back();
  }
}

void TreeUnwrapper::CloseUnwrappedLineTreeNode(
    TokenPartitionTree* node,
    preformatted_tokens_type::const_iterator token_iter) {
  const auto& children = node->Children();
  if (!children.empty()) {
    const auto last_child_end = children.back().Value().TokensRange().end();
    CHECK(last_child_end >= token_iter)
        << "Child range should never have to catch up to parent.";
    if (token_iter < last_child_end) {
      // Parent needs to catch up to child.
      // This can occur because we're only updating one active_unwrapped_line_
      // node at a time, so this is needed to maintain the parent-child
      // range equivalence.
      node->Value().SpanUpToToken(last_child_end);
    }
  }
}

void TreeUnwrapper::FinishUnwrappedLine() {
  RemoveTrailingEmptyPartitions(active_unwrapped_lines_);

  const auto iter = CurrentFormatTokenIterator();
  CloseUnwrappedLineTreeNode(active_unwrapped_lines_, iter);

  // At this point, the current active_unwrapped_lines_ is finalized because
  // we are starting a new one.  Now is the right time to verify invariants.
  VerifyTreeNodeFormatTokenRanges(*active_unwrapped_lines_,
                                  preformatted_tokens_.begin());
}

void TreeUnwrapper::StartNewUnwrappedLine(PartitionPolicyEnum partitioning,
                                          const Symbol* origin) {
  // TODO(fangism): Take an optional indentation depth override parameter.
  auto& current_unwrapped_line = CurrentUnwrappedLine();
  if (current_unwrapped_line.IsEmpty()) {  // token range is empty
    // Re-use previously created unwrapped line.
    current_unwrapped_line.SetIndentationSpaces(current_indentation_spaces_);
    current_unwrapped_line.SetPartitionPolicy(partitioning);
    current_unwrapped_line.SetOrigin(origin);
    VLOG(4) << "re-using node at " << NodePath(*active_unwrapped_lines_) << ": "
            << current_unwrapped_line;
    // There may have been subtrees created with empty ranges, e.g.
    // for the sake of being able to correctly indent comments inside blocks.
    // If so, delete those so that token partition range invariants are
    // maintained through re-use of an existing node.
    if (!active_unwrapped_lines_->Children().empty()) {
      VLOG(4) << "removed pre-existing child partitions.";
      active_unwrapped_lines_->Children().clear();
    }
  } else {
    // To maintain the invariant that a parent range's upper-bound is equal
    // to the upper-bound of its last child, we may have to add one more
    // child whose range spans up to the parent's upper-bound.
    // The right time to do this is when an UnwrappedLine is finalized,
    // which is the same time that a new UnwrappedLine is added, here.
    FinishUnwrappedLine();

    // Create new sibling to current unwrapped line, maintaining same level.
    active_unwrapped_lines_ = active_unwrapped_lines_->NewSibling(
        UnwrappedLine(current_indentation_spaces_, CurrentFormatTokenIterator(),
                      partitioning));
    CurrentUnwrappedLine().SetOrigin(origin);
    VLOG(4) << "new sibling node " << NodePath(*active_unwrapped_lines_) << ": "
            << CurrentUnwrappedLine();
  }
}

void TreeUnwrapper::MergeLastTwoPartitions() {
  auto* parent =
      MergeLeafIntoPreviousLeaf(unwrapped_lines_.RightmostDescendant());
  if (parent != nullptr) {
    // Pre-existing partition no longer exists, update active_unwrapped_lines_
    // to point to a new empty partition at the current indentation level.
    const auto current_token_iter =
        unwrapped_lines_.RightmostDescendant()->Value().TokensRange().end();
    active_unwrapped_lines_ = parent->NewChild(UnwrappedLine(
        current_indentation_spaces_, current_token_iter
        // TODO(fangism): partitioning policy?
        // TODO(fangism): origin?
        ));
  }
}

void TreeUnwrapper::AddTokenToCurrentUnwrappedLine() {
  CHECK(NextUnfilteredTokenIsRetained());
  // Advance CurrentFormatTokenIterator().
  CurrentUnwrappedLine().SpanNextToken();
  VLOG(4) << "appended: " << *CurrentUnwrappedLine().TokensRange().back().token;
  ++next_unfiltered_token_;
}

bool TreeUnwrapper::NextUnfilteredTokenIsRetained() const {
  const auto iter = CurrentFormatTokenIterator();
  // (iter->token == &*next_unfiltered_token_) implies that is was one of the
  // tokens preserved in the subset array of filtered tokens, as determined
  // by a predication function (keeper), but without having to re-check
  // (and maintain a copy/reference of) the keeper predicate, nor perform
  // a set membership check (e.g. binary search).
  // This works only because we maintain that next_unfiltered_token_
  // will never lead nor lag CurrentFormatTokenIterator() by more than one
  // filtered token.
  return iter != preformatted_tokens_.end() &&  // possible if array is empty
         iter->token == &*next_unfiltered_token_;
}

void TreeUnwrapper::SkipUnfilteredTokens(
    std::function<bool(const verible::TokenInfo&)> predicate) {
  while (predicate(*next_unfiltered_token_)) {
    ++next_unfiltered_token_;
  }
}

// Advances next_unfiltered_token_ and also places the token into the
// CurrentUnwrappedLine() if it is a non-whitespace token, like a comment.
void TreeUnwrapper::AdvanceNextUnfilteredToken() {
  if (next_unfiltered_token_->isEOF()) return;
  if (NextUnfilteredTokenIsRetained()) {
    // This is a non-syntax-tree token, such as a comment or attribute.
    // Based on the KeepNonWhitespace predicate, next_unfiltered_token_
    // must point to the next PreFormatToken.
    // This already advances next_unfiltered_token_.
    AddTokenToCurrentUnwrappedLine();
  } else {
    // The inverse condition implies that the token pointed to was filtered
    // out, e.g. whitespace.
    ++next_unfiltered_token_;
  }
}

void TreeUnwrapper::TraverseChildren(const verible::SyntaxTreeNode& node) {
  // Can't just use TreeContextVisitor::Visit(node) because we need to
  // call a visit hook between children.
  const verible::SyntaxTreeContext::AutoPop p(&current_context_, &node);
  InterChildNodeHook(node);
  for (const auto& child : node.children()) {
    if (child) {
      child->Accept(this);
      InterChildNodeHook(node);
    }
  }
}

TreeUnwrapper::preformatted_tokens_type::const_iterator
TreeUnwrapper::VisitIndentedChildren(const SyntaxTreeNode& node,
                                     int indentation_delta,
                                     PartitionPolicyEnum partitioning) {
  // Visit subtree with increased indentation level.
  const ValueSaver<int> depth_saver(
      &current_indentation_spaces_,
      current_indentation_spaces_ + indentation_delta);

  // Mark a new sibling at the new indentation level, apply partition policy.
  StartNewUnwrappedLine(partitioning, &node);

  // Start first child right away.
  const ValueSaver<TokenPartitionTree*> tree_saver(
      &active_unwrapped_lines_,
      active_unwrapped_lines_->NewChild(UnwrappedLine(
          current_indentation_spaces_, CurrentFormatTokenIterator(),
          PartitionPolicyEnum::kFitOnLineElseExpand /* default */)));
  VLOG(3) << __FUNCTION__ << ", new child node "
          << NodePath(*active_unwrapped_lines_) << ": "
          << CurrentUnwrappedLine();
  TraverseChildren(node);

  return CurrentFormatTokenIterator();

  // To maintain the invariant that a parent range's upper-bound is equal
  // to the upper-bound of its last child, we may have to add one more
  // child whose range spans up to the parent's upper-bound.
  // The right time to do this is when an UnwrappedLine is finalized,
  // which is the same time that a new UnwrappedLine is added.
  // See StartNewUnwrappedLine().
}

void TreeUnwrapper::VisitIndentedSection(const SyntaxTreeNode& node,
                                         int indentation_delta,
                                         PartitionPolicyEnum partitioning) {
  const auto last_ftoken_iter =
      VisitIndentedChildren(node, indentation_delta, partitioning);

  // TODO(fangism): do we ever need to remove trailing empty partitions here?

  // Update parent's end() format token iterator to match that of
  // its last child.  It can still be advanced later.
  active_unwrapped_lines_->Value().SpanUpToToken(last_ftoken_iter);

  // Start new empty UnwrappedLine at the previous indentation level.
  StartNewUnwrappedLine(PartitionPolicyEnum::kUninitialized, nullptr);
}

std::ostream& operator<<(std::ostream& stream, const TreeUnwrapper& unwrapper) {
  for (const auto& uwline : unwrapper.FullyPartitionedUnwrappedLines()) {
    stream << uwline << std::endl;
  }
  return stream;
}

}  // namespace verible
