// Copyright (c) 2013 The Chromium 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 "gn/err.h"

#include <stddef.h>

#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "gn/filesystem_utils.h"
#include "gn/input_file.h"
#include "gn/parse_tree.h"
#include "gn/standard_out.h"
#include "gn/tokenizer.h"
#include "gn/value.h"

namespace {

std::string GetNthLine(std::string_view data, int n) {
  size_t line_off = Tokenizer::ByteOffsetOfNthLine(data, n);
  size_t end = line_off + 1;
  while (end < data.size() && !Tokenizer::IsNewline(data, end))
    end++;
  return std::string(data.substr(line_off, end - line_off));
}

void FillRangeOnLine(const LocationRange& range,
                     int line_number,
                     std::string* line) {
  // Only bother if the range's begin or end overlaps the line. If the entire
  // line is highlighted as a result of this range, it's not very helpful.
  if (range.begin().line_number() != line_number &&
      range.end().line_number() != line_number)
    return;

  // Watch out, the char offsets in the location are 1-based, so we have to
  // subtract 1.
  int begin_char;
  if (range.begin().line_number() < line_number)
    begin_char = 0;
  else
    begin_char = range.begin().column_number() - 1;

  int end_char;
  if (range.end().line_number() > line_number)
    end_char = static_cast<int>(line->size());  // Ending is non-inclusive.
  else
    end_char = range.end().column_number() - 1;

  CHECK(end_char >= begin_char);
  CHECK(begin_char >= 0 && begin_char <= static_cast<int>(line->size()));
  CHECK(end_char >= 0 && end_char <= static_cast<int>(line->size()));
  for (int i = begin_char; i < end_char; i++)
    line->at(i) = '-';
}

// The line length is used to clip the maximum length of the markers we'll
// make if the error spans more than one line (like unterminated literals).
void OutputHighlighedPosition(const Location& location,
                              const Err::RangeList& ranges,
                              size_t line_length) {
  // Make a buffer of the line in spaces.
  std::string highlight;
  highlight.resize(line_length);
  for (size_t i = 0; i < line_length; i++)
    highlight[i] = ' ';

  // Highlight all the ranges on the line.
  for (const auto& range : ranges)
    FillRangeOnLine(range, location.line_number(), &highlight);

  // Allow the marker to be one past the end of the line for marking the end.
  highlight.push_back(' ');
  CHECK(location.column_number() - 1 >= 0 &&
        location.column_number() - 1 < static_cast<int>(highlight.size()));
  highlight[location.column_number() - 1] = '^';

  // Trim unused spaces from end of line.
  while (!highlight.empty() && highlight[highlight.size() - 1] == ' ')
    highlight.resize(highlight.size() - 1);

  highlight += "\n";
  OutputString(highlight, DECORATION_BLUE);
}

}  // namespace

Err::Err(const Err& other) {
  if (other.info_)
    info_ = std::make_unique<ErrInfo>(*other.info_);
}

Err::Err(const Location& location,
         const std::string& msg,
         const std::string& help)
    : info_(std::make_unique<ErrInfo>(location, msg, help)) {}

Err::Err(const LocationRange& range,
         const std::string& msg,
         const std::string& help)
    : info_(std::make_unique<ErrInfo>(range.begin(), msg, help)) {
  info_->ranges.push_back(range);
}

Err::Err(const Token& token, const std::string& msg, const std::string& help)
    : info_(std::make_unique<ErrInfo>(token.location(), msg, help)) {
  info_->ranges.push_back(token.range());
}

Err::Err(const ParseNode* node,
         const std::string& msg,
         const std::string& help_text)
    : info_(std::make_unique<ErrInfo>(Location(), msg, help_text)) {
  // Node will be null in certain tests.
  if (node) {
    LocationRange range = node->GetRange();
    info_->location = range.begin();
    info_->ranges.push_back(range);
  }
}

Err::Err(const Value& value,
         const std::string& msg,
         const std::string& help_text)
    : info_(std::make_unique<ErrInfo>(Location(), msg, help_text)) {
  if (value.origin()) {
    LocationRange range = value.origin()->GetRange();
    info_->location = range.begin();
    info_->ranges.push_back(range);
  }
}

Err& Err::operator=(const Err& other) {
  if (other.info_) {
    info_ = std::make_unique<ErrInfo>(*other.info_);
  } else {
    info_.reset();
  }
  return *this;
}

void Err::PrintToStdout() const {
  InternalPrintToStdout(false, true);
}

void Err::PrintNonfatalToStdout() const {
  InternalPrintToStdout(false, false);
}

void Err::AppendSubErr(const Err& err) {
  info_->sub_errs.push_back(err);
}

void Err::InternalPrintToStdout(bool is_sub_err, bool is_fatal) const {
  DCHECK(info_);

  if (!is_sub_err) {
    if (is_fatal)
      OutputString("ERROR ", DECORATION_RED);
    else
      OutputString("WARNING ", DECORATION_RED);
  }

  // File name and location.
  const InputFile* input_file = info_->location.file();
  std::string loc_str = info_->location.Describe(true);
  if (!loc_str.empty()) {
    if (is_sub_err)
      loc_str.insert(0, "See ");
    else
      loc_str.insert(0, "at ");
    if (!info_->toolchain_label.is_null())
      loc_str += " ";
  }
  std::string toolchain_str;
  if (!info_->toolchain_label.is_null()) {
    toolchain_str += "(" + info_->toolchain_label.GetUserVisibleName(false) + ")";
  }
  std::string colon;
  if (!loc_str.empty() || !toolchain_str.empty())
    colon = ": ";
  OutputString(loc_str + toolchain_str + colon + info_->message + "\n");

  // Quoted line.
  if (input_file) {
    std::string line =
        GetNthLine(input_file->contents(), info_->location.line_number());
    if (!base::ContainsOnlyChars(line, base::kWhitespaceASCII)) {
      OutputString(line + "\n", DECORATION_DIM);
      OutputHighlighedPosition(info_->location, info_->ranges, line.size());
    }
  }

  // Optional help text.
  if (!info_->help_text.empty())
    OutputString(info_->help_text + "\n");

  // Sub errors.
  for (const auto& sub_err : info_->sub_errs)
    sub_err.InternalPrintToStdout(true, is_fatal);
}
