/**
 *
 * @file src/trace/Serializer_values.hpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Augustin Degomme
 * @author Thibault Soucarre
 *
 * @date 2024-07-17
 */
#ifndef SERIALIZER_VALUES
#define SERIALIZER_VALUES

#include "trace/Serializer.hpp"

#include <limits>
#include <float.h>
#include "trace/values/Values.hpp"
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <trace/Serializer.hpp>
using namespace std;

// serialize in this file all kinds of Values

using namespace boost::serialization;

// Value serialization methods

BOOST_SERIALIZATION_SPLIT_FREE(Value) // we have 2 functions (load/save) instead of one serialize

// we will assume that at this point,  values are correct = do not store the is_correct bit which is used only for parsing
// we don't need to serialize Value then, which saves a lot of compilation time.

template <class Archive>
void save(Archive &ar, const Value &l, const unsigned int) {
    bool b = l.is_correct();
    ar &b;
}

template <class Archive>
void load(Archive &ar, Value &l, const unsigned int) {
    bool t;
    ar &t;
    l.set_correct(t);
}

BOOST_SERIALIZATION_ASSUME_ABSTRACT(Value) // this type can be inherited by other serialized classes*/

// telle the compiler not to be stupid when serializing these objects
BOOST_CLASS_TRACKING(Date, track_never)
BOOST_CLASS_TRACKING(Name, track_never)
BOOST_CLASS_TRACKING(Color, track_never)
BOOST_CLASS_TRACKING(Double, track_never)
BOOST_CLASS_TRACKING(Hex, track_never)
BOOST_CLASS_TRACKING(String, track_never)
BOOST_CLASS_TRACKING(::Integer, track_never)

// Date serialization methods

BOOST_SERIALIZATION_SPLIT_FREE(Date)

template <class Archive>
void save(Archive &ar, const Date &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    const double d = l.get_value();
    ar &d;
}

template <class Archive>
void load(Archive &ar, Date &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    double d;
    ar &d;
    new (&l) Date(d);
}

// Color serialization methods

BOOST_SERIALIZATION_SPLIT_FREE(Color)

template <class Archive>
void save(Archive &ar, const Color &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    double r = l.get_red();
    ar &r;
    r = l.get_green();
    ar &r;
    r = l.get_blue();
    ar &r;
}

template <class Archive>
void load(Archive &ar, Color &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    double r;
    double g;
    double b;
    ar &r;
    ar &g;
    ar &b;
    new (&l) Color(r, g, b);
}

// Double serialization methods
BOOST_SERIALIZATION_SPLIT_FREE(Double)

template <class Archive>
void save(Archive &ar, const Double &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    double d = l.get_value();
    ar &d;
}

template <class Archive>
void load(Archive &ar, Double &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    double d;
    ar &d;
    new (&l) Double(d);
}

// Hex serialization methods
BOOST_SERIALIZATION_SPLIT_FREE(Hex)

template <class Archive>
void save(Archive &ar, const Hex &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    unsigned int t = l.get_value();
    ar &t;
}

template <class Archive>
void load(Archive &ar, Hex &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    unsigned int d;
    ar &d;
    new (&l) Hex(d);
}

// Integer serialization methods
BOOST_SERIALIZATION_SPLIT_FREE(::Integer) // boost.Integer exists and causes a conflict without ::

template <class Archive>
void save(Archive &ar, const ::Integer &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    int t = l.get_value();
    ar &t;
}

template <class Archive>
void load(Archive &ar, ::Integer &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    int d;
    ar &d;
    new (&l)::Integer(d);
}

// String serialization methods
BOOST_SERIALIZATION_SPLIT_FREE(String)

template <class Archive>
void save(Archive &ar, const String &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    std::string t = l.to_string();
    ar &t;
}

template <class Archive>
void load(Archive &ar, String &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    std::string d;
    ar &d;
    new (&l) String(d);
}

// Name serialization methods
BOOST_SERIALIZATION_SPLIT_FREE(Name)

template <class Archive>
void save(Archive &ar, const Name &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    std::string t = l.get_name();
    ar &t;
    std::string t2 = l.get_alias();
    ar &t2;
}

template <class Archive>
void load(Archive &ar, Name &l, const unsigned int) {
    ar &boost::serialization::base_object<Value>(l);
    std::string n, a;
    ar &n;
    ar &a;
    new (&l) Name(n, a);
}

#endif
