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

#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/file/h/file.hpp>

#include <oess_1/db/storage/h/chain_storage.hpp>
#include <oess_1/db/storage/h/page_index_calculator.hpp>

#include <oess_1/db/storage/trx/h/types.hpp>

const std::string initial_value = "This is initial value of first chain";
const std::string physic_name = "test/storage/create/test.normal";

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

		oess_1::io::mem_buf_t buf;
		oess_1::db::storage::chain_id_t first_chain;

		buf.write( initial_value.data(), initial_value.size() );
		buf.set_pos( 0 );

		std::auto_ptr< oess_1::db::storage::chain_storage_t >
				storage( oess_1::db::storage::create_chain_storage(
						physic_name, config, buf, buf.size(), first_chain ) );

		oess_1::db::storage::page_index_calculator_t calculator(
				config.page_size(), config.chain_link_size() );
		if( calculator.first_chain_id() != first_chain )
			throw std::runtime_error(
					std::string( "unexpected first_chain_id: " ) +
					cpp_util_2::slexcast( first_chain ) +
					", expected first_chain_id: " +
					cpp_util_2::slexcast(
							calculator.first_chain_id() ) );

		std::string precise_value;
		oess_1::io::obstring_t precise_value_stream( precise_value );
		storage->chain_load( first_chain, precise_value_stream,
				initial_value.length() );
		if( initial_value != precise_value )
			throw std::runtime_error(
					std::string( "value differs: " ) +
					initial_value + ", " + precise_value );

		storage.reset();
	}

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

		oess_1::io::mem_buf_t buf;
		oess_1::db::storage::chain_id_t first_chain;

		std::auto_ptr< oess_1::db::storage::chain_storage_t >
				storage( oess_1::db::storage::open_chain_storage(
						physic_name, config, true, false,
						buf, oess_1::db::storage::no_chain_length_limit,
						first_chain ) );

		oess_1::db::storage::page_index_calculator_t calculator(
				config.page_size(), config.chain_link_size() );
		if( calculator.first_chain_id() != first_chain )
			throw std::runtime_error(
					std::string( "unexpected first_chain_id: " ) +
					cpp_util_2::slexcast( first_chain ) +
					", expected first_chain_id: " +
					cpp_util_2::slexcast(
							calculator.first_chain_id() ) );

		if( buf.size() != config.chain_link_size() )
			throw std::runtime_error(
					std::string( "unexpected size of first_chain object: " ) +
					cpp_util_2::slexcast( buf.size() ) );

		std::string expected_value( initial_value );
		while( expected_value.size() < buf.size() )
			expected_value += '\0';

		std::string precise_value( buf.ptr(), buf.size() );
		if( expected_value != precise_value )
			throw std::runtime_error(
					std::string( "value differs: " ) +
					expected_value + ", " + precise_value );
	}

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

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

void
test_create_and_destroy_with_snapshots()
	{
		const std::string test_name = "test_create_and_destroy_with_snapshots";

		test_normal_create();

		oess_1::db::storage::trx::trace_file_number_t snapshots[] =
				{ 1, 10, 100 };

		{
			oess_1::file::file_t f;

			for( unsigned int i = 0;
					i != sizeof( snapshots ) / sizeof( snapshots[ 0 ] ); ++i )
				{
					f.create( oess_1::db::storage::trx::create_snapshot_file_name(
							physic_name, snapshots[ i ] ) );
					f.close();
					f.create( oess_1::db::storage::trx::create_snapshot_file_name(
							physic_name, snapshots[ i ] ) );
					f.close();
					f.create( oess_1::db::storage::trx::create_snapshot_file_name(
							physic_name, snapshots[ i ] ) );
					f.close();
				}
		}

		test_normal_destroy();

		for( unsigned int i = 0;
				i != sizeof( snapshots ) / sizeof( snapshots[ 0 ] ); ++i )
			{
				std::string snapshot_file(
						oess_1::db::storage::trx::create_snapshot_file_name(
								physic_name, snapshots[ i ] ) );

				if( oess_1::file::file_t::is_file_exists( snapshot_file ) )
					throw std::runtime_error( test_name + " FAILED: "
							"snapshot file still exists: " + snapshot_file );
			}
	}

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

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

		return 2;
	}
