
#include <iostream>
#include <string>

#include <boost/algorithm/string.hpp>

#include <fc/io/json.hpp>
#include <fc/reflect/reflect.hpp>
#include <fc/variant.hpp>

#include <graphene/utilities/key_conversion.hpp>

#include <scorum/protocol/types.hpp>
#include <scorum/protocol/authority.hpp>

#include <scorum/chain/schema/shared_authority.hpp>

#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>

#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>

#include <fc/fixed_string.hpp>
#include <fc/shared_string.hpp>
#include <fc/shared_allocator.hpp>

using namespace boost::multi_index;
namespace bip = boost::interprocess;

namespace fc {

/*
template<typename... T >
void to_variant( const bip::deque< T... >& t, fc::variant& v ) {
std::vector<variant> vars(t.size());
for( size_t i = 0; i < t.size(); ++i ) {
 vars[i] = t[i];
}
v = std::move(vars);
}

template<typename T, typename... A>
void from_variant( const fc::variant& v, bip::deque< T, A... >& d ) {
const variants& vars = v.get_array();
d.clear();
d.resize( vars.size() );
for( uint32_t i = 0; i < vars.size(); ++i ) {
 from_variant( vars[i], d[i] );
}
}
*/
}

/* Book record. All its members can be placed in shared memory,
 *  * hence the structure itself can too.
 *   */

struct book
{
    typedef fc::shared_allocator<book> allocator_type;

    template <typename Constructor, typename Allocator>
    book(Constructor&& c, const Allocator& al)
        : name(al)
        , author(al)
        , pages(0)
        , prize(0)
        , auth(al)
        , deq(al)
    {
        c(*this);
    }

    fc::shared_string name;
    fc::shared_string author;
    int32_t pages;
    int32_t prize;
    scorum::chain::shared_authority auth;
    fc::shared_deque<fc::shared_string> deq;

    book(const fc::shared_string::allocator_type& al)
        : name(al)
        , author(al)
        , pages(0)
        , prize(0)
        , auth(al)
        , deq(al)
    {
    }
};

typedef fc::
    shared_multi_index_container<book,
                                 indexed_by<ordered_non_unique<BOOST_MULTI_INDEX_MEMBER(
                                                book, fc::shared_string, author)>,
                                            ordered_non_unique<BOOST_MULTI_INDEX_MEMBER(book, fc::shared_string, name)>,
                                            ordered_non_unique<BOOST_MULTI_INDEX_MEMBER(book, int32_t, prize)>>>
        book_container;

FC_REFLECT(book, (name)(author)(pages)(prize)(deq)(auth))

struct astr
{
    fc::fixed_string<> str;
    fc::fixed_string<> str1;
    fc::fixed_string<> str2;
};
FC_REFLECT(astr, (str)(str1)(str2))
struct bstr
{
    std::string str;
    std::string str1;
    std::string str2;
};
FC_REFLECT(bstr, (str)(str1)(str2))

int main(int argc, char** argv, char** envp)
{
    try
    {

        bip::managed_mapped_file seg(bip::open_or_create, "./book_container.db", 1024 * 100);
        bip::named_mutex mutex(bip::open_or_create, "./book_container.db");

        /*
        book b( book::allocator_type( seg.get_segment_manager() ) );
        b.name = "test name";
        b.author = "test author";
        b.deq.push_back( fc::shared_string( "hello world", basic_string_allocator( seg.get_segment_manager() )  ) );
        idump((b));
        */
        book_container* pbc = seg.find_or_construct<book_container>("book container")(
            book_container::ctor_args_list(), book_container::allocator_type(seg.get_segment_manager()));

        for (const auto& item : *pbc)
        {
            idump((item));
        }

        // b.pages = pbc->size();
        // b.auth = scorum::chain::authority( 1, "dan", pbc->size() );
        pbc->emplace(
            [&](book& b) {
                b.name = "emplace name";
                b.pages = pbc->size();
            },
            book::allocator_type(seg.get_segment_manager()));

        bip::deque<book, book::allocator_type>* deq = seg.find_or_construct<bip::deque<book, book::allocator_type>>(
            "book deque")(book_container::allocator_type(seg.get_segment_manager()));
        idump((deq->size()));

        // book c( b ); //book::allocator_type( seg.get_segment_manager() ) );
        // deq->push_back( b );
    }
    catch (const std::exception& e)
    {
        edump((std::string(e.what())));
    }
    return 0;
}
