// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Boolberry developers
// Copyright (c) 2017-2025 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// You may obtain a copy of the licence at:
//
//     https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
//
// The EUPL is a copyleft licence that is compatible with the MIT/X11
// licence used by the original projects; the MIT terms are therefore
// considered “grandfathered” under the EUPL for this code.
//
// SPDX‑License‑Identifier: EUPL-1.2
//

#pragma once
#include <type_traits>
#ifndef DISABLE_PFR_SERIALIZATION_SELFCHECK
  #include <boost/pfr.hpp>
#endif
#define BEGIN_BOOST_SERIALIZATION()     template <class t_archive> void serialize(t_archive &_arch, const unsigned int ver) {

template<size_t A, size_t B> struct TAssertEquality {
  static_assert(A == B, "Serialization map is not updated, sizeof() missmatch");
  static constexpr bool _cResult = (A == B);
};

//experemental feature: self-validated serialization map, needed to not forget add new members to serialization maps
#define BEGIN_BOOST_SERIALIZATION_SV(sz)  BEGIN_BOOST_SERIALIZATION()  \
              static constexpr bool _cIsEqual = TAssertEquality<sz, sizeof(*this)>::_cResult;



#define BOOST_SERIALIZE(x)    _arch & x;
#define BOOST_SERIALIZE_BASE_CLASS(class_type)    _arch & static_cast<class_type&>(*this);

#define BOOST_END_VERSION_UNDER(x)                            \
  if(ver < x ) {return;}

#define END_BOOST_SERIALIZATION()       }



/**********************************************************************************************************************************
  This serialization closing macro adds self-validation by checking the total number of fields in the structure using boost::pfr.

  Note: "num_fields" does NOT represent the number of fields included in the serialization. Instead, it indicates the total number
  of fields in the structure, some of which might not be included in the serialization for valid reasons. If someone adds new 
  fields to the structure but forgets to update the serialization map, the compilation will fail. Any update to "num_fields" must
  be accompanied by a thorough review of the serialization map to ensure no fields are omitted.
**********************************************************************************************************************************/
#ifndef DISABLE_PFR_SERIALIZATION_SELFCHECK
  #define END_BOOST_SERIALIZATION_TOTAL_FIELDS(num_fields)  static_assert(num_fields == boost::pfr::tuple_size<std::remove_reference<decltype(*this)>::type>::value, "Unexpected number of fields!"); }
#else
  #define END_BOOST_SERIALIZATION_TOTAL_FIELDS(num_fields) END_BOOST_SERIALIZATION()
#endif

#define BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(current_version) static const unsigned int current_boost_version_serialization_version = current_version;

#define LOOP_BACK_BOOST_SERIALIZATION_VERSION(type) BOOST_CLASS_VERSION(type, type::current_boost_version_serialization_version);



template<bool IsSaving, typename destination_t>
struct boost_transition_t {};

template<typename destination_t>
struct boost_transition_t<true, destination_t>
{
  template <typename archive, typename origin_type>
  static void chain_serialize(archive& ar, const origin_type& origin_tx)
  {
    destination_t dst_tx = AUTO_VAL_INIT(dst_tx);
    transition_convert(origin_tx, dst_tx);
    ar & dst_tx;
  }
};

template<typename destination_t>
struct boost_transition_t<false, destination_t>
{
  template <typename archive, typename origin_type>
  static void chain_serialize(archive& ar, origin_type& origin_tx)
  {
    // TODO: consider using move semantic for temporary 'dst_tx'
    destination_t dst_tx = AUTO_VAL_INIT(dst_tx);
    ar & dst_tx;    
    transition_convert(dst_tx, origin_tx);
  }
};


#define BOOST_CHAIN_TRANSITION_VER(obj_version, old_type)   if (obj_version == ver)  {boost_transition_t<t_archive::is_saving::value, old_type>::chain_serialize(_arch, *this);return;}

#define BOOST_CHAIN_TRANSITION_IF_COND_TRUE(condition, old_type)   if (condition)  {boost_transition_t<t_archive::is_saving::value, old_type>::chain_serialize(_arch, *this);return;}

/*
  example of use: 

  struct tx_extra_info 
  {
    crypto::public_key m_tx_pub_key;
    extra_alias_entry m_alias;
    std::string m_user_data_blob;
    extra_attachment_info m_attachment_info;

    BEGIN_BOOST_SERIALIZATION()
      BOOST_SERIALIZE(m_tx_pub_key)
      BOOST_SERIALIZE(m_alias)
      if(ver < xxx) return;
      BOOST_SERIALIZE(m_user_data_blob)
      BOOST_SERIALIZE(m_attachment_info)
    END_BOOST_SERIALIZATION()
  };
*/
