// This file is generated by base_string_adapter_cc.template.

// Copyright 2019 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 {{format_include(config.protocol.package, "base_string_adapter")}}
#include {{format_include(config.protocol.package, "Protocol")}}

#include <utility>
#include "base/base64.h"
#include "base/json/json_reader.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "{{config.crdtp.dir}}/cbor.h"
#include "{{config.crdtp.dir}}/protocol_core.h"

using namespace {{config.crdtp.namespace}};

using {{"::".join(config.protocol.namespace)}}::Binary;
using {{"::".join(config.protocol.namespace)}}::String;
using {{"::".join(config.protocol.namespace)}}::StringUtil;

{% for namespace in config.protocol.namespace %}
namespace {{namespace}} {
{% endfor %}

// In Chromium, we do not support big endian architectures, so no conversion is needed
// to interpret UTF16LE.
// static
String StringUtil::fromUTF16LE(const uint16_t* data, size_t length) {
  std::string utf8;
  base::UTF16ToUTF8(reinterpret_cast<const char16_t*>(data), length, &utf8);
  return utf8;
}

std::unique_ptr<protocol::Value> toProtocolValue(
    const base::Value& value, int depth) {
  if (!depth)
    return nullptr;
  if (value.is_none())
    return protocol::Value::null();
  if (value.is_bool())
    return protocol::FundamentalValue::create(value.GetBool());
  if (value.is_int())
    return protocol::FundamentalValue::create(value.GetInt());
  if (value.is_double())
    return protocol::FundamentalValue::create(value.GetDouble());
  if (value.is_string())
    return protocol::StringValue::create(value.GetString());
  if (value.is_list()) {
    auto result = protocol::ListValue::create();
    for (const base::Value& item : value.GetList()) {
      if (auto converted = toProtocolValue(item, depth - 1)) {
        result->pushValue(std::move(converted));
      }
    }
    return result;
  }
  if (value.is_dict()) {
    auto result = protocol::DictionaryValue::create();
    for (auto kv : value.DictItems()) {
      if (auto converted = toProtocolValue(kv.second, depth - 1)) {
        result->setValue(kv.first, std::move(converted));
      }
    }
    return result;
  }
  return nullptr;
}

base::Value toBaseValue(Value* value, int depth) {
  if (!value || !depth)
    return base::Value();
  if (value->type() == Value::TypeBoolean) {
    bool inner;
    value->asBoolean(&inner);
    return base::Value(inner);
  }
  if (value->type() == Value::TypeInteger) {
    int inner;
    value->asInteger(&inner);
    return base::Value(inner);
  }
  if (value->type() == Value::TypeDouble) {
    double inner;
    value->asDouble(&inner);
    return base::Value(inner);
  }
  if (value->type() == Value::TypeString) {
    std::string inner;
    value->asString(&inner);
    return base::Value(inner);
  }
  if (value->type() == Value::TypeArray) {
    ListValue* list = ListValue::cast(value);
    base::Value result(base::Value::Type::LIST);
    for (size_t i = 0; i < list->size(); i++) {
      base::Value converted = toBaseValue(list->at(i), depth - 1);
      if (!converted.is_none())
        result.Append(std::move(converted));
    }
    return result;
  }
  if (value->type() == Value::TypeObject) {
    DictionaryValue* dict = DictionaryValue::cast(value);
    base::Value result(base::Value::Type::DICTIONARY);
    for (size_t i = 0; i < dict->size(); i++) {
      DictionaryValue::Entry entry = dict->at(i);
      base::Value converted = toBaseValue(entry.second, depth - 1);
      if (!converted.is_none())
        result.SetKey(entry.first, std::move(converted));
    }
    return result;
  }
  return base::Value();
}

{% for namespace in config.protocol.namespace %}
}  // namespace {{namespace}} {
{% endfor %}
