////////////////////////////////////////////////////////////////////////
// A test & demo app for s11n[lite].
// Author: stephan@s11n.net
// License: Do As You Damned Well Please
////////////////////////////////////////////////////////////////////////

#ifdef NDEBUG
#  undef NDEBUG // we always want assert() to work
#endif

#include <cassert>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>


////////////////////////////////////////////////////////////////////////
#include <s11n.net/s11n/s11nlite.hpp> // s11n & s11nlite frameworks
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
// misc util stuff
#include <s11n.net/s11n/s11n_debuggering_macros.hpp> // CERR
#include <s11n.net/acme/argv_parser.hpp> // argv_parser class
////////////////////////////////////////////////////////////////////////

struct AType {
        AType()
        {
                CERR << "AType::AType\n";
                for( int i = 0; i < 5; ++i )
                {
                        this->m_vec.push_back( i * i );
                }

        }
        virtual ~AType(){}

        virtual bool operator()( s11nlite::node_type & dest ) const
        {
                CERR << "AType::serialize\n";
                typedef s11nlite::node_traits_type NT;
                NT::class_name( dest, "AType" );
                s11nlite::serialize_subnode( dest, "vec", this->m_vec );
                return true;
        }

        virtual bool operator()( const s11nlite::node_type & src )
        {
                this->m_vec.clear();
                CERR << "AType::deserialize\n";
                s11nlite::deserialize_subnode( src, "vec", this->m_vec );
                return true;
        }

private:
        std::vector<int> m_vec;
};

struct BType : public AType {
        BType()
        {
                CERR << "BType::BType\n";
        }
        virtual ~BType(){}
        virtual bool operator()( s11nlite::node_type & dest ) const
        {
                this->AType::operator()( dest );
                CERR << "BType::serialize\n";
                typedef s11nlite::node_traits_type NT;
                NT::class_name( dest, "BType" );
                return true;
        }

        virtual bool operator()( const s11nlite::node_type & src )
        {
                this->AType::operator()( src );
                CERR << "BType::deserialize\n";
                return true;
        }

};

struct X : public BType {
        X()
        {
                CERR << "X::X\n";
        }
        virtual ~X(){}

        virtual bool operator()( s11nlite::node_type & dest ) const
        {
                this->BType::operator()( dest );
                CERR << "X::serialize\n";
                typedef s11nlite::node_traits_type NT;
                NT::class_name( dest, "X" );
                return true;
        }

        virtual bool operator()( const s11nlite::node_type & src )
        {
                this->BType::operator()( src );
                CERR << "X::deserialize\n";
                return true;
        }
};

#define S11N_TYPE AType
#define S11N_TYPE_NAME "AType"
#include <s11n.net/s11n/reg_serializable_traits.hpp>

#define S11N_TYPE BType
#define S11N_TYPE_NAME "BType"
#define S11N_BASE_TYPE AType
#include <s11n.net/s11n/reg_serializable_traits.hpp>

#define S11N_TYPE X
#define S11N_TYPE_NAME "X"
#define S11N_BASE_TYPE AType
#include <s11n.net/s11n/reg_serializable_traits.hpp>

void test_hier();

int
main( int argc, char **argv )
{
        typedef acme::argv_parser ARGV;
        ARGV & args = ARGV::args( argc, argv );

        if( args.is_set( "d" ) ) // either -d or --d
        {
                cl::class_loader_debug_level(1);
        }
        else
        {
                CERR << "tip: use -d to enable classloader debug output.\n";
        }

        // set the Serializer we want using -s=classname
        s11nlite::serializer_class( args.get( "s", "parens" ) );
        test_hier();

        return 0;
}

void test_hier()
{
        AType * c = new X;

        using namespace s11nlite;

        std::ostringstream os; // simulate a file
        save( c, os );
        CERR << "Data=[\n"<<os.str()<<"]\n";
        delete( c );

        std::istringstream is( os.str() );
        c = load_serializable<AType>( is );
        save( c, std::cout );
        delete( c );
}

