/*

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__SCHEME__TYPES_HPP_ )
#define _OESS_1__SCHEME__TYPES_HPP_

#include <exception>

#include <oess_1/scheme/h/declspec.hpp>

#include <string>

#include <cpp_util_2/h/nocopy.hpp>

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

namespace oess_1 {

namespace scheme {

class	type_t;

//
// base_t
//

/*!
	\brief Интерфейс описания базового типа
*/
class	OESS_1__SCHEME__TYPE	base_t
{
	public :
		virtual ~base_t();

		virtual const type_t &
		query_type() const = 0;

		//! Является ли наследование виртуальным?
		virtual bool
		is_virtual() const = 0;

		//! Используется ли механизм subclassing_by_extension?
		/* \since v.1.2.0 */
		virtual bool
		is_extension_of() const = 0;
};

//
// cpp_mapping_t
//

/*!
	\brief Интерфейс описания отображения типа в C++
*/
class	OESS_1__SCHEME__TYPE	cpp_mapping_t {
	public :
		virtual ~cpp_mapping_t();

		//! Имя типа в C++.
		/*! Если имя не было определено в описании типа,
			то возвращается имя типа из DDL.
		*/
		virtual const std::string &
		query_name() const = 0;
};

//
// attr_cont_kind_t
//

/*!
	\brief Интерфейс описания детализации атрибута.

	От данного интерфейса производны интерфейсы для
	детализации вида атрибута (контейнер, параметры контейнера,
	размерность фиксированного вектора и т.д.).
*/
class	OESS_1__SCHEME__TYPE	attr_cont_kind_t {
	public :
		virtual ~attr_cont_kind_t();

		//! Определение типа детализации.
		virtual oess_1::int_t
		query_kind_id() const = 0;
};

//
// attr_type_t
//

/*!
	\brief Интерфейс описания типа атрибута.
*/
class	OESS_1__SCHEME__TYPE	attr_type_t {
	public :
		virtual ~attr_type_t();

		//! Тип атрибута.
		virtual const type_t &
		query_type() const = 0;

		//! Разновидность типа атрибута.
		enum type_kind_t {
			//! Атрибут-объект.
			e_value,
			//! Атрибут-указатель.
			e_ptr,
			//! Атрибут-указатель на расширение типа.
			e_extension
		};

		virtual type_kind_t
		query_type_kind() const = 0;

		//! Разновидность контейнера.
		virtual const attr_cont_kind_t &
		query_cont_kind() const = 0;
};

//
// attr_present_if_t
//

/*!
	\since v.1.2.0
	\brief Интерфейс описания предиката сериализации
		опционального атрибута.
*/
class	attr_present_if_t
:	private cpp_util_2::nocopy_t
{
	public :
		virtual ~attr_present_if_t();

		//! Получить предикат для C++.
		/*!
			\throws std::exception если значение для C++ не задано.
		*/
		virtual const std::string &
		cpp() const
		throw( std::exception ) = 0;

		//! Определено ли значение для C++.
		virtual bool
		is_cpp() const = 0;
};

//
// attr_default_t
//

/*!
	\since v.1.2.0
	\brief Интерфейс значения атрибута по-умолчанию.
*/
class	attr_default_t
:	private cpp_util_2::nocopy_t
{
	public :
		virtual ~attr_default_t();

		//! Получить значение по-умолчанию для C++.
		/*!
			\throws std::exception если значение для C++ не задано.
		*/
		virtual const std::string &
		cpp() const
		throw( std::exception ) = 0;

		//! Определено ли значение для C++.
		virtual bool
		is_cpp() const = 0;

		//! Является ли опциональным.
		virtual bool
		is_optional() const = 0;

		//! Получить предикат сериализации данного атрибута.
		/*!
			\throws std::exception если атрибут не является
				опциональным. В этом случае нет объекта
				attr_present_if_t.
		*/
		virtual const attr_present_if_t &
		present_if() const = 0;
};

//
// attr_t
//

/*!
	\brief Интейфейс описания атрибута.
*/
class	OESS_1__SCHEME__TYPE	attr_t {
	public :
		virtual ~attr_t();

		//! Имя атрибута.
		virtual const std::string &
		query_name() const = 0;

		//! Тип атрибута.
		virtual const attr_type_t &
		query_attr_type() const = 0;

		/*!
			\since v.1.2.0
			\brief Значение атрибута по-умолчанию.
			\return 0, если значение по-умолчанию не задано.
		*/
		virtual const attr_default_t *
		query_attr_default() const = 0;

		/*!
			\since v.1.2.0
			\brief Расширение, которому принадлежит данный атрибут.

			Т.е. показывает глубину вложенных тегов {extension}
			в DDL описании, на которой было сделано описание
			данного атрибута.

			\return 0, если атрибут не принадлежит расширению.
				1, если принадлежит расширению. 2, если
				принадлежит расширению расширения. И т.д.
		*/
		virtual unsigned int
		extension_level() const = 0;
};

//
// type_t
//

/*!
	\brief Интерфейс описания типа.
*/
class	OESS_1__SCHEME__TYPE	type_t {
	public :
		virtual ~type_t();

		//! Имя типа.
		virtual const std::string &
		query_name() const = 0;

		//! Является ли тип полностью определенным.
		virtual bool
		is_defined() const = 0;

		//! Является ли тип встроенным типом ObjESSty?
		virtual bool
		is_builtin() const = 0;

		//! Является ли тип абстрактным?
		virtual bool
		is_abstract() const = 0;

		/*!
			\since v.1.2.0
			\brief Является ли тип расширяемым?
		*/
		virtual bool
		is_extensible() const = 0;

		/*!
			\since v.1.2.0
			\brief Поддерживает ли тип subclassing_by_extension?
		*/
		virtual bool
		is_subclassing_by_extension() const = 0;

		/*!
			\since v.1.2.0
			\brief Произведен ли тип как раширение базового?

			\return true, если используется механизм
				subclassing_by_extension и данный тип произведен как
				расширение от своего базового.
		*/
		virtual bool
		is_derived_as_extension() const = 0;

		//! Определение общего количества базовых типов.
		virtual size_t
		query_base_count() const = 0;

		//! Доступ к базовому типу по номеру.
		/*! Нумерация начинается с 0. */
		virtual const base_t &
		query_base( size_t index ) const = 0;

		//! Найти базовый тип по имени.
		/*! Если тип не найден, то возвращается 0. */
		virtual const base_t *
		find_base( const std::string & name ) const = 0;

		//! Определение общего количества атрибутов.
		/*! \note Учитываются и все атрибуты во всех расширениях.
			\sa extension_attr_count(), extension_attr().
		*/
		virtual size_t
		query_attr_count() const = 0;

		//! Доступ к атрибуту по номеру.
		/*! Нумерация начинается с нуля.
			\note Данная функция дает доступ к общему списку атрибутов,
				в который входят и все атрибуты из всех расширений.
				Для доступа к атрибутам из конкретного расширения
				нужно использовать функции extension_attr_count(),
				extension_attr().
		*/
		virtual const attr_t &
		query_attr( size_t index ) const = 0;

		//! Найти атрибут по имени.
		/*! Если атрибут не найден, то возвращается 0. */
		virtual const attr_t *
		find_attr( const std::string & name ) const = 0;

		//! Доступ к отображению типа в C++.
		virtual const cpp_mapping_t &
		query_cpp_mapping() const = 0;

		//! Глубина определенных в типе расширений.
		/*! \since v.1.2.0
			\return 0, если у типа нет расширений. 1, если у типа
				только одно расширение. 2, если у типа два вложенных
				друг в друга расширения и т.д.
		*/
		virtual unsigned int
		extension_deep() const = 0;

		//! Количество атрибутов в указанном расширении.
		/*! \since v.1.2.0

			Если extension == 0, то возвращается количество
			атрибутов, которые не входят в расширения. */
		virtual unsigned int
		extension_attr_count( unsigned int extension ) const = 0;

		//! Получить атрибут по порядковому номеру в расширении.
		/*! \since v.1.2.0

			Если extension == 0, то возвращается атрибут, который
			не входит ни в одно из расширений.
		*/
		virtual const attr_t &
		extension_attr( unsigned int extension,
			unsigned int attr_index ) const = 0;
};

//
// pseudo_base_list_t
//

/*!
	Класс, который предоставляет доступ к списку базовых классов
	в стиле STL-контейнера.
*/
class	pseudo_base_list_t {
	private :
		const type_t &	m_type;

	public :
		inline
		pseudo_base_list_t( const type_t & t ) :
			m_type( t )
		{
		}

		class	const_iterator {
			friend class pseudo_base_list_t;
			private :
				const type_t *	m_type;
				size_t	m_index;

				inline
				const_iterator(
					const type_t & t,
					size_t index ) :
					m_type( &t ),
					m_index( index )
				{
				}

			public :
				inline
				const_iterator() :
					m_type( 0 ),
					m_index( 0 )
				{
				}

				inline
				const_iterator(
					const const_iterator & o ) :
					m_type( o.m_type ),
					m_index( o.m_index )
				{
				}

				inline const base_t &
				operator*() const {
					return m_type->query_base( m_index );
				}

				bool
				operator==( const const_iterator & o ) const {
					return ( m_type == o.m_type && m_index == o.m_index );
				}

				bool
				operator!=( const const_iterator & o ) const {
					return ( m_type != o.m_type || m_index != o.m_index );
				}

				const_iterator&
				operator++() {
					++m_index;
					return *this;
				}

				const_iterator
				operator++( int ) {
					return const_iterator( *m_type, m_index++ );
				}
		};

		inline const_iterator
		begin() const {
			return const_iterator( m_type, 0 );
		}

		inline const_iterator
		end() const {
			return const_iterator( m_type, m_type.query_base_count() );
		}
};

//
// pseudo_attr_list_t
//
/*!
	Класс, который предоставляет доступ к списку атрибутов
	в стиле STL-контейнера.
*/
class	pseudo_attr_list_t {
	private :
		//! Тип, доступ к атрибутам которого осуществляет данный объект.
		const type_t &	m_type;

	public :
		//! Инициализирующий конструктор.
		inline
		pseudo_attr_list_t(
			//! Тип, доступ к атрибутам которого
			//! осуществляет данный объект.
			const type_t & t )
			:	m_type( t )
		{
		}

		//! Класс константного итератора.
		class	const_iterator {
			friend class pseudo_attr_list_t;
			private :
				//! Тип, доступ к атрибутам которого
				//! осуществляет данный объект.
				/*!
					Содержит нулевой указатель, если использовался
					конструктор по-умолчанию.
				*/
				const type_t *	m_type;
				//! Порядковый номер текущего атрибута в списке атрибутов.
				size_t	m_index;

				//! Инициализирующий конструктор.
				/*!
					Доступен классу pseudo_attr_list_t.
				*/
				inline
				const_iterator(
					const type_t & t,
					size_t index ) :
					m_type( &t ),
					m_index( index )
				{
				}

			public :
				//! Конструктор по-умолчанию.
				inline
				const_iterator() :
					m_type( 0 ),
					m_index( 0 )
				{
				}

				//! Копирующий конструктор.
				inline
				const_iterator(
					const const_iterator & o ) :
					m_type( o.m_type ),
					m_index( o.m_index )
				{
				}

				inline const attr_t &
				operator*() const {
					return m_type->query_attr( m_index );
				}

				bool
				operator==( const const_iterator & o ) const {
					return ( m_type == o.m_type && m_index == o.m_index );
				}

				bool
				operator!=( const const_iterator & o ) const {
					return ( m_type != o.m_type || m_index != o.m_index );
				}

				const_iterator&
				operator++() {
					++m_index;
					return *this;
				}

				const_iterator
				operator++( int ) {
					return const_iterator( *m_type, m_index++ );
				}
		};

		//! Получить итератор на первый атрибут в списке атрибутов.
		inline const_iterator
		begin() const {
			return const_iterator( m_type, 0 );
		}

		//! Получить итератор, указывающий за последний атрибут в
		//! списке атрибутов.
		inline const_iterator
		end() const {
			return const_iterator( m_type, m_type.query_attr_count() );
		}
};

//
// pseudo_extension_attr_list_t
//

/*! \since v.1.2.0
	\brief Псевдо-список для предоставления доступа к списку
		атрибутов расширения типа в стиле STL итераторов.

	Если при конструировании псевдо-списка указать в качестве
	уровня расширения 0, то перечисляются все атрибуты,
	которые не входят ни в одно из расширений.
*/
class	pseudo_extension_attr_list_t {
	private :
		const type_t &	m_type;
		const unsigned int	m_extension;

	public :
		inline
		pseudo_extension_attr_list_t(
			const type_t & t,
			unsigned int extension )
		:	m_type( t )
		,	m_extension( extension )
		{}

		class	const_iterator
		{
			friend class pseudo_extension_attr_list_t;
			private :
				const type_t *	m_type;
				const unsigned int m_extension;
				size_t	m_index;

				inline
				const_iterator(
					const type_t & t,
					const unsigned int extension,
					size_t index )
				:	m_type( &t )
				,	m_extension( extension )
				,	m_index( index )
				{}

			public :
				inline
				const_iterator()
				:	m_type( 0 )
				,	m_extension( 0 )
				,	m_index( 0 )
				{}

				inline
				const_iterator(
					const const_iterator & o )
				:	m_type( o.m_type )
				,	m_extension( o.m_extension )
				,	m_index( o.m_index )
				{}

				inline const attr_t &
				operator*() const
				{
					return m_type->extension_attr(
						m_extension, m_index );
				}

				bool
				operator==( const const_iterator & o ) const
				{
					return ( m_type == o.m_type &&
						m_extension == o.m_extension &&
						m_index == o.m_index );
				}

				bool
				operator!=( const const_iterator & o ) const
				{
					return ( m_type != o.m_type ||
						m_extension != o.m_extension ||
						m_index != o.m_index );
				}

				const_iterator&
				operator++()
				{
					++m_index;
					return *this;
				}

				const_iterator
				operator++( int )
				{
					return const_iterator( *m_type,
						m_extension, m_index++ );
				}
		};

		inline const_iterator
		begin() const
		{
			return const_iterator( m_type, m_extension, 0 );
		}

		inline const_iterator
		end() const
		{
			return const_iterator( m_type, m_extension,
				m_type.extension_attr_count( m_extension ) );
		}
};

/*
	Описания итерфейсов для всех поддерживаемых разновидностей
	типов атрибутов.
*/

//
// single_obj_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		простым одиночным объектом.
*/
class	OESS_1__SCHEME__TYPE	single_obj_kind_t :
	public attr_cont_kind_t {
	public :
		virtual ~single_obj_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 0
		};

		virtual oess_1::int_t
		query_kind_id() const;
};

//
// stl_vector_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		std::vector.
*/
class	OESS_1__SCHEME__TYPE	stl_vector_kind_t :
	public attr_cont_kind_t {
	public :
		virtual ~stl_vector_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 1
		};

		virtual oess_1::int_t
		query_kind_id() const;
};

//
// stl_list_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		std::list.
*/
class	OESS_1__SCHEME__TYPE	stl_list_kind_t :
	public attr_cont_kind_t {
	public :
		virtual ~stl_list_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 2
		};

		virtual oess_1::int_t
		query_kind_id() const;
};

//
// stl_deque_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		std::deque.
*/
class	OESS_1__SCHEME__TYPE	stl_deque_kind_t :
	public attr_cont_kind_t {
	public :
		virtual ~stl_deque_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 3
		};

		virtual oess_1::int_t
		query_kind_id() const;
};

//
// stl_set_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		std::set.
*/
class	OESS_1__SCHEME__TYPE	stl_set_kind_t :
	public attr_cont_kind_t {
	public :
		virtual ~stl_set_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 4
		};

		virtual oess_1::int_t
		query_kind_id() const;
};

//
// stl_multiset_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		std::multiset.
*/
class	OESS_1__SCHEME__TYPE	stl_multiset_kind_t :
	public attr_cont_kind_t {
	public :
		virtual ~stl_multiset_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 5
		};

		virtual oess_1::int_t
		query_kind_id() const;
};

//
// stl_map_base_kind_t
//

/*!
	\brief Базовый интерфейс для описания атрибутов, которые
		являются либо std::map, либо std::map.
*/
class	OESS_1__SCHEME__TYPE	stl_map_base_kind_t :
	public attr_cont_kind_t {
	public :
		virtual ~stl_map_base_kind_t();

		virtual oess_1::int_t
		query_kind_id() const = 0;

		//! Тип ключа для map.
		virtual const type_t &
		query_key_type() const = 0;
};

//
// stl_map_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		std::map.
*/
class	OESS_1__SCHEME__TYPE	stl_map_kind_t :
	public stl_map_base_kind_t {
	public :
		virtual ~stl_map_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 6
		};

		virtual oess_1::int_t
		query_kind_id() const;

		virtual const type_t &
		query_key_type() const = 0;
};

//
// stl_multimap_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		std::multimap.
*/
class	OESS_1__SCHEME__TYPE	stl_multimap_kind_t :
	public stl_map_base_kind_t {
	public :
		virtual ~stl_multimap_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 7
		};

		virtual oess_1::int_t
		query_kind_id() const;

		// Тип ключа для map.
		// В качестве типа значения используется тип
		// атрибута.
		virtual const type_t &
		query_key_type() const = 0;
};

//
// fixed_vector_kind_t
//

/*!
	\brief Детализация описания атрибута, который является
		вектором фиксированного размера.
*/
class	OESS_1__SCHEME__TYPE	fixed_vector_kind_t :
	public attr_cont_kind_t {
	public :
		virtual ~fixed_vector_kind_t();

		enum kind_id_t {
			//! Идентификатор данной разновидности атрибутов.
			e_id = 8
		};

		virtual oess_1::int_t
		query_kind_id() const;

		// Размерность вектора в элементах.
		virtual size_t
		query_capacity() const = 0;
};

//
// type_kind_processor_t
//

/*!
	\brief Базовый класс для обработчиков разновидностей типа.

	Этот обработчик самостоятельно проверяет разновидность
	атрибута и вызывает соотвествующий виртуальный метод.
	Это значит, что проверку вариантов не нужно вставлять в
	код, который обрабатывает атрибуты.

	Обработчики конкретных типов атрибутов описаны как
	чистые виртуальные методы. Поэтому, если забыть реализовать
	обработчик для какой-либо разновидности атрибута, то
	производный от kind_processor_t класс не удасться
	использовать.
*/
class	OESS_1__SCHEME__TYPE	type_kind_processor_t {
	public :
		virtual ~type_kind_processor_t();

		//! Выполнить операцию над атрибутом.
		/*! Если тип атрибута распознать не удалось,
			то порождается исключение. */
		void
		process_type_kind( const attr_type_t & k );

	protected :
		/*!
			Обработчик атрибутов-значений.
		*/
		virtual void
		on_value_kind(
			const attr_type_t & k ) = 0;

		/*!
			Обработчик атрибутов-указателей.
		*/
		virtual void
		on_ptr_kind(
			const attr_type_t & k ) = 0;

		/*!
			\since v.1.2.0
			\brief Обработать атрибут, который является указателем
				на производный класс-расширение.
		*/
		virtual void
		on_extension_kind(
			const attr_type_t & k ) = 0;
};

//
// cont_kind_processor_t
//

/*!
	\brief Базовый класс для обработчиков разновидностей
	контейнеров.

	Этот обработчик самостоятельно проверяет разновидность
	атрибута и вызывает соотвествующий виртуальный метод.
	Это значит, что проверку вариантов не нужно вставлять в
	код, который обрабатывает атрибуты.

	Обработчики конкретных типов атрибутов описаны как
	чистые виртуальные методы. Поэтому, если забыть реализовать
	обработчик для какой-либо разновидности атрибута, то
	производный от kind_processor_t класс не удасться
	использовать.
*/
class	OESS_1__SCHEME__TYPE	cont_kind_processor_t {
	public :
		virtual ~cont_kind_processor_t();

		//! Выполнить операцию над атрибутом.
		/*! Если тип атрибута распознать не удалось,
			то порождается исключение. */
		void
		process_cont_kind( const attr_cont_kind_t & k );

	protected :
		virtual void
		on_single_obj_kind(
			const single_obj_kind_t & k ) = 0;

		virtual void
		on_stl_vector_kind(
			const stl_vector_kind_t & k ) = 0;

		virtual void
		on_stl_list_kind(
			const stl_list_kind_t & k ) = 0;

		virtual void
		on_stl_deque_kind(
			const stl_deque_kind_t & k ) = 0;

		virtual void
		on_stl_set_kind(
			const stl_set_kind_t & k ) = 0;

		virtual void
		on_stl_multiset_kind(
			const stl_multiset_kind_t & k ) = 0;

		virtual void
		on_stl_map_kind(
			const stl_map_kind_t & k ) = 0;

		virtual void
		on_stl_multimap_kind(
			const stl_multimap_kind_t & k ) = 0;

		virtual void
		on_fixed_vector_kind(
			const fixed_vector_kind_t & k ) = 0;
};

} /* scheme */

} /* namespace oess_1 */

#endif

