/*

oess_1: Object Entity Serialization & Stability
Yauheni A. Akhotnikau (C) 2002-2003
eao197@yahoo.com
-------------------------------------------------

Permission is granted to anyone to use this software for any purpose on any
computer system, and to redistribute it freely, subject to the following
restrictions:

1. This software is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

2. The origin of this software must not be misrepresented, either by
   explicit claim or by omission.

3. Altered versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

-------------------------------------------------

*/
#include <iostream>
#include <exception>
#include <map>

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

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

class	my_t :
	public oess_1::stdsn::serializable_t
{
	OESS_SERIALIZER( my_t )
	private :
		static int	m_global_counter;

		int	m_ordinal;
	public :
		my_t()
			:	m_ordinal( ++m_global_counter )
		{
			std::cout << m_ordinal << " my_t::my_t()" << std::endl;
		}
		virtual ~my_t()
		{
			std::cout << m_ordinal << " my_t::~my_t()" << std::endl;
		}

		void
		say() const
		{
			std::cout << m_ordinal << " my_t::say()" << std::endl;
		}
};

int	my_t::m_global_counter = 0;

class	my_ptr_t :
	public oess_1::stdsn::shptr_t
{
	OESS_SERIALIZER( my_ptr_t )
	OESS_1_SHPTR_IFACE( my_ptr_t, my_t,
		oess_1::stdsn::shptr_t )
};

bool
operator<( const my_ptr_t & o1, const my_ptr_t & o2 )
{
	return ( o1.get() < o2.get() );
}

class	my_cont_t :
	public oess_1::stdsn::serializable_t
{
	OESS_SERIALIZER( my_cont_t )
	private :
		typedef std::multimap< my_ptr_t, int > cont_t;
		cont_t	m_cont;

	public :
		my_cont_t()
		{
		}
		virtual ~my_cont_t()
		{
		}

		void
		show() const
		{
			for( cont_t::const_iterator
					it = m_cont.begin(),
					it_end = m_cont.end();
				it != it_end; ++it )
			{
				(*it).first->say();
			}
		}

		void
		add( const my_ptr_t & o )
		{
			static int i = 0;
			m_cont.insert( cont_t::value_type( o, ++i ) );
		}
};

#include "main.ddl.cpp"

void
do_test()
{
	oess_1::io::mem_buf_t buf;

	{
		my_ptr_t ptr( new my_t() );
		oess_1::stdsn::shptr_t empty;
		my_ptr_t ptr2( ptr );

		my_t * p = ptr.get();
		if( p )
			p->say();
		p = ptr2.get();
		if( p )
		{
			p->say();
			ptr2->say();
			(*ptr2).say();
		}

		oess_1::stdsn::oent_std_t oent( buf );
		oent << ptr << empty << ptr2;
		my_cont_t my_cont;
		my_cont.add( ptr );
		my_cont.add( ptr2 );
		my_cont.show();

		oent << my_cont;
	}

	std::cout << "buf size: " << buf.size() << std::endl;

	{
		buf.set_pos( 0 );
		my_ptr_t ptr;
		my_cont_t cont;

		oess_1::stdsn::ient_std_t ient( buf );

		while( !buf.eof() )
		{
			ient >> ptr;
			if( ptr.get() )
				ptr->say();
			else
				std::cout << "empty pointer" << std::endl;

			ient >> ptr;
			if( ptr.get() )
				ptr->say();
			else
				std::cout << "empty pointer" << std::endl;

			ient >> ptr;
			if( ptr.get() )
				ptr->say();
			else
				std::cout << "empty pointer" << std::endl;

			ient >> cont;
			cont.show();
		}
	}
}

int
main( int, char ** )
{
	try
	{
		do_test();

		return 0;
	}
	catch( std::exception & x )
	{
		std::cerr << x.what() << std::endl;
	}

	return 2;
}

