/*

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/inout_templ.hpp>
#include <oess_1/stdsn/h/ent_no_markers.hpp>

struct	compression_info_t
:	public oess_1::stdsn::serializable_t
{
	OESS_SERIALIZER( compression_info_t )
	public :
		const std::string	default_algorithm;
		const oess_1::uchar_t default_level;

		std::string	m_algorithm;
		oess_1::uchar_t	m_level;

		compression_info_t()
		:	default_algorithm( "gzip-inflate" )
		,	default_level( 5 )
		,	m_algorithm( default_algorithm )
		,	m_level( default_level )
		{}
		virtual ~compression_info_t()
		{}

		compression_info_t &
		operator=( const compression_info_t & o )
		{
			if( &o != this )
			{
				m_algorithm = o.m_algorithm;
				m_level = o.m_level;
			}
			return *this;
		}
};

std::ostream &
operator<<( std::ostream & to, const compression_info_t & what )
{
	return ( to << "{compression_info_t {m_algorithm "
		<< what.m_algorithm
		<< "} {m_level "
		<< static_cast< unsigned int >( what.m_level )
		<< "} }" );
}

struct	signature_info_t
:	public oess_1::stdsn::serializable_t
{
	OESS_SERIALIZER( signature_info_t )
	public :
		const std::string	default_algorithm;

		std::string	m_algorithm;

		signature_info_t()
		:	default_algorithm( "md5" )
		,	m_algorithm( default_algorithm )
		{}
		virtual ~signature_info_t()
		{}

		signature_info_t &
		operator=( const signature_info_t & o )
		{
			if( &o != this )
			{
				m_algorithm = o.m_algorithm;
			}
			return *this;
		}
};

std::ostream &
operator<<( std::ostream & to, const signature_info_t & what )
{
	return ( to << "{signature_info_t {m_algorithm "
		<< what.m_algorithm
		<< "} }" );
}

struct	compression_and_signature_t
:	public oess_1::stdsn::serializable_t
{
	OESS_SERIALIZER( compression_and_signature_t )
	public :
		const oess_1::uchar_t	no_compression;
		const oess_1::uchar_t compression_used;

		const oess_1::uchar_t	no_signature;
		const oess_1::uchar_t signature_used;

		oess_1::uchar_t	m_is_compression_used;
		compression_info_t	m_compression;

		oess_1::uchar_t	m_is_signature_used;
		signature_info_t	m_signature;

		compression_and_signature_t()
		:	no_compression( 0 )
		,	compression_used( 1 )
		,	no_signature( 0 )
		,	signature_used( 1 )
		,	m_is_compression_used( no_compression )
		,	m_is_signature_used( no_signature )
		{}
		virtual ~compression_and_signature_t()
		{}
};

std::ostream &
operator<<( std::ostream & to,
	const compression_and_signature_t & what )
{
	return ( to << "{compression_and_signature_t "
		<< "{m_is_compression_used "
		<< static_cast< unsigned int >( what.m_is_compression_used )
		<< "} {m_compression "
		<< what.m_compression
		<< "} {m_is_signature_used "
		<< static_cast< unsigned int >( what.m_is_signature_used )
		<< "} {m_signature "
		<< what.m_signature
		<< "} }" );
}

#include "main.ddl.cpp"

void
pack_and_unpack(
	const compression_and_signature_t & what,
	compression_and_signature_t & unpacked )
{
	std::cout << "***\n""pack: " << what << std::endl;

	oess_1::io::mem_buf_t buf;
	oess_1::stdsn::oent_no_markers_t to( buf );
	to << what;
	std::cout << "buffer size: " << buf.size() << std::endl;

	buf.set_pos( 0 );
	oess_1::stdsn::ient_no_markers_t from( buf );
	from >> unpacked;

	std::cout << "unpacked: " << unpacked << std::endl;
}

void
do_test()
{
	compression_and_signature_t v1, v2;
std::cout << "do_test 1" << std::endl;
	pack_and_unpack( v1, v2 );

	v1.m_is_compression_used = v1.compression_used;
std::cout << "do_test 2" << std::endl;
	pack_and_unpack( v1, v2 );

	v1.m_compression.m_algorithm = "bzip2";
std::cout << "do_test 3" << std::endl;
	pack_and_unpack( v1, v2 );

	v1.m_is_compression_used = v1.no_compression;
	// Сейчас v2.m_compression.m_algorithm содержит "bzip2".
	// При сериализации v1.m_compression не сохраняется, но
	// после десериализации v2.m_compression.m_algorithm
	// должен быть равен compression_t::default_algorithm.
std::cout << "do_test 4" << std::endl;
	pack_and_unpack( v1, v2 );

	v1.m_is_signature_used = v1.signature_used;
std::cout << "do_test 5" << std::endl;
	pack_and_unpack( v1, v2 );

	v1.m_signature.m_algorithm = "sha1";
std::cout << "do_test 6" << std::endl;
	pack_and_unpack( v1, v2 );

	v1.m_is_signature_used = v1.no_signature;
	// Сейчас v2.m_signature.m_algorithm содержит "sha1".
	// При сериализации v1.m_signature не сохраняется, но
	// после десериализации v2.m_signature.m_algorithm
	// должен быть равен signature_t::default_algorithm.
std::cout << "do_test 7" << std::endl;
	pack_and_unpack( v1, v2 );
}

int
main( int, char ** )
{
	try
	{
		do_test();
	}
	catch( const std::exception & x )
	{
		std::cerr << x.what() << std::endl;
	}
	return 0;
}
