#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/seq.hpp>
#include <boost/preprocessor/stringize.hpp>

#define PLATON_REFLECT_MEMBER_OP( r, OP, elem ) \
  OP t.elem

/**
 * @defgroup serialize Serialize API
 * @brief Defines functions to serialize and deserialize object
 * @ingroup contractdev
 */

/**
 * @defgroup serializecpp Serialize C++ API
 * @brief Defines C++ API to serialize and deserialize object
 * @ingroup serialize
 * @{
 */

/**
 *  Defines serialization and deserialization for a class
 *
 *  @brief Defines serialization and deserialization for a class
 *
 *  @param TYPE - the class to have its serialization and deserialization defined
 *  @param MEMBERS - a sequence of member names.  (field1)(field2)(field3)
 */
#define PLATON_SERIALIZE( TYPE,  MEMBERS ) \
 template<typename DS> \
 friend DS& operator << ( DS& ds, const TYPE& t ){ \
    return ds BOOST_PP_SEQ_FOR_EACH( PLATON_REFLECT_MEMBER_OP, <<, MEMBERS );\
 }\
 template<typename DS> \
 friend DS& operator >> ( DS& ds, TYPE& t ){ \
    return ds BOOST_PP_SEQ_FOR_EACH( PLATON_REFLECT_MEMBER_OP, >>, MEMBERS );\
 }

/**
 *  Defines serialization and deserialization for a class which inherits from other classes that
 *  have their serialization and deserialization defined
 *
 *  @brief Defines serialization and deserialization for a class which inherits from other classes that
 *  have their serialization and deserialization defined
 *
 *  @param TYPE - the class to have its serialization and deserialization defined
 *  @param BASE - a sequence of base class names (basea)(baseb)(basec)
 *  @param MEMBERS - a sequence of member names.  (field1)(field2)(field3)
 */
#define PLATON_SERIALIZE_DERIVED( TYPE, BASE, MEMBERS ) \
 template<typename DS> \
 friend DS& operator << ( DS& ds, const TYPE& t ){ \
    ds << static_cast<const BASE&>(t); \
    return ds BOOST_PP_SEQ_FOR_EACH( PLATON_REFLECT_MEMBER_OP, <<, MEMBERS );\
 }\
 template<typename DS> \
 friend DS& operator >> ( DS& ds, TYPE& t ){ \
    ds >> static_cast<BASE&>(t); \
    return ds BOOST_PP_SEQ_FOR_EACH( PLATON_REFLECT_MEMBER_OP, >>, MEMBERS );\
 }
///@} serializecpp
