// 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/developer/debug/zxdb/client/setting_schema.h"

#include <algorithm>
#include <set>
#include <string>

#include "src/lib/fxl/strings/join_strings.h"
#include "src/lib/fxl/strings/trim.h"

namespace zxdb {

namespace {

Err ValidateOptions(const std::vector<std::string>& options, const std::vector<std::string>& set) {
  for (auto& s : set) {
    if (std::find(options.begin(), options.end(), s) == options.end())
      return Err("Option \"%s\" is not a valid option", s.c_str());
  }
  return Err();
}

}  // namespace

void SettingSchema::AddBool(std::string name, std::string description, bool v) {
  AddSetting(std::move(name), std::move(description), SettingValue(v));
}

void SettingSchema::AddInt(std::string name, std::string description, int64_t v) {
  AddSetting(std::move(name), std::move(description), SettingValue(v));
}

void SettingSchema::AddExecutionScope(std::string name, std::string description,
                                      const ExecutionScope v) {
  AddSetting(std::move(name), std::move(description), SettingValue(v));
}

void SettingSchema::AddInputLocations(std::string name, std::string description,
                                      std::vector<InputLocation> v) {
  AddSetting(std::move(name), std::move(description), SettingValue(std::move(v)));
}

void SettingSchema::AddString(std::string name, std::string description, std::string v,
                              std::vector<std::string> valid_options) {
  AddSetting(std::move(name), std::move(description), SettingValue(v), std::move(valid_options));
}

bool SettingSchema::AddList(std::string name, std::string description, std::vector<std::string> v,
                            std::vector<std::string> options) {
  if (!options.empty() && ValidateOptions(options, v).has_error())
    return false;
  AddSetting(std::move(name), std::move(description), SettingValue(v), std::move(options));
  return true;
}

void SettingSchema::AddSetting(std::string name, std::string description,
                               SettingValue default_value, std::vector<std::string> options) {
  auto& record = settings_[name];
  record.name = std::move(name);
  record.description = std::move(description);
  record.default_value = std::move(default_value);
  record.options = std::move(options);
}

bool SettingSchema::HasSetting(const std::string& key) {
  return settings_.find(key) != settings_.end();
}

Err SettingSchema::ValidateSetting(const std::string& key, const SettingValue& value) const {
  auto it = settings_.find(key);
  if (it == settings_.end())
    return Err("Setting \"%s\" not found in the given context.", key.c_str());

  const auto& record = it->second;
  if (record.default_value.type() != value.type()) {
    return Err("Setting \"%s\" expects a different type (expected: %s, given: %s).", key.c_str(),
               SettingTypeToString(record.default_value.type()), SettingTypeToString(value.type()));
  }

  if (!record.options.empty()) {
    // Validate the setting value.
    if (value.is_list()) {
      // Each list element must be in the valid option list.
      if (Err err = ValidateOptions(record.options, value.get_list()); err.has_error())
        return err;
    } else if (value.is_string()) {
      // String must be in the valid option list.
      if (std::find(record.options.begin(), record.options.end(), value.get_string()) ==
          record.options.end()) {
        return Err("Option \"%s\" is not a valid option", value.get_string().c_str());
      }
    }
  }

  return Err();
}

const SettingSchema::Record* SettingSchema::GetSetting(const std::string& name) const {
  const auto& found = settings_.find(name);
  if (found == settings_.end())
    return nullptr;
  return &found->second;
}

}  // namespace zxdb
