// Copyright 2016 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/sysmgr/config.h"

#include <string>
#include <utility>
#include <vector>

#include "src/lib/files/file.h"
#include "src/lib/fxl/strings/string_printf.h"
#include "rapidjson/document.h"

namespace sysmgr {
namespace {
using fxl::StringPrintf;

constexpr char kApps[] = "apps";
constexpr char kServices[] = "services";
constexpr char kStartupServices[] = "startup_services";
constexpr char kOptionalServices[] = "optional_services";
constexpr char kUpdateDependencies[] = "update_dependencies";
}  // namespace

bool Config::ParseFromDirectory(const std::string& dir) {
  auto cb = [this](rapidjson::Document document) {
    ParseDocument(std::move(document));
  };
  json_parser_.ParseFromDirectory(dir, cb);
  return !json_parser_.HasError();
}

bool Config::ParseFromString(const std::string& data,
                             const std::string& pseudo_file) {
  rapidjson::Document document =
      json_parser_.ParseFromString(data, pseudo_file);
  if (!json_parser_.HasError()) {
    ParseDocument(std::move(document));
  }
  return !json_parser_.HasError();
}

void Config::ReadJsonStringArray(
    const rapidjson::Document& document, const char* member,
    std::vector<std::string>* out) {
  auto it = document.FindMember(member);
  if (it != document.MemberEnd()) {
    const auto& value = it->value;
    if (value.IsArray() &&
        std::all_of(
            value.GetArray().begin(), value.GetArray().end(),
            [](const rapidjson::Value& val) { return val.IsString(); })) {
      for (const auto& service : value.GetArray()) {
        out->push_back(service.GetString());
      }
    } else {
      json_parser_.ReportError(
          StringPrintf("'%s' is not an array of strings.", member));
    }
  }
}

bool Config::HasError() const { return json_parser_.HasError(); }

std::string Config::error_str() const { return json_parser_.error_str(); }

void Config::ParseDocument(rapidjson::Document document) {
  if (!document.IsObject()) {
    json_parser_.ReportError("Config file is not a JSON object.");
    return;
  }

  if (!ParseServiceMap(document, kServices, &services_)) {
    return;
  }

  auto apps_it = document.FindMember(kApps);
  if (apps_it != document.MemberEnd()) {
    const auto& value = apps_it->value;
    const auto* name = apps_it->name.GetString();
    if (value.IsArray()) {
      for (const auto& app : value.GetArray()) {
        auto launch_info = GetLaunchInfo(app, name);
        if (launch_info) {
          apps_.push_back(std::move(launch_info));
        }
      }
    } else {
      json_parser_.ReportError(StringPrintf("'%s' is not an array.", name));
    }
  }

  ReadJsonStringArray(document, kStartupServices, &startup_services_);
  ReadJsonStringArray(document, kUpdateDependencies, &update_dependencies_);
  ReadJsonStringArray(document, kOptionalServices, &optional_services_);
}

bool Config::ParseServiceMap(const rapidjson::Document& document,
                             const std::string& key,
                             Config::ServiceMap* services) {
  auto it = document.FindMember(key);
  if (it != document.MemberEnd()) {
    const auto& value = it->value;
    if (!value.IsObject()) {
      json_parser_.ReportError(
          StringPrintf("'%s' must be an object.", key.c_str()));
      return false;
    }
    for (const auto& reg : value.GetObject()) {
      if (!reg.name.IsString()) {
        json_parser_.ReportError(
            StringPrintf("Keys of '%s' must be strings.", key.c_str()));
        continue;
      }
      std::string service_key = reg.name.GetString();
      auto launch_info = GetLaunchInfo(
          reg.value, StringPrintf("%s.%s", key.c_str(), service_key.c_str()));
      if (launch_info) {
        services->emplace(service_key, std::move(launch_info));
      }
    }
  }
  return !json_parser_.HasError();
}

fuchsia::sys::LaunchInfoPtr Config::GetLaunchInfo(
    const rapidjson::Document::ValueType& value, const std::string& name) {
  auto launch_info = fuchsia::sys::LaunchInfo::New();
  if (value.IsString()) {
    launch_info->url = value.GetString();
    return launch_info;
  }

  if (value.IsArray()) {
    const auto& array = value.GetArray();
    // If the element is an array, ensure it is non-empty and all values are
    // strings.
    if (!array.Empty() && std::all_of(array.begin(), array.end(),
                                      [](const rapidjson::Value& val) {
                                        return val.IsString();
                                      })) {
      launch_info->url = array[0].GetString();
      for (size_t i = 1; i < array.Size(); ++i) {
        launch_info->arguments.push_back(array[i].GetString());
      }
      return launch_info;
    }
  }

  json_parser_.ReportError(StringPrintf(
      "'%s' must be a string or a non-empty array of strings.", name.c_str()));
  return nullptr;
}

}  // namespace sysmgr
