/*

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.

*/

#if !defined( _OESS_1__SCHEME__IMPL__TYPES_IMPL_HPP_ )
#define _OESS_1__SCHEME__IMPL__TYPES_IMPL_HPP_

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

#include <deque>
#include <map>

#include <auto_ptr_3/h/obj_ptr.hpp>

#include <smart_ref_3/h/smart_ref.hpp>

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

#include <oess_1/scheme/impl/h/iface_refs.hpp>

namespace oess_1 {

namespace scheme {

namespace impl {

//
// std_base_t
//
class	std_base_t :
	public base_t
{
	public :
		//! Возможные разновидности наследования.
		/*! \since v.1.2.0 */
		enum subclassing_mode_t
		{
			//! Нормальное, обычное наследование.
			normal_subclassing,
			//! Наследование через расширение базового класса.
			subclassing_by_extension
		};

		//! Конструктор для случая нормального наследования.
		std_base_t(
			const type_t & type,
			bool is_virtual );
		//! Конструктор для случая с наследованием через
		//! расширение базового класса.
		/*! \since v.1.2.0 */
		std_base_t(
			const type_t & type,
			const subclassing_mode_t & subclassing_mode );

		virtual ~std_base_t();

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

		virtual bool
		is_virtual() const;

		virtual bool
		is_extension_of() const;
	//! \}

	private :
		//! Тип, от которого унаследовались.
		const type_t &	m_type;
		//! Было ли наследование виртуальным?
		bool	m_is_virtual;
		//! Какая разновидность наследования использовалась.
		subclassing_mode_t	m_subclassing_mode;
};

//
// std_cpp_mapping_t
//
class	std_cpp_mapping_t :
	public cpp_mapping_t {
	public :
		std_cpp_mapping_t(
			const std::string & ddl_type_name );
		virtual ~std_cpp_mapping_t();

		// Установить имя типа в C++.
		void
		set_name( const std::string & name );

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

	private :
		// Имя типа в С++.
		// Изначально делается равным имени типа в DDL.
		std::string	m_name;
};

//
// std_attr_type_t
//
class	std_attr_type_t :
	public attr_type_t {
	public :
		std_attr_type_t(
			const type_t & type );
		virtual ~std_attr_type_t();

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

		// Установить разновидность типа.
		void
		set_type_kind(
			type_kind_t kind_id );

		virtual type_kind_t
		query_type_kind() const;

		// Установить разновидность типа контейнера.
		void
		set_cont_kind(
			const ref_attr_cont_kind_t & ref_kind );

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

	private :
		const type_t &	m_type;

		// По умолчанию равен e_value.
		type_kind_t	m_type_kind;

		// По умолчанию равен single_obj_kind_t.
		ref_attr_cont_kind_t	m_ref_cont_kind;
};

//
// std_attr_present_if_t
//

/*!
	\since v.1.2.0
	\brief Реализация интерфейса описания предиката сериализации
		опционального атрибута.
*/
class	std_attr_present_if_t
:	public attr_present_if_t
{
	public :
		//! Конструктор по-умолчанию.
		std_attr_present_if_t();
		virtual ~std_attr_present_if_t();

		//! Установить значение предиката для C++.
		void
		set_cpp( const std::string & expr );

	//! \name Унаследованные методы.
	//! \{
		virtual const std::string &
		cpp() const
		throw( std::exception );

		virtual bool
		is_cpp() const;
	//! \}

	private :
		//! Значение предиката для C++.
		/*!
			Содержит пустую строку, если предикат для C++
			не задан.
		*/
		std::string	m_cpp;
};

//
// std_attr_default_t
//

/*!
	\since v.1.2.0
	\brief Реализации интерфейс значения атрибута по-умолчанию.
*/
class	std_attr_default_t
:	public attr_default_t
{
	public :
		//! Основной конструктор.
		/*!
			Если \a is_optional == \a true, то создается объект
			std_attr_present_if_t.
		*/
		std_attr_default_t(
			//! \a true, если атрибут является опциональным.
			bool is_optional );
		virtual ~std_attr_default_t();

		//! Установить значение для C++.
		void
		set_cpp(
			const std::string & expr );

		//! Получить read-write доступ к реализации
		//! интерфейса %attr_present_if_t.
		/*!
			\throw std::exception если атрибут не является опциональным.
		*/
		std_attr_present_if_t &
		std_present_if()
		throw( std::exception );

	//! \name Унаследованные методы.
	//! \{
		virtual const std::string &
		cpp() const
		throw( std::exception );

		virtual bool
		is_cpp() const;

		virtual bool
		is_optional() const;

		virtual const attr_present_if_t &
		present_if() const;
	//! \}

	private :
		//! Значение для C++.
		/*! Пустая строка, если значение не задано. */
		std::string	m_cpp;

		//! Предикат сериализации атрибута.
		/*! Существует, только, если в конструкторе
			указано, что атрибут опциональный. */
		auto_ptr_3::obj_ptr_t< std_attr_present_if_t >
			m_present_if;
};

//
// attr_t
//

/*!
	\brief Стандартная реализация интерфейса %attr_t.
*/
class	std_attr_t :
	public attr_t {
	public :
		std_attr_t(
			// Имя атрибута.
			const std::string & name,
			// Тип атрибута.
			const type_t & type,
			//! Глубина вложенности расширения, в котором был
			//! описан атрибут.
			unsigned int extension_level );
		virtual ~std_attr_t();

	//! \name Унаследованные методы.
	//! \{
		virtual const std::string &
		query_name() const;

		virtual const attr_type_t &
		query_attr_type() const;

		virtual const attr_default_t *
		query_attr_default() const;

		virtual unsigned int
		extension_level() const;
	//! \}

		// Установить разновидность типа.
		void
		set_type_kind(
			attr_type_t::type_kind_t kind_id );

		// Установить разновидность типа контейнера.
		void
		set_cont_kind(
			const ref_attr_cont_kind_t & ref_kind );

		/*!
			\since v.1.2.0
			\brief Создает реализацию интерфейса %attr_default_t.
		*/
		void
		make_std_attr_default(
			//! \a true, если атрибут опциональный.
			bool is_optional );

		/*!
			\since v.1.2.0
			\brief Получить доступ к стандартной реализации
				интерфейса %attr_default_t.
			\throw std::exception если не было предшествующего
				обращения к make_std_attr_default().
		*/
		std_attr_default_t &
		std_attr_default();

	private :
		//! Имя атрибута.
		std::string	m_name;

		//! Тип атрибута.
		std_attr_type_t	m_type;

		/*! \since v.1.2.0
			\brief Глубина расширения, в котором описан данный атрибут.
		*/
		unsigned int	m_extension_level;

		/*!
			\since v.1.2.0
			\brief Описание значения атрибута по-умолчанию.

			Создается при вызове метода make_std_attr_default().
		*/
		auto_ptr_3::obj_ptr_t< std_attr_default_t > m_default;
};

//
// ref_std_attr_t
//
SMART_REF_3_DECL_DERIVED_REF( std_attr_t, attr_t, class )

//
// std_type_t
//

/*!
	\brief Стандартная реализация интерфейса %type_t.
*/
class	std_type_t :
	public type_t
{
	public :
		std_type_t(
			const std::string & name,
			// Является ли тип встроенным?
			bool is_builtin = false );
		virtual ~std_type_t();

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

		virtual bool
		is_defined() const;

		//! Сделать тип полностью опеределенным.
		void
		make_defined();

		virtual bool
		is_builtin() const;

		virtual bool
		is_abstract() const;

		//! Сделать тип абстрактным.
		void
		make_abstract();

		virtual bool
		is_extensible() const;

		//! Сделать тип расширяемым.
		/*! \since v.1.2.0 */
		void
		make_extensible();

		virtual bool
		is_subclassing_by_extension() const;

		/*!
			\since v.1.2.0
			\brief Указать, что тип поддерживает subclassing_by_extension.
		*/
		void
		turn_subclassing_by_extension_on();

		virtual bool
		is_derived_as_extension() const;

		//! Добавление еще одного базового типа.
		/*! В случае невозможности добавить тип в
			список порождается исключение. */
		void
		add_base(
			const ref_base_t & ref_base );

		//! Добавление еще одного базового типа но в режиме
		//! subclassing_by_extension.
		/*!
			\since v.1.2.0

			Допускается наличие только одного базового типа,
			который наследуется через расширение.

			\throw oess_1::ex_t в случае невозможности добавления типа.
		*/
		void
		add_base_as_extension(
			const ref_base_t & base );

		virtual size_t
		query_base_count() const;

		virtual const base_t &
		query_base( size_t index ) const;

		virtual const base_t *
		find_base( const std::string & name ) const;

		//! Добавление еще одного атрибута.
		/*! В случае невозможности добавить атрибут в
			список порождается исключение. */
		void
		add_attr(
			const ref_attr_t & ref_attr,
			//! Глубина расширения, в котором описывается
			//! атрибут. Должна совпадать с текущим значением
			//! m_extension_deep.
			unsigned int extension_level );

		virtual size_t
		query_attr_count() const;

		virtual const attr_t &
		query_attr( size_t index ) const;

		virtual const attr_t *
		find_attr( const std::string & name ) const;

		virtual const cpp_mapping_t &
		query_cpp_mapping() const;

		virtual unsigned int
		extension_deep() const;

		virtual unsigned int
		extension_attr_count( unsigned int extension ) const;

		virtual const attr_t &
		extension_attr( unsigned int extension,
			unsigned int attr_index ) const;
	//! \}

		//! Доступ к отображению типа в C++ для редактирования.
		std_cpp_mapping_t &
		query_cpp_mapping();

		/*! \since v.1.2.0
			\brief Увеличить глубину расширений типа.

			После вызова данной функции все добавляемые атрибуты
			будут размещатся в очередное расширение.
		*/
		void
		start_extension();

	public :
		//! Имя типа.
		std::string	m_name;

		//! Определен ли тип?
		bool	m_is_defined;

		//! Встроенный ли тип?
		bool	m_is_builtin;

		//! По-умолчанию: не абстрактный.
		bool	m_is_abstract;

		/*!
			\since v.1.2.0
			\brief Является ли тип расширяемым?

			По-умолчанию не является.
		*/
		bool	m_is_extensible;

		/*!
			\since v.1.2.0
			\brief Поддерживает ли тип subclassing_by_extension?

			Равен true, если поддерживает.

			По-умолчанию не поддерживает.
		*/
		bool	m_is_subclassing_by_extension;

		//! Тип списка базовых типов.
		typedef std::deque< ref_base_t >
			ref_base_deque_t;
		//! Список базовый типов.
		ref_base_deque_t	m_bases;

		//! Словарь имен базовых типов.
		typedef std::map< std::string, const base_t *,
			std::less< std::string > >
			bases_map_t;
		//! Для быстрой проверки наличия базового типа.
		bases_map_t	m_bases_map;

		//! Тип списка атрибутов.
		typedef std::deque< ref_attr_t >
			ref_attr_deque_t;
		//! Тип списка атрибутов, распределенных по расширениям.
		/*! \since v.1.2.0

			Элемент с индексом 0 содержит список атрибутов, не
			принадлежащих ни одному из расширений. */
		typedef std::deque< ref_attr_deque_t >
			attr_extension_deque_t;

		//! Список атрибутов.
		/*!
			Содержит все атрибуты, включая все атрибуты из всех
			расширений.
		*/
		ref_attr_deque_t	m_attrs;

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

			Элемент с индексом 0 содержит список атрибутов, не
			принадлежащих ни одному из расширений. */
		attr_extension_deque_t	m_attr_extensions;

		//! Словарь имен атрибутов.
		typedef std::map< std::string, const attr_t *,
			std::less< std::string > >
			attrs_map_t;
		//! Для быстрой проверки наличия атрибута.
		attrs_map_t	m_attrs_map;

		//! Отображение в C++.
		std_cpp_mapping_t	m_cpp_mapping;

		/*!
			\since v.1.2.0
			\brief Признак того, что subclassing_by_extension уже
				был использован.

			Если используется subclassing_by_extension, то множественное
			наследование запрещено.
		*/
		bool	m_is_derived_as_extension;
};

//
// ref_std_type_t
//
SMART_REF_3_DECL_DERIVED_REF( std_type_t, type_t, class )

//
// map_base_kind_impl_t
//

/*
	Вспомогательный класс для реализации
	stl_map_kind_t и stl_multimap_kind_t.
*/
class	map_base_kind_impl_t {
	public :
		map_base_kind_impl_t(
			const type_t & type );
		virtual ~map_base_kind_impl_t();

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

	private :
		const type_t &	m_type;
};

//
// std_stl_map_kind_t
//
class	std_stl_map_kind_t :
	public stl_map_kind_t,
	public map_base_kind_impl_t {
	public :
		std_stl_map_kind_t(
			const type_t & type );
		virtual ~std_stl_map_kind_t();

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

//
// std_stl_multimap_kind_t
//
class	std_stl_multimap_kind_t :
	public stl_multimap_kind_t,
	public map_base_kind_impl_t {
	public :
		std_stl_multimap_kind_t(
			const type_t & type );
		virtual ~std_stl_multimap_kind_t();

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

//
// std_fixed_vector_kind_t
//
class	std_fixed_vector_kind_t :
	public fixed_vector_kind_t {
	public :
		std_fixed_vector_kind_t(
			size_t capacity );
		virtual ~std_fixed_vector_kind_t();

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

	private :
		size_t	m_capacity;
};

} /* namespace impl */

} /* namespace scheme */

} /* namespace oess_1 */

#endif
