/*
 * Пример, который копирует содержимое одной БД в новую БД.
 */

#include <algorithm>
#include <functional>
#include <iostream>

#include <ace/OS_main.h>

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

#include <oess_1/db/cln/h/local_db.hpp>

/*
 * Предикат для std::for_each.
 * Выполняет копирование содержимого очередного слайса БД.
 */
class slice_copier_t
	:	public std::unary_function< const std::string &, void >
	{
	private :
		// Откуда берем содержимое.
		oess_1::db::cln::db_t & m_source_db;
		// Куда помещаем.
		oess_1::db::cln::db_t & m_dest_db;

		void
		copy_slice_content( const std::string & slice_name )
			{
				oess_1::io::mem_buf_t buffer;
				unsigned int objects_copied = 0;
				unsigned int bytes_copied = 0;

				oess_1::ent_id_t ent;
				while( ( ent = m_source_db.ent_find_next(
								slice_name,
								ent ) ) )
					{
						buffer.change_size( 0 );
						oess_1::uint_t ent_size = m_source_db.ent_raw_load(
								ent, buffer );

						buffer.set_pos( 0 );
						oess_1::ent_id_t copied_ent = m_dest_db.ent_raw_create(
								slice_name,
								buffer,
								ent_size );

						++objects_copied;
						bytes_copied += ent_size;

						std::cout << slice_name << ": " << ent
								<< " (" << ent_size << " bytes) -> "
								<< copied_ent << std::endl;
					}

				std::cout << slice_name << ": "
						<< objects_copied << " objects, "
						<< bytes_copied << " bytes copied"
						<< std::endl;
			}

	public :
		slice_copier_t(
			oess_1::db::cln::db_t & source_db,
			oess_1::db::cln::db_t & dest_db )
			:	m_source_db( source_db )
			,	m_dest_db( dest_db )
			{}

		result_type
		operator()( argument_type slice_name )
			{
				std::cout << slice_name << ": creating" << std::endl;
				m_dest_db.slice_create( slice_name );

				copy_slice_content( slice_name );
			}
	};

void
copy_opened_db_content(
	oess_1::db::cln::db_t & source_db,
	oess_1::db::cln::db_t & dest_db )
	{
		// Для начала получаем список разделов для копирования.
		std::set< std::string > slices = source_db.slice_names();
		if( !slices.empty() )
			{
				// Теперь копируем каждый раздел поочереди.
				std::for_each(
						slices.begin(),
						slices.end(),
						slice_copier_t( source_db, dest_db ) );
			}
		else
			std::cout << "no slices to copy" << std::endl;
	}

void
copy_db_content(
	const std::string & source_db_name,
	const std::string & dest_db_name )
	{
		// Открываем старую БД.
		oess_1::db::cln::local_db_t source_db(
				source_db_name,
				oess_1::db::cln::local_db_t::no_overwrite |
						oess_1::db::cln::local_db_t::read_only_mode );

		// Создаем новую БД.
		// В качестве конфигурации используем конфигурационный
		// файл от старой БД.
		oess_1::db::storage::config_t empty_config;
		oess_1::db::cln::local_db_t dest_db(
				dest_db_name,
				oess_1::db::storage::load_cfg_file(
						empty_config.make_cfg_file_name( source_db_name ) ),
				oess_1::db::cln::local_db_t::auto_create );

		copy_opened_db_content(
				*source_db.query_db(),
				*dest_db.query_db() );
	}

int
main( int argc, char ** argv )
	{
		if( 3 != argc )
			{
				std::cerr << "sample_db_content_copy <old_db> <new_db>"
						<< std::endl;
				return 1;
			}

		try
			{
				copy_db_content( argv[ 1 ], argv[ 2 ] );
			}
		catch( const std::exception & x )
			{
				std::cerr << "exception caght: " << x.what() << std::endl;
				return 2;
			}

		return 0;
	}

