/*

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 Стандартные классы для управления сериализацией
		сущностей.
*/

#if !defined( _OESS_1__STDSN__ENT_STD_HPP_ )
#define _OESS_1__STDSN__ENT_STD_HPP_

#include <auto_ptr_3/h/obj_ptr.hpp>

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

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

namespace oess_1 {

namespace stdsn {

class	operation_history_t;

/*!
	\since v.1.2.0
	\brief Метка отсутствия сериализованного представления
		опционального атрибута.
*/
const oess_1::uchar_t	opt_attr_missing_flag = 0;

/*!
	\since v.1.2.0
	\brief Метка присутствия сериализованного представления
		опционального атрибута.
*/
const oess_1::uchar_t	opt_attr_present_flag = 1;

//
// ient_std_t
//

/*!
	\brief Реализация интерфейса ient_t для случая, когда во
	входном потоке вообще нет маркеров.
*/
class	OESS_1__STDSN__TYPE	ient_std_t :
	public ient_t
{
	public :
		ient_std_t(
			oess_1::io::istream_t & stream );
		virtual ~ient_std_t();

		virtual bool
		obj_start(
			const void * object,
			const std::string * type_name,
			const std::string & scheme );

		virtual void
		obj_finish(
			const void * object,
			const std::string * type_name );

		virtual void
		obj_complete(
			const void * object,
			const std::string * type_name );

		//! Имя типа сохранено в потоке в виде строки.
		virtual void
		unpack_type_name(
			std::string & type_name );

		virtual oess_1::io::istream_t &
		query_stream();

		/*!
			Метка существования опционального атрибута
			представляется элементом типа
			oess_1::uchar_t со значением
			oess_1::stdsn::opt_attr_missing_flag или
			oess_1::stdsn::opt_attr_existence_flag.
		*/
		virtual bool
		check_optional_attr_existence(
			const std::string & attr_name );

		/*!
			Во входном потоке расширение сериализовано и сохранено
			в виде одной строки (std::string). Метод извлекает из
			входного потока строку с расширением и возвращает указатель
			на динамически созданный объект iextension_std_t.
		*/
		virtual iextension_t *
		extension_start();

		/*!
			Ничего не делает.
		*/
		virtual void
		extension_finish(
			iextension_t & extension );

	private :
		oess_1::io::istream_t &	m_stream;

		//! Информация о том, какие объекты уже были сериализованы.
		/*!
			\since v.1.2.0
		*/
		auto_ptr_3::obj_ptr_t< operation_history_t >	m_history;

	private :
	//! \name Защита от копирования.
	//! \{
		ient_std_t(
			const ient_std_t & );
		ient_std_t &
		operator=(
			const ient_std_t & );
	//! \}
};

//
// iextension_std_t
//

/*!
	\since v.1.2.0
	\brief Реализация интерфейса iextension_t для случая, когда во
	входном потоке вообще нет маркеров.

	Для того, чтобы не дублировать код по разбору входного потока
	из ient_std_t в iextension_std_t, объект
	iextension_no_marker_t создает собственный объект ient_no_marker_t
	и делегирует свою функциональность этому объекту.
*/
class	OESS_1__STDSN__TYPE	iextension_std_t
:	public iextension_t
{
	public :
		iextension_std_t(
			//! Сериализованое представление расширения.
			const std::string & data );
		virtual ~iextension_std_t();

	//! \name Реализация унаследованных методов.
	//! \{
		virtual bool
		obj_start(
			const void * object,
			const std::string * type_name,
			const std::string & scheme );

		virtual void
		obj_finish(
			const void * object,
			const std::string * type_name );

		virtual void
		obj_complete(
			const void * object,
			const std::string * type_name );

		virtual void
		unpack_type_name(
			std::string & type_name );

		virtual oess_1::io::istream_t &
		query_stream();

		virtual bool
		check_optional_attr_existence(
			const std::string & attr_name );

		virtual iextension_t *
		extension_start();

		virtual void
		extension_finish(
			iextension_t & extension );
	//! \}

		/*!
			\return \a true, если полученная в конструкторе строка не
				пуста.
		*/
		virtual bool
		is_present() const;

		virtual void
		unpack_opaque( unknown_extension_t & ext );

	private :
		//! Двоичное представление расширения.
		const std::string	m_data;
		//! Входной поток для расширения.
		oess_1::io::ibstring_t	m_stream;
		//! Объект, который реально занимается разбором
		//! входного потока с расширением.
		ient_std_t	m_ient;

	private :
	//! \name Защита от копирования.
	//! \{
		iextension_std_t(
			const iextension_std_t & );
		iextension_std_t &
		operator=(
			const iextension_std_t & );
	//! \}
};

//
// oent_std_t
//

/*!
	\brief Реализация интерфейса oent_t для случая, когда в
	выходном потоке вообще нет маркеров.
*/
class	OESS_1__STDSN__TYPE	oent_std_t :
	public oent_t
{
	public :
		oent_std_t( oess_1::io::ostream_t & stream );
		virtual ~oent_std_t();

		virtual bool
		obj_start(
			const void * object,
			const std::string * type_name,
			const std::string & scheme );

		virtual void
		obj_finish(
			const void * object,
			const std::string * type_name );

		virtual void
		obj_complete(
			const void * object,
			const std::string * type_name );

		//! Имя типа сохраняется в потоке в виде строки.
		virtual void
		pack_type_name(
			const std::string & type_name,
			const std::string & /*type_scheme*/ );

		virtual oess_1::io::ostream_t &
		query_stream();

		/*!
			Метка существования опционального атрибута
			представляется элементом типа
			oess_1::uchar_t со значением
			oess_1::stdsn::opt_attr_missing_flag или
			oess_1::stdsn::opt_attr_existence_flag.
		*/
		virtual bool
		set_optional_attr_existence(
			const std::string & attr_name,
			bool existence );

		/*!
			\return динамически созданный объект
				oextension_std_t.
		*/
		virtual oextension_t *
		extension_start();

		/*!
			Для сохранения сериализованого представления в потоке
			у объекта \a extension вызывается метод pack().
		*/
		virtual void
		extension_finish(
			oextension_t & extension );

	private :
		oess_1::io::ostream_t &	m_stream;

		//! Информация о том, какие объекты уже были сериализованы.
		/*!
			\since v.1.2.0
		*/
		auto_ptr_3::obj_ptr_t< operation_history_t >	m_history;

	private :
	//! \name Защита от копирования.
	//! \{
		oent_std_t(
			const oent_std_t & );
		oent_std_t &
		operator=(
			const oent_std_t & );
	//! \}
};

//
// oextension_std_t
//

/*!
	\brief Реализация интерфейса %oextension_t для случая, когда в
	выходном потоке вообще нет маркеров.

	Для того, чтобы не дублировать код по разбору входного потока
	из oent_std_t в oextension_std_t, объект
	oextension_no_marker_t создает собственный объект oent_no_marker_t
	и делегирует свою функциональность этому объекту.
*/
class	OESS_1__STDSN__TYPE	oextension_std_t
:	public oextension_t
{
	public :
		oextension_std_t();
		virtual ~oextension_std_t();

	//! \name Унаследованные методы.
	//! \{
		virtual bool
		obj_start(
			const void * object,
			const std::string * type_name,
			const std::string & scheme );

		virtual void
		obj_finish(
			const void * object,
			const std::string * type_name );

		virtual void
		obj_complete(
			const void * object,
			const std::string * type_name );

		virtual void
		pack_type_name(
			const std::string & type_name,
			const std::string & /*type_scheme*/ );

		virtual oess_1::io::ostream_t &
		query_stream();

		virtual bool
		set_optional_attr_existence(
			const std::string & attr_name,
			bool existence );

		virtual oextension_t *
		extension_start();

		virtual void
		extension_finish(
			oextension_t & extension );

		/*!
			Сохраняет все расширение в виде одной строки (std::string).
		*/
		virtual void
		pack( oess_1::io::ostream_t & to ) const;

		virtual void
		pack_opaque( const unknown_extension_t & ext );

	private :
		//! Сериализованное представление расширения.
		std::string	m_data;
		//! Вспомогательный выходной поток для накопления
		//! сериализованного представления расширения в %m_data.
		oess_1::io::obstring_t	m_stream;
		//! Объект, который реально занимается сериализацией.
		oent_std_t	m_oent;

	private :
	//! \name Защита от копирования.
	//! \{
		oextension_std_t(
			const oextension_std_t & );
		oextension_std_t &
		operator=(
			const oextension_std_t & );
	//! \}
};

} /* namespace stdsn */

} /* namespace oess_1 */

#endif

