/*
	Проверка создания новой БД.
*/

#include <iostream>
#include <stdexcept>

#include <auto_ptr_3/h/obj_ptr.hpp>

#include <cpp_util_2/h/lexcast.hpp>

#include <oess_1/defs/h/ex.hpp>

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

#include <oess_1/db/storage/h/stream_storage.hpp>

const std::string physic_name = "test/stream_storage/create/test.normal";

void
test_normal_create()
	{
		const oess_1::db::storage::config_t config;

		auto_ptr_3::obj_ptr_t< oess_1::db::storage::stream_storage_t >
				storage( oess_1::db::storage::create_stream_storage(
						physic_name, config ) );

		storage->trans_start();

		// В созданном хранилище не должно быть потоков.
		unsigned int stream_count = storage->stream_names().size();
		if( stream_count )
			throw std::runtime_error( "test_normal_create FAILED!: "
					"expected stream_count: 0, real stream_count: " +
					cpp_util_2::slexcast( stream_count ) );	

		storage->stream_create( "bbb" );
		oess_1::db::storage::entity_stream_t & stream_bbb =
				storage->stream_get( "bbb" );
		if( 1 != stream_bbb.id() )
			throw std::runtime_error( "test_normal_create FAILED!: "
					"expected stream id: 1, real stream id: " +
					cpp_util_2::slexcast( stream_bbb.id() ) );	

		storage->stream_create( "aaa" );
		oess_1::db::storage::entity_stream_t & stream_aaa =
				storage->stream_get( "aaa" );
		if( 2 != stream_aaa.id() )
			throw std::runtime_error( "test_normal_create FAILED!: "
					"expected stream id: 2, real stream id: " +
					cpp_util_2::slexcast( stream_aaa.id() ) );	

		storage->trans_commit();
	}

void
test_trx_rollback(
	oess_1::db::storage::stream_storage_t & storage )
	{
		storage.trans_start();

		storage.stream_create( "ccc" );
		storage.stream_create( "ddd" );

		try
			{
				storage.stream_create( "aaa" );
				throw std::runtime_error( "test_trx_rollback FAILED!: "
						"stream 'aaa' created again" );
			}
		catch( const oess_1::logic_ex_t & x )
			{}

		storage.stream_destroy( "aaa" );
		storage.stream_create( "aaa" );
		if( 2 == storage.stream_get( "aaa" ).id() )
			throw std::runtime_error( "test_trx_rollback FAILED!: "
					"stream id for 'aaa' is 2" );

		if( 4 != storage.stream_names().size() )
			throw std::runtime_error( "test_trx_rollback FAILED!: "
					"stream count is not 4" );

		storage.trans_rollback();

		if( 2 != storage.stream_names().size() )
			throw std::runtime_error( "test_trx_rollback FAILED!: "
					"stream count is not 2" );
		if( storage.stream_is_exists( "ccc" ) )
			throw std::runtime_error( "test_trx_rollback FAILED!: "
					"stream 'ccc' exists!" );	
		if( storage.stream_is_exists( "ddd" ) )
			throw std::runtime_error( "test_trx_rollback FAILED!: "
					"stream 'ddd' exists!" );	
	}

void
test_normal_open()
	{
		const oess_1::db::storage::config_t config;

		auto_ptr_3::obj_ptr_t< oess_1::db::storage::stream_storage_t >
				storage( oess_1::db::storage::open_stream_storage(
						physic_name, config, false, true ) );

		unsigned int stream_count = storage->stream_names().size();
		if( stream_count != 2 )
			throw std::runtime_error( "test_normal_open FAILED!: "
					"expected stream_count: 2, real stream_count: " +
					cpp_util_2::slexcast( stream_count ) );	
		if( !storage->stream_is_exists( "aaa" ) )
			throw std::runtime_error( "test_normal_open FAILED!: "
					"stream 'aaa' not exists!" );	
		if( !storage->stream_is_exists( "bbb" ) )
			throw std::runtime_error( "test_normal_open FAILED!: "
					"stream 'bbb' not exists!" );	

		test_trx_rollback( *storage );
	}

void
test_normal_destroy()
	{
		oess_1::db::storage::destroy_stream_storage( physic_name );

		if( oess_1::db::storage::is_stream_storage_exists( physic_name ) )
			throw std::runtime_error(	
					std::string( "test_normal_destroy FAILED:"
							"storage still exists!" ) );
	}

int
main( int, char ** )
	{
		try
			{
				test_normal_create();
				test_normal_open();
				test_normal_destroy();

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

		return 2;
	}
