// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <fstream>
#include <regex>

#include <fidl/linting_tree_callbacks.h>
#include <fidl/utils.h>

namespace fidl {
namespace linter {

LintingTreeCallbacks::LintingTreeCallbacks() {
  // Anonymous derived class; unique to the LintingTreeCallbacks
  class CallbackTreeVisitor : public fidl::raw::DeclarationOrderTreeVisitor {
   private:
    int gap_subre_count = 1;  // index 0 unused, since match starts with 1
    // Regex OR expression should try line comment first:
    const int kLineComment = gap_subre_count++;
    const int kIgnoredToken = gap_subre_count++;
    const int kWhiteSpace = gap_subre_count++;

   public:
    CallbackTreeVisitor(const LintingTreeCallbacks& callbacks)
        : callbacks_(callbacks), end_of_last_gap_(nullptr), end_of_last_token_(nullptr) {
      InitGapTextRegex();
    }

    void OnFile(std::unique_ptr<raw::File> const& element) override {
      for (auto& callback : callbacks_.file_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnFile(element);
      for (auto& callback : callbacks_.exit_file_callbacks_) {
        callback(*element.get());
      }
    }
    void OnSourceElementStart(const raw::SourceElement& element) override {
      ProcessGapText(element.start_);
      for (auto& callback : callbacks_.source_element_callbacks_) {
        callback(element);
      }
    }
    void OnSourceElementEnd(const raw::SourceElement& element) override {
      ProcessGapText(element.end_);
    }
    void OnAttribute(const raw::Attribute& element) override {
      for (auto& callback : callbacks_.attribute_callbacks_) {
        callback(element);
      }
    }
    void OnUsing(std::unique_ptr<raw::Using> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.using_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnUsing(element);
      ProcessGapText(element->end_);
    }
    void OnConstDeclaration(std::unique_ptr<raw::ConstDeclaration> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.const_declaration_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnConstDeclaration(element);
      for (auto& callback : callbacks_.exit_const_declaration_callbacks_) {
        callback(*element.get());
      }
      ProcessGapText(element->end_);
    }
    void OnBitsDeclaration(std::unique_ptr<raw::BitsDeclaration> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.bits_declaration_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnBitsDeclaration(element);
      for (auto& callback : callbacks_.exit_bits_declaration_callbacks_) {
        callback(*element.get());
      }
      ProcessGapText(element->end_);
    }
    void OnBitsMember(std::unique_ptr<raw::BitsMember> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.bits_member_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnBitsMember(element);
      ProcessGapText(element->end_);
    }
    void OnEnumMember(std::unique_ptr<raw::EnumMember> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.enum_member_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnEnumMember(element);
      ProcessGapText(element->end_);
    }
    void OnEnumDeclaration(std::unique_ptr<raw::EnumDeclaration> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.enum_declaration_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnEnumDeclaration(element);
      for (auto& callback : callbacks_.exit_enum_declaration_callbacks_) {
        callback(*element.get());
      }
      ProcessGapText(element->end_);
    }
    void OnProtocolDeclaration(std::unique_ptr<raw::ProtocolDeclaration> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.protocol_declaration_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnProtocolDeclaration(element);
      for (auto& callback : callbacks_.exit_protocol_declaration_callbacks_) {
        callback(*element.get());
      }
      ProcessGapText(element->end_);
    }
    void OnProtocolMethod(std::unique_ptr<raw::ProtocolMethod> const& element) override {
      ProcessGapText(element->start_);
      if (element->maybe_request != nullptr) {
        for (auto& callback : callbacks_.method_callbacks_) {
          callback(*element.get());
        }
      } else {
        for (auto& callback : callbacks_.event_callbacks_) {
          callback(*element.get());
        }
      }
      DeclarationOrderTreeVisitor::OnProtocolMethod(element);
      ProcessGapText(element->end_);
    }
    void OnParameter(std::unique_ptr<raw::Parameter> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.parameter_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnParameter(element);
      ProcessGapText(element->end_);
    }
    void OnStructMember(std::unique_ptr<raw::StructMember> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.struct_member_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnStructMember(element);
      ProcessGapText(element->end_);
    }
    void OnStructDeclaration(std::unique_ptr<raw::StructDeclaration> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.struct_declaration_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnStructDeclaration(element);
      for (auto& callback : callbacks_.exit_struct_declaration_callbacks_) {
        callback(*element.get());
      }
      ProcessGapText(element->end_);
    }
    void OnTableMember(std::unique_ptr<raw::TableMember> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.table_member_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnTableMember(element);
      ProcessGapText(element->end_);
    }
    void OnTableDeclaration(std::unique_ptr<raw::TableDeclaration> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.table_declaration_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnTableDeclaration(element);
      for (auto& callback : callbacks_.exit_table_declaration_callbacks_) {
        callback(*element.get());
      }
      ProcessGapText(element->end_);
    }
    void OnTypeConstructorOld(std::unique_ptr<raw::TypeConstructorOld> const& element) override {
      for (auto& callback : callbacks_.type_constructor_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnTypeConstructorOld(element);
    }
    void OnUnionMember(std::unique_ptr<raw::UnionMember> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.union_member_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnUnionMember(element);
      ProcessGapText(element->end_);
    }
    void OnUnionDeclaration(std::unique_ptr<raw::UnionDeclaration> const& element) override {
      ProcessGapText(element->start_);
      for (auto& callback : callbacks_.union_declaration_callbacks_) {
        callback(*element.get());
      }
      DeclarationOrderTreeVisitor::OnUnionDeclaration(element);
      for (auto& callback : callbacks_.exit_union_declaration_callbacks_) {
        callback(*element.get());
      }
      ProcessGapText(element->end_);
    }

   private:
    void InitGapTextRegex() {
      std::string subre[gap_subre_count];

      // Regex OR expression should try line comment first:
      subre[kLineComment] = R"REGEX(//(?:\S*[ \t]*\S+)*)REGEX";
      subre[kIgnoredToken] = R"REGEX(\S+)REGEX";
      subre[kWhiteSpace] = R"REGEX((?:[ \t]+\n?)|\n)REGEX";
      // white space spanning multiple lines will be split on the
      // newline, with the newline included.

      auto regex_str = "^(" + subre[kLineComment] + ")|(" + subre[kIgnoredToken] + ")|(" +
                       subre[kWhiteSpace] + ")";

      kGapTextRegex_ = std::regex(regex_str);
    }

    // "GapText" includes everything between source elements (or between a
    // source element and the beginning or the end of the file). This
    // includes whitespace, comments, and certain tokens not processed as
    // source elements, including colons, curly braces, square brackets,
    // parentheses, commas, and semicolons.
    //
    // Break up the gap text into the different types to pass to the
    // appropriate callbacks. Include the leading characters on the line
    // as an additional parameter, to give callbacks somne insight into
    // their line context. For example, is the whitespace preceeded by
    // a line comment (meaning it is not a blank line)? Is the line comment
    // preceeded by any non-whitespace characters (it is not a comment-
    // only line)?
    void OnGapText(std::string_view gap_view, const SourceFile& source_file,
                   std::string_view line_so_far_view) {
      auto remaining_gap_view = gap_view;
      auto remaining_line_so_far_view = line_so_far_view;
      std::string content = std::string(remaining_gap_view);
      std::smatch match;
      while (!content.empty()) {
        // The regex_search loop should consume the entire gap
        std::regex_search(content, match, kGapTextRegex_);
        assert(!match.empty() &&
               "gap content did not match any of the expected regular expressions");

        auto view = remaining_gap_view;
        view.remove_suffix(remaining_gap_view.size() - match[0].length());
        auto line_prefix_view = remaining_line_so_far_view;
        line_prefix_view.remove_suffix(remaining_gap_view.size());

        if (match[kLineComment].matched) {
          // TODO(fxbug.dev/7979): Remove FirstLineIsRegularComment() check
          // when no longer needed.
          // If there are multiple contiguous lines starting with the
          // doc comment marker ("///"), they will be merged (including
          // newlines, but with the 3 slashes stripped off) into a single
          // string, and generate an "Attribute" with |name| "Doc", and
          // |value| the multi-line string. BUT the span()
          // std::string_view for the Attribute SourceElement has ONLY the
          // first line. So when LintingTreeCallbacks processes the |gap_text|,
          // the first line is not part of the gap, but the remaining lines
          // show up as gap text comments.
          if (utils::FirstLineIsRegularComment(match[0].str())) {  // not Doc Comment
            auto line_comment = SourceSpan(view, source_file);
            for (auto& callback : callbacks_.line_comment_callbacks_) {
              // starts with the comment marker (2 slashes) and ends with
              // the last non-space character before the first newline
              callback(line_comment, line_prefix_view);
            }
          }
        } else if (match[kIgnoredToken].matched) {
          auto ignored_token = SourceSpan(view, source_file);
          for (auto& callback : callbacks_.ignored_token_callbacks_) {
            // includes (but may not be limited to): "as" : ; , { } [ ] ( )
            callback(ignored_token);
          }
        } else if (match[kWhiteSpace].matched) {
          auto white_space = SourceSpan(view, source_file);
          for (auto& callback : callbacks_.white_space_up_to_newline_callbacks_) {
            // All whitespace only (space, tab, newline)
            callback(white_space, line_prefix_view);
          }
        } else {
          assert(false && "Should never be reached. Bad regex?");
        }
        if (view.back() == '\n') {
          remaining_line_so_far_view.remove_prefix(
              (view.data() - remaining_line_so_far_view.data()) + view.size());
        }
        remaining_gap_view.remove_prefix(match[0].length());
        content = std::string(remaining_gap_view);
      }
    }

    void ProcessGapText(const fidl::Token& next_token) {
      const char* gap_start = next_token.previous_end().data().data();
      if (gap_start > end_of_last_gap_) {
        auto const& source_file = next_token.span().source_file();
        auto const& source_view = source_file.data();
        const char* source_start = source_view.data();
        const char* source_end = source_view.data() + source_view.size();

        if (gap_start > end_of_last_token_) {
          if (end_of_last_token_ == nullptr) {
            gap_start = source_start;
          } else {
            gap_start = end_of_last_token_;
          }
        }

        // The gap starts from the end of the last processed token and
        // ends with the beginning of the next token to be processed.
        // It is then broken down into either contigous whitespace,
        // a line comment (excluding trailing whitespace at the end of
        // the line), or other characters (also called "ignored tokens,"
        // which can include the word "as", and various puctuation.)
        auto next_view = next_token.data();
        const char* gap_end = next_view.data();
        auto gap_view = source_view;
        gap_view.remove_prefix(gap_start - source_start);
        gap_view.remove_suffix(source_end - gap_end);

        // Get a view of the gap PLUS characters prior to the gap up to the
        // beginning of the line. There may still be multiple lines in the
        // gap, but the first line in the gap will be a complete line.
        // (The last line in the gap is typically not the comnplete line,
        // unless the next token happens to start on column 1 of the next line.
        auto line_so_far_view = source_view;
        line_so_far_view.remove_suffix(source_end - gap_end);
        if (gap_start > source_start) {
          auto preceeding_newline =
              line_so_far_view.find_last_of('\n', gap_start - source_start - 1);
          if (preceeding_newline != std::string_view::npos) {
            line_so_far_view.remove_prefix(preceeding_newline + 1);
          }
        }

        OnGapText(gap_view, source_file, line_so_far_view);
        end_of_last_gap_ = gap_end;
        end_of_last_token_ = gap_end + next_view.size();
      }
    }

    const LintingTreeCallbacks& callbacks_;
    std::regex kGapTextRegex_;
    const char* end_of_last_gap_;
    const char* end_of_last_token_;
  };

  tree_visitor_ = std::make_unique<CallbackTreeVisitor>(*this);
}  // namespace linter

void LintingTreeCallbacks::Visit(std::unique_ptr<raw::File> const& element) {
  tree_visitor_->OnFile(element);
}

}  // namespace linter
}  // namespace fidl
