// Copyright 2018 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 "src/lib/json_parser/json_parser.h"

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>

#include <functional>
#include <string>

#include <fbl/unique_fd.h>
#include <rapidjson/document.h>
#include <rapidjson/error/en.h>

#include "lib/fit/function.h"
#include "src/lib/files/directory.h"
#include "src/lib/files/file.h"
#include "src/lib/fxl/macros.h"
#include "src/lib/fxl/strings/join_strings.h"
#include "src/lib/fxl/strings/string_printf.h"

namespace json_parser {
namespace {

using ErrorCallback = fit::function<void(size_t, const std::string&)>;
using fxl::StringPrintf;

void GetLineAndColumnForOffset(const std::string& input, size_t offset, int32_t* output_line,
                               int32_t* output_column) {
  if (offset == 0) {
    // Errors at position 0 are assumed to be related to the whole file.
    *output_line = 0;
    *output_column = 0;
    return;
  }
  *output_line = 1;
  *output_column = 1;
  for (size_t i = 0; i < input.size() && i < offset; i++) {
    if (input[i] == '\n') {
      *output_line += 1;
      *output_column = 1;
    } else {
      *output_column += 1;
    }
  }
}
}  // namespace

rapidjson::Document JSONParser::ParseFromFile(const std::string& file) {
  file_ = file;
  std::string data;
  if (!files::ReadFileToString(file, &data)) {
    errors_.push_back(StringPrintf("Failed to read file: %s", file.c_str()));
    return rapidjson::Document();
  }
  return ParseFromString(data, file);
}

rapidjson::Document JSONParser::ParseFromFileAt(int dirfd, const std::string& file) {
  file_ = file;
  std::string data;
  if (!files::ReadFileToStringAt(dirfd, file, &data)) {
    errors_.push_back(StringPrintf("Failed to read file: %s", file.c_str()));
    return rapidjson::Document();
  }
  return ParseFromString(data, file);
}

rapidjson::Document JSONParser::ParseFromString(const std::string& data, const std::string& file) {
  data_ = data;
  file_ = file;
  rapidjson::Document document;
  document.Parse<rapidjson::kParseIterativeFlag>(data_);
  if (document.HasParseError()) {
    ReportErrorInternal(document.GetErrorOffset(), GetParseError_En(document.GetParseError()));
  }
  return document;
}

void JSONParser::ParseFromDirectory(const std::string& path,
                                    fit::function<void(rapidjson::Document)> cb) {
  ParseFromDirectoryAt(AT_FDCWD, path, std::move(cb));
}

void JSONParser::ParseFromDirectoryAt(int dirfd, const std::string& path,
                                      fit::function<void(rapidjson::Document)> cb) {
  fbl::unique_fd dir_fd(openat(dirfd, path.c_str(), O_RDONLY | O_DIRECTORY));
  if (!dir_fd.is_valid()) {
    // A non-existent directory is not an error.
    return;
  }

  std::vector<std::string> dir_entries;
  if (!files::ReadDirContentsAt(dir_fd.get(), ".", &dir_entries)) {
    ReportError(fxl::StringPrintf("Could not read directory contents from path %s error %s",
                                  path.c_str(), strerror(errno)));
    return;
  }
  for (const auto& entry : dir_entries) {
    if (!files::IsFileAt(dir_fd.get(), entry))
      continue;

    rapidjson::Document document = ParseFromFileAt(dir_fd.get(), entry);
    if (!document.HasParseError() && !document.IsNull()) {
      cb(std::move(document));
    }
  }
}

void JSONParser::CopyStringArray(const std::string& name, const rapidjson::Value& value,
                                 std::vector<std::string>* out) {
  out->clear();
  if (!value.IsArray()) {
    ReportError(fxl::StringPrintf("'%s' is not an array.", name.c_str()));
    return;
  }
  for (const auto& entry : value.GetArray()) {
    if (!entry.IsString()) {
      ReportError(fxl::StringPrintf("'%s' contains an item that's not a string", name.c_str()));
      out->clear();
      return;
    }
    out->push_back(entry.GetString());
  }
}

void JSONParser::ReportError(const std::string& error) { ReportErrorInternal(0, error); }

void JSONParser::ReportErrorInternal(size_t offset, const std::string& error) {
  int32_t line;
  int32_t column;
  GetLineAndColumnForOffset(data_, offset, &line, &column);
  if (line == 0) {
    errors_.push_back(StringPrintf("%s: %s", file_.c_str(), error.c_str()));
  } else {
    errors_.push_back(StringPrintf("%s:%d:%d: %s", file_.c_str(), line, column, error.c_str()));
  }
}

bool JSONParser::HasError() const { return !errors_.empty(); }

std::string JSONParser::error_str() const { return fxl::JoinStrings(errors_, "\n"); }

}  // namespace json_parser
