#include <iostream>

#include <ace/Thread_Manager.h>

#include <oess_1/io/h/bstring_buf.hpp>

#include <oess_1/stdsn/h/serializable.hpp>
#include <oess_1/stdsn/h/inout_templ.hpp>
#include <oess_1/stdsn/h/ent_no_markers.hpp>

class	A
	:	virtual public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( A )
	private :
		std::string	m_a;

	public :
		A()
			{}
		A( const std::string & a )
			:	m_a( a )
			{}
		virtual ~A()
			{}
	};

class	B
	:	virtual public A
	{
		OESS_SERIALIZER( B )
	private :
		std::string	m_b;

	public :
		B()
			{}
		B( const std::string & b )
			:	m_b( b )
			{}
		virtual ~B()
			{}
	};

class	C
	:	virtual public A
	{
		OESS_SERIALIZER( C )
	private :
		std::string	m_c;

	public :
		C()
			{}
		C( const std::string & c )
			:	m_c( c )
			{}
		virtual ~C()
			{}
	};

class	D
	:	virtual public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( D )
	private :
		std::string	m_d;

	public :
		D()
			{}
		D( const std::string & d )
			:	m_d( d )
			{}
		virtual ~D()
			{}
	};

class	E
	:	public D
	,	virtual public B
	,	virtual public C
	{
		OESS_SERIALIZER( E )
	private :
		std::string	m_e;

	public :
		E()
			{}
		E( const std::string & e )
			:	D( "ThisIsE+D" )
			,	A( "ThisIsE+A" )
			,	B( "ThisIsE+B" )
			,	C( "ThisIsE+C" )
			{}
		virtual ~E()
			{}
	};

#include "main.ddl.cpp"

std::string
serialize( const E & e )
	{
		std::string receiver;
		oess_1::io::obstring_t	stream( receiver );
		oess_1::stdsn::oent_no_markers_t oent( stream );

		oent << e;

		return receiver;
	}

class	test_thread_t
	{
	private :
		const E *	m_e;
		const std::string *	m_e_image;
		int *	m_error_count;

	public :
		test_thread_t()
			:	m_e( 0 )
			,	m_e_image( 0 )
			,	m_error_count( 0 )
			{}

		void
		start(
			const E & e,
			const std::string & e_image,
			int & error_count )
			{
				m_e = &e;
				m_e_image = &e_image;
				m_error_count = &error_count;

				ACE_Thread_Manager::instance()->spawn(
						reinterpret_cast< ACE_THR_FUNC >(
								&test_thread_t::thread_func ),
						this );
			}

		static void
		thread_func( test_thread_t * t )
			{
				t->body();
			}

	protected :
		void
		body()
			{
				for( int i = 0; i != 100000; ++i )
					{
						std::string s = serialize( *m_e );
						if( s != *m_e_image )
							(*m_error_count)++;
					}
			}
	};

int
main( int, char ** )
	{
		int error_count = 0;
		try
			{
				E e( "TestString" );
				std::string e_image( serialize( e ) );

				int i;

				test_thread_t threads[ 3 ];
				for( i = 0; i != sizeof( threads ) / sizeof( threads[ 0 ] ); ++i )
					threads[ i ].start( e, e_image, error_count );

				ACE_Thread_Manager::instance()->wait();

				std::cout << "error_count: " << error_count << std::endl;
			}
		catch( const std::exception & x )
			{
				std::cout << "Oops! " << x.what() << std::endl;
				return 1;
			}

		return error_count;
	}

