/*

Copyright (c) 2002-2005, Yauheni Akhotnikau
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

- The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.

*/

/*!
	\file
	\brief Штатная реализация интерфейса %entity_stream_t.
*/
#if !defined( _OESS_1__DB__STORAGE__IMPL__STD_ENTITY_STREAM_HPP_ )
#define _OESS_1__DB__STORAGE__IMPL__STD_ENTITY_STREAM_HPP_

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

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

namespace oess_1 {

namespace db {

namespace storage {

namespace impl {

//
// stream_desc_t
//

/*!
	\since v.1.4.0
	\brief Описатель потока хранилища.

	Поток представляет из себя двухсвязный список объектов
	stream_item_t. Описатель потока хранит ссылки на первый и
	последний элементы этого списка, т.е. потока.
*/
class	stream_desc_t
	:	public oess_1::stdsn::serializable_t
	{
		typedef oess_1::stdsn::serializable_t base_type_t;
		OESS_SERIALIZER( stream_desc_t )

	public :
		//! Конструктор по-умолчанию.
		stream_desc_t();
		//! Конструктор копирования.
		stream_desc_t(
			const stream_desc_t & o );
		virtual ~stream_desc_t();

		//! Оператор копирования.
		stream_desc_t &
		operator=(
			const stream_desc_t & o );

		//! Идентификатор цепочки первого элемента списка.
		chain_id_t
		first() const;

		//! Установить идентификатор цепочки первого элемента.
		void
		set_first(
			const chain_id_t & chain );

		//! Идентификатор цепочки последнего элемента списка.
		chain_id_t
		last() const;

		//! Установить идентификатор цепочки последнего элемента списка.
		void
		set_last(
			const chain_id_t & chain );

	private :
		//! Идентификатор цепочки первого элемента списка.
		chain_id_t	m_first;
		//! Идентификатор цепочки последнего элемента списка.
		chain_id_t	m_last;
	};

//
// stream_item_t
//

/*!
	\since v.1.4.0
	\brief Один элемент потока сущностей.

	Поток в хранилище представляет из себя двухсвязный список
	объектов stream_item_t. Каждый stream_item_t содержит ссылку на
	само значение сущности, которое сохраняется в виде отдельной
	цепочки в хранилище.
*/
class	stream_item_t
	:	public oess_1::stdsn::serializable_t
	{
		typedef oess_1::stdsn::serializable_t base_type_t;
		OESS_SERIALIZER( stream_item_t )

	public :
		//! Конструктор по-умолчанию.
		stream_item_t();
		//! Конструктор для случая добавления элемента в конец списка.
		stream_item_t(
			//! Описатель всего потока.
			const chain_id_t & description_chain,
			//! Предыдущий элемент.
			const chain_id_t & prev,
			//! Размер сущности в байтах.
			oess_1::uint_t & length,
			//! Идентификатор цепочки со значением сущности.
			const chain_id_t & entity_chain );
		//! Конструктор копирования.
		stream_item_t(
			const stream_item_t & o );
		virtual ~stream_item_t();

		enum
			{
				//! Ограничение на размер двоичного образа этого объекта.
				/*!
					\note Это приблизительное значение, которое
						гарантированно больше образа объекта.
				*/
				length_limit = 32
			};
	
		//! Оператор копирования.
		stream_item_t &
		operator=(
			const stream_item_t & o );

		//! Получить ссылку на описатель всего потока.
		chain_id_t
		description_chain() const;

		//! Установить ссылку на описатель всего потока.
		void
		set_description_chain(
			const chain_id_t & chain );

		//! Получить ссылку на предыдущий элемент потока.
		chain_id_t
		prev() const;

		//! Установить ссылку на следующий элемент потока.
		void
		set_prev(
			const chain_id_t & chain );

		//! Получить ссылку на следующий элемент потока.
		chain_id_t
		next() const;

		//! Установить ссылку на следующий элемент потока.
		void
		set_next(
			const chain_id_t & chain );

		//! Установить параметры сохраненной сущности.
		void
		set_entity_params(
			//! Размер сущности в байтах.
			oess_1::uint_t length,
			//! Идентификатор цепочки, в которой сохранена сущность.
			const chain_id_t & chain );

		//! Получить размер сущности в байтах.
		oess_1::uint_t
		length() const;

		//! Получить идентификатор цепочки, в которой сохранена сущность.
		const chain_id_t &
		entity_chain() const;

	private :
		//! Описатель всего потока.
		chain_id_t	m_description_chain;
		//! Предыдущий элемент.
		chain_id_t	m_prev;
		//! Следующий элемент.
		chain_id_t	m_next;
		//! Размер сущности в байтах.
		oess_1::uint_t	m_length;
		//! Идентификатор цепочки со значением сущности.
		chain_id_t	m_entity_chain;
	};

/*
** std_entity_stream_t
*/

/*!
	\brief Штатная реализация интерфейса %entity_stream_t.

	\attention Данный класс не расчитан на перезагрузку описания
		потока из хранилища после отката транзакции. Он однократно
		загружает описание потока при своем создании и затем держит
		это описание в ОП. Поэтому при откате транзакции объект
		std_entity_stream_t нужно уничтожить, а вместо него создать
		новый, который загрузит из БД актуальное значение.
*/
class	std_entity_stream_t
	:	public entity_stream_t
	{
	public :
		//! Инициализирующий конструктор.
		std_entity_stream_t(
			//! Хранилище, в котором физически расположен поток.
			chain_storage_t & storage,
			//! Назначенный этому потоку идентификатор.
			oess_1::uint_t id,
			//! Идентификатор цепочки, в которой храниться описатель
			//! этого потока сущностей.
			const chain_id_t & description_chain );
		virtual ~std_entity_stream_t();

	//! \name Реализация унаследованных методов.
	//! \{
		virtual oess_1::uint_t
		id() const;

		virtual chain_id_t
		entity_create(
			oess_1::io::istream_t & ent_value,
			oess_1::uint_t ent_size );

		virtual void
		entity_load(
			const chain_id_t & ent_id,
			oess_1::io::ostream_t & ent_value ) const;

		virtual void
		entity_update(
			const chain_id_t & ent_id,
			oess_1::io::istream_t & ent_value,
			oess_1::uint_t ent_size );

		virtual void
		entity_destroy(
			const chain_id_t & ent_id );

		virtual void
		entity_destroy_all();

		virtual chain_id_t 
		entity_find_next(
			const chain_id_t & ent_id ) const;
	//! \}

	private :
		//! Хранилище, в котором физически расположен поток.
		chain_storage_t &	m_storage;
		//! Назначенный этому потоку идентификатор.
		oess_1::uint_t m_id;
		//! Идентификатор цепочки, в которой храниться описатель
		//! этого потока сущностей.
		chain_id_t	m_description_chain;

		//! Загруженное из хранилища описание потока.
		stream_desc_t	m_desc;
	};

} /* namespace impl */

} /* namespace storage */

} /* namespace db */

} /* namespace oess_1 */

#endif

