// Copyright 2021 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 "verilog/tools/ls/lsp-parse-buffer.h"

#include <cstdint>
#include <memory>
#include <ostream>
#include <string>
#include <utility>
#include <vector>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "common/analysis/lint_rule_status.h"
#include "common/lsp/lsp-file-utils.h"
#include "common/lsp/lsp-text-buffer.h"
#include "common/util/logging.h"
#include "verilog/analysis/verilog_analyzer.h"
#include "verilog/analysis/verilog_linter.h"
#include "verilog/analysis/verilog_linter_configuration.h"

namespace verilog {
static absl::StatusOr<std::vector<verible::LintRuleStatus>> RunLinter(
    absl::string_view filename, const verilog::VerilogAnalyzer &parser) {
  const auto &text_structure = parser.Data();

  verilog::LinterConfiguration config;
  const std::string file_path = verible::lsp::LSPUriToPath(filename);
  if (auto from_flags = LinterConfigurationFromFlags(file_path);
      from_flags.ok()) {
    config = *from_flags;
  } else {
    LOG(ERROR) << from_flags.status().message() << std::endl;
  }

  return VerilogLintTextStructure(filename, config, text_structure);
}

ParsedBuffer::ParsedBuffer(int64_t version, absl::string_view uri,
                           absl::string_view content)
    : version_(version),
      uri_(uri),
      parser_(verilog::VerilogAnalyzer::AnalyzeAutomaticPreprocessFallback(
          content, uri)) {
  VLOG(1) << "Analyzed " << uri << " lex:" << parser_->LexStatus()
          << "; parser:" << parser_->ParseStatus() << std::endl;
  // TODO(hzeller): should we use a filename not URI ?
  if (auto lint_result = RunLinter(uri, *parser_); lint_result.ok()) {
    lint_statuses_ = std::move(lint_result.value());
  }
}

void BufferTracker::Update(const std::string &uri,
                           const verible::lsp::EditTextBuffer &txt) {
  if (current_ && current_->version() == txt.last_global_version()) {
    LOG(DFATAL) << "Testing: Forgot to update version number ?";
    return;  // Nothing to do (we don't really expect this to happen)
  }
  txt.RequestContent([&txt, &uri, this](absl::string_view content) {
    current_.reset(new ParsedBuffer(txt.last_global_version(), uri, content));
  });
  if (current_->parsed_successfully()) {
    last_good_ = current_;
  }
}

verible::lsp::BufferCollection::UriBufferCallback
BufferTrackerContainer::GetSubscriptionCallback() {
  return
      [this](const std::string &uri, const verible::lsp::EditTextBuffer *txt) {
        // The Update() might replace, thus discard, old parsed buffers.
        // However, the change listeners we're about to inform might
        // expect them to be still alive while the update takes place.
        // So hold on to them here until all updates are performed.
        // (this copy is cheap as it is just reference counted pointers).
        BufferTracker remember_previous;
        if (const BufferTracker *tracker = FindBufferTrackerOrNull(uri)) {
          remember_previous = *tracker;
        }

        if (txt) {
          const BufferTracker *tracker = Update(uri, *txt);
          // Updated current() and last_good(); Now inform our listeners.
          for (const auto &change_listener : change_listeners_) {
            change_listener(uri, tracker);
          }
        } else {
          Remove(uri);
          for (const auto &change_listener : change_listeners_) {
            change_listener(uri, nullptr);
          }
        }
      };
}

BufferTracker *BufferTrackerContainer::Update(
    const std::string &uri, const verible::lsp::EditTextBuffer &txt) {
  auto inserted = buffers_.insert({uri, nullptr});
  if (inserted.second) {
    inserted.first->second.reset(new BufferTracker());
  }
  inserted.first->second->Update(uri, txt);
  return inserted.first->second.get();
}

const BufferTracker *BufferTrackerContainer::FindBufferTrackerOrNull(
    const std::string &uri) const {
  auto found = buffers_.find(uri);
  if (found == buffers_.end()) return nullptr;
  return found->second.get();
}
}  // namespace verilog
