#include <iostream>

#include "boost/json/src.hpp"

// 构造json
void create_json() {
    boost::json::object val;
    val["a_string"] = "helloworld";
    val["a_number"] = 123;
    val["a_null"] = nullptr;
    val["a_array"] = {1, "2", boost::json::object({{"123", "123"}})};
    val["a_object"].emplace_object()["a_name"] = "a_data";
    val["a_bool"] = true;

    // 对象序列化
    std::cout << boost::json::serialize(val) << std::endl;
}

// 通过initializer_list构造json
void create_initializer_list() {
    boost::json::value val = {{"a_string", "test_string"},
                              {"a_number", 123},
                              {"a_null", nullptr},
                              {"a_array", {1, "2", {{"123", "123"}}}},
                              {"a_object", {{"a_name", "a_data"}}},
                              {"a_bool", true}};

    // 对象序列化
    std::cout << boost::json::serialize(val) << std::endl;
}

// 序列化 部分输出
void part_serialize() {
    boost::json::value value = {{"a_string", "test_string"},
                                {"a_number", 123},
                                {"a_null", nullptr},
                                {"a_array", {1, "2", {{"123", "123"}}}},
                                {"a_object", {{"a_name", "a_data"}}},
                                {"a_bool", true}};

    boost::json::serializer ser;
    ser.reset(&value);

    char temp_buf[6];
    while (!ser.done()) {
        std::memset(temp_buf, 0, sizeof(char) * 6);
        ser.read(temp_buf, 5);
        std::cout << temp_buf << std::endl;
    }
}

// 差异对比
void diff_contrast() {
    boost::json::value confused_json1 = {{"data", "value"}};
    boost::json::value confused_json2 = {{"data", "value"}};
    std::cout << "confused_json1: " << boost::json::serialize(confused_json1) << std::endl;
    std::cout << "confused_json2: " << boost::json::serialize(confused_json2) << std::endl;

    boost::json::value no_confused_json1 = {boost::json::array({"data", "value"})};
    boost::json::value no_confused_json2 = boost::json::object({{"data", "value"}});
    std::cout << "no_confused_json1: " << boost::json::serialize(no_confused_json1) << std::endl;
    std::cout << "no_confused_json2: " << boost::json::serialize(no_confused_json2) << std::endl;
}

// 错误处理
void error_process() {
    boost::json::error_code ec;
    boost::json::parse("{\"123\":[1,2,4]}", ec);
    std::cout << ec.message() << std::endl;

    boost::json::parse("{\"123\":[1,2,4}", ec);
    std::cout << ec.message() << std::endl;
}

// 非严格模式
void non_strict_mode() {
    unsigned char buf[4096];
    boost::json::static_resource mr(buf);
    boost::json::parse_options opt;
    opt.allow_comments = true;         // 允许注释
    opt.allow_trailing_commas = true;  // 允许最后的逗号
    boost::json::error_code ec;
    boost::json::parse("[1,2,3,] // comment test", ec, &mr, opt);
    std::cout << ec.message() << std::endl;
    boost::json::parse("[1,2,3,] // comment test", ec, &mr);
    std::cout << ec.message() << std::endl;
}

// 流写入
void stream_write() {
    boost::json::stream_parser p;
    p.reset();
    p.write("[1,2,");
    p.write("3]");
    p.finish();

    std::cout << boost::json::serialize(p.release()) << std::endl;
}

namespace my_namespace {
class my_class {
public:
    int a;
    int b;

    my_class(int a = 0, int b = 1)
        : a(a)
        , b(b) {
    }
};

void tag_invoke(boost::json::value_from_tag, boost::json::value &jv, my_class const &c) {
    auto &jo = jv.emplace_object();
    jo["a"] = c.a;
    jo["b"] = c.b;
}

my_class tag_invoke(boost::json::value_to_tag<my_class>, boost::json::value const &jv) {
    auto &jo = jv.as_object();
    return my_class(jo.at("a").as_int64(), jo.at("b").as_int64());
}

}  // namespace my_namespace

// 序列化
void serialize_class() {
    my_namespace::my_class obj;
    boost::json::value val = boost::json::value_from(obj);
    boost::json::value val2 = {obj};

    std::cout << boost::json::serialize(val) << std::endl;
    std::cout << boost::json::serialize(val2) << std::endl;
}

// 反序列化
void deserialization_class() {
    my_namespace::my_class obj(10086, 10010);
    boost::json::value val = boost::json::object({{"a", 10086}, {"b", 10010}});
    auto my_obj = boost::json::value_to<my_namespace::my_class>(val);
    std::cout << my_obj.a << ":" << my_obj.b << std::endl;
}

int main() {
    create_json();
    std::cout << "====================" << std::endl;
    create_initializer_list();
    std::cout << "====================" << std::endl;
    part_serialize();
    std::cout << "====================" << std::endl;
    diff_contrast();
    std::cout << "====================" << std::endl;
    error_process();
    std::cout << "====================" << std::endl;
    non_strict_mode();
    std::cout << "====================" << std::endl;
    stream_write();
    std::cout << "====================" << std::endl;
    serialize_class();
    std::cout << "====================" << std::endl;
    deserialization_class();
    return 0;
}