// 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 "garnet/bin/cpuperf/session_result_spec.h"

#include <lib/syslog/cpp/macros.h>

#include <rapidjson/document.h>
#include <rapidjson/error/en.h>
#include <rapidjson/schema.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>

#include "src/lib/files/file.h"
#include "src/lib/fxl/strings/string_printf.h"
#include "src/lib/json_parser/rapidjson_validation.h"

namespace cpuperf {

namespace {

// Top-level schema.
const char kRootSchema[] = R"({
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "config_name": {
      "type": "string"
    },
    "model_name": {
      "type": "string"
    },
    "num_iterations": {
      "type": "integer",
      "minimum": 1
    },
    "num_traces": {
      "type": "integer",
      "minimum": 1
    },
    "output_path_prefix": {
      "type": "string"
    }
  }
})";

const char kConfigNameKey[] = "config_name";
const char kModelNameKey[] = "model_name";
const char kNumIterationsKey[] = "num_iterations";
const char kNumTracesKey[] = "num_traces";
const char kOutputPathPrefixKey[] = "output_path_prefix";

}  // namespace

SessionResultSpec::SessionResultSpec(const std::string& config_name, const std::string& model_name,
                                     size_t num_iterations, size_t num_traces,
                                     const std::string& output_path_prefix)
    : config_name(config_name),
      model_name(model_name),
      num_iterations(num_iterations),
      num_traces(num_traces),
      output_path_prefix(output_path_prefix) {}

// Given an iteration number and trace number, return the output file.
std::string SessionResultSpec::GetTraceFilePath(size_t iter_num, size_t trace_num) const {
  return fxl::StringPrintf("%s.%zu.%zu.cpuperf", output_path_prefix.c_str(), iter_num, trace_num);
}

bool DecodeSessionResultSpec(const std::string& json, SessionResultSpec* out_spec) {
  // Initialize schemas for JSON validation.
  auto root_schema_result = json_parser::InitSchema(kRootSchema);
  if (root_schema_result.is_error()) {
    FX_LOGS(ERROR) << "Invalid schema: " << root_schema_result.error_value().ToString();
    return false;
  }

  SessionResultSpec result;
  rapidjson::Document document;
  document.Parse<rapidjson::kParseCommentsFlag>(json.c_str(), json.size());
  if (document.HasParseError()) {
    auto offset = document.GetErrorOffset();
    auto code = document.GetParseError();
    FX_LOGS(ERROR) << "Couldn't parse the session result spec file: offset " << offset << ", "
                   << GetParseError_En(code);
    return false;
  }
  auto root_schema = std::move(root_schema_result.value());
  auto validation_result =
      json_parser::ValidateSchema(document, root_schema, "session result spec");
  if (validation_result.is_error()) {
    FX_LOGS(ERROR) << "json validation failed: " << validation_result.error_value();
    return false;
  }

  if (document.HasMember(kConfigNameKey)) {
    result.config_name = document[kConfigNameKey].GetString();
  }

  if (document.HasMember(kModelNameKey)) {
    result.model_name = document[kModelNameKey].GetString();
  }

  if (document.HasMember(kNumIterationsKey)) {
    result.num_iterations = document[kNumIterationsKey].GetUint();
  }

  if (document.HasMember(kNumTracesKey)) {
    result.num_traces = document[kNumTracesKey].GetUint();
  }

  if (document.HasMember(kOutputPathPrefixKey)) {
    result.output_path_prefix = document[kOutputPathPrefixKey].GetString();
  }

  *out_spec = std::move(result);
  return true;
}

bool WriteSessionResultSpec(const std::string& output_file_path, const SessionResultSpec& spec) {
  rapidjson::StringBuffer string_buffer;
  rapidjson::Writer<rapidjson::StringBuffer> writer(string_buffer);

  writer.StartObject();

  if (!spec.config_name.empty()) {
    writer.Key(kConfigNameKey);
    writer.String(spec.config_name.c_str());
  }

  if (!spec.model_name.empty()) {
    writer.Key(kModelNameKey);
    writer.String(spec.model_name.c_str());
  }

  writer.Key(kNumIterationsKey);
  writer.Uint(spec.num_iterations);

  writer.Key(kNumTracesKey);
  writer.Uint(spec.num_traces);

  writer.Key(kOutputPathPrefixKey);
  writer.String(spec.output_path_prefix.c_str());

  writer.EndObject();

  std::string encoded = string_buffer.GetString();
  if (!files::WriteFile(output_file_path, encoded.data(), encoded.size())) {
    FX_LOGS(ERROR) << "Error writing to: " << output_file_path;
    return false;
  }
  return true;
}

}  // namespace cpuperf
