#include <iostream>
#include <stdexcept>

#include <cpp_util_2/h/lexcast.hpp>

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

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

#include <oess_1/stdsn/custom/ace/h/Date_Time.h>

class test_t
	:	public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( test_t )
	private :
		ACE_Date_Time m_d;

	public :
		test_t();
		test_t( const ACE_Date_Time & d );

		const ACE_Date_Time & get_date() const;
	};

test_t::test_t()
	{}

test_t::test_t( const ACE_Date_Time & d )
	:	m_d( d )
	{}

const ACE_Date_Time &
test_t::get_date() const 
	{
		return m_d;
	}

#include "date_time.ddl.cpp"

#define CHECK_EQUAL(a,b)\
if( a != b )\
	throw std::runtime_error( "expected: " + \
			cpp_util_2::slexcast( static_cast< long >( a ) ) + \
			", actual: " + \
			cpp_util_2::slexcast( static_cast< long >( b ) ) )

void
do_test()
	{
		ACE_Date_Time test_date( 14, 11, 2005, 7, 58, 29 );

		const unsigned int representation_size =
				oess_1::io::bin_data_size_t< oess_1::short_t >::image_size +
				oess_1::io::bin_data_size_t< oess_1::char_t >::image_size +
				oess_1::io::bin_data_size_t< oess_1::char_t >::image_size +
				oess_1::io::bin_data_size_t< oess_1::char_t >::image_size +
				oess_1::io::bin_data_size_t< oess_1::char_t >::image_size +
				oess_1::io::bin_data_size_t< oess_1::char_t >::image_size +
				oess_1::io::bin_data_size_t< oess_1::int_t >::image_size +
				oess_1::io::bin_data_size_t< oess_1::char_t >::image_size;

		test_t orig( test_date );

		oess_1::io::mem_buf_t stream;
		oess_1::stdsn::oent_std_t ostream( stream );

		ostream << orig;

		if( representation_size != stream.size() )
			throw std::runtime_error( "binary representation size mismatch: "
					"expected: " +
					cpp_util_2::slexcast( representation_size ) +
					", actual size: " +
					cpp_util_2::slexcast( stream.size() ) );

		test_t actual;
		stream.set_pos( 0 );

		oess_1::stdsn::ient_std_t istream( stream );

		istream >> actual;

		CHECK_EQUAL( orig.get_date().year(), actual.get_date().year() );
		CHECK_EQUAL( orig.get_date().month(), actual.get_date().month() );
		CHECK_EQUAL( orig.get_date().day(), actual.get_date().day() );
		CHECK_EQUAL( orig.get_date().hour(), actual.get_date().hour() );
		CHECK_EQUAL( orig.get_date().minute(), actual.get_date().minute() );
		CHECK_EQUAL( orig.get_date().second(), actual.get_date().second() );
		CHECK_EQUAL( orig.get_date().microsec(), actual.get_date().microsec() );
		CHECK_EQUAL( orig.get_date().weekday(), actual.get_date().weekday() );
	}

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

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

		return 1;
	}

