/*

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__SCHEME_IMPL_HPP_ )
#define _OESS_1__SCHEME__IMPL__SCHEME_IMPL_HPP_

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

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

namespace oess_1 {

namespace scheme {

namespace impl {

class	std_scheme_t;

//
// std_attr_editor_t
//

/*!
	\brief Стандартная реализация интерфейса %attr_editor_t.
*/
class	std_attr_editor_t :
	public attr_editor_t {
	public :
		std_attr_editor_t(
			std_scheme_t & scheme );
		virtual ~std_attr_editor_t();

		//! Попытка создать объект-атрибут.
		/*! В случае возникновения ошибок порождаются
			исключения. */
		void
		def(
			const std::string & attr_name,
			const std::string & type_name,
			//! Глубина расширения, которому принадлежит атрибут.
			unsigned int extension_level );

		// Извлечение ссылки на сам атрибут для
		// попытки занесения атрибута в тип.
		const ref_attr_t &
		query_ref_attr() const;

		virtual void
		make_ptr_kind();

		virtual void
		make_extension_kind();

		// По умолчанию разновидность типа контейнера - single_obj_kind.
		virtual void
		make_single_obj_kind();

		virtual void
		make_stl_vector_kind();

		virtual void
		make_stl_list_kind();

		virtual void
		make_stl_deque_kind();

		virtual void
		make_stl_set_kind();

		virtual void
		make_stl_multiset_kind();

		// В случае ошибки порождается исключение.
		virtual void
		make_stl_map_kind(
			const std::string & key_type_name );

		// В случае ошибки порождается исключение.
		virtual void
		make_stl_multimap_kind(
			const std::string & key_type_name );

		virtual void
		make_fixed_vector_kind(
			size_t capacity );

		virtual void
		set_default_existence(
			bool is_optional );

		virtual void
		set_cpp_default(
			const std::string & expr );

		virtual void
		set_cpp_present_if(
			const std::string & expr );

	private :
		std_scheme_t &	m_scheme;
		ref_std_attr_t	m_ref_attr;

		void
		set_cont_kind( const ref_attr_cont_kind_t & ref );

		const type_t &
		find_type(
			const std::string & type_name ) const;
};

//
// ref_std_attr_editor_t
//
SMART_REF_3_DECL_REF( std_attr_editor_t, class )

//
// std_cpp_mapping_editor_t
//
class	std_cpp_mapping_editor_t :
	public cpp_mapping_editor_t {
	public :
		std_cpp_mapping_editor_t(
			std_cpp_mapping_t & cpp_mapping );
		virtual ~std_cpp_mapping_editor_t();

		virtual void
		set_name( const std::string & name );

	private :
		std_cpp_mapping_t &	m_cpp_mapping;
};

//
// ref_std_cpp_mapping_editor_t
//
SMART_REF_3_DECL_REF( std_cpp_mapping_editor_t, class )

//
// std_type_editor_t
//

/*!
	\brief Стандартная реализация интерфейса %type_editor_t.
*/
class	std_type_editor_t :
	public type_editor_t
{
	public :
		std_type_editor_t(
			std_scheme_t & scheme );
		virtual ~std_type_editor_t();

		//! Попытка создать объект std_type_t.
		/*! В случае ошибки порождаются исключения. */
		void
		def( const std::string & name );

		//! Сделать тип определенным.
		/*! Вызывается схемой при получении уведомления
			о завершении редактирования типа. */
		void
		make_defined();

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

		virtual void
		make_extensible();

		virtual void
		add_base(
			const std::string & name,
			bool is_virtual );

		virtual void
		add_base_as_extension(
			const std::string & name );

		virtual attr_editor_t &
		start_attr_def(
			const std::string & attr_name,
			const std::string & type_name );

		virtual void
		commit_attr_def();

		virtual void
		rollback_attr_def();

		virtual cpp_mapping_editor_t &
		cpp_mapping();

		virtual void
		start_extension();

		virtual void
		turn_subclassing_by_extension_on();
	//! \}

	private :
		//! Схема, которой мы принадлежим.
		std_scheme_t &	m_scheme;

		//! Описываемый тип.
		ref_std_type_t	m_ref_type;

		//! Ссылка на текущий редактор атрибута.
		/*! Принимает корректное значение после
			успешного вызова start_attr_def.
			Обнуляется после вызовов commit_attr_def
			и rollback_attr_def. */
		ref_std_attr_editor_t	m_ref_attr_editor;

		//! Определяется только после успешного
		//! вызова метода def.
		ref_std_cpp_mapping_editor_t	m_ref_cpp_mapping_editor;

		/*! \since v.1.2.0
			\brief Текущая глубина вложенности расширений.

			Имеет значение 0, если расширений нет. */
		unsigned int	m_extension_deep;
};

//
// ref_std_type_editor_t
//
SMART_REF_3_DECL_REF( std_type_editor_t, class )

//
// std_scheme_t
//
class	std_scheme_t :
	public scheme_t {
	public :
		std_scheme_t();
		virtual ~std_scheme_t();

		// Определить количество пользовательских
		// типов в схеме. Встроенные типы в это
		// число не входят.
		virtual size_t
		query_type_count() const;

		// Доступ к типу по номеру.
		// Нумерация начинается с 0.
		// В случае ошибки порождается исключение.
		virtual const type_t &
		query_type( size_t index ) const;

		// Найти тип по имени. Можно искать как
		// пользовательские, так и встроенные типы.
		// Если тип не найден, то возвращается 0.
		virtual const type_t *
		find_type( const std::string & name ) const;

		// Начать определение типа.
		// Невозможность определения типа с
		// указанным именем может возникнуть только
		// на этапе занесения типа в схему.
		// В случае ошибки порождается исключение.
		virtual type_editor_t &
		start_type_def(
			const std::string & name );

		// Завершить определение типа и добавить
		// тип в схему.
		// В случае ошибки порождается исключение.
		// После завершения данной функции пользоваться
		// объектом type_editor_t нельзя!
		virtual void
		commit_type_def();

		// Отказаться от определения типа.
		// После завершения данной функции пользоваться
		// объектом type_editor_t нельзя!
		virtual void
		rollback_type_def();

		// Найти тип с указанным именем, а если такого
		// типа нет, то создать новый неопределенный
		// тип с таким именем.
		const ref_std_type_t &
		find_or_create_type(
			const std::string & name );

	private :
		typedef std::deque< ref_std_type_t >	ref_std_type_deque_t;

		//! Список встроенных типов.
		/*! Таких типов, как oess_1::uint_t, std::string...

			В этот же список помещается тип
			oess_1::stdsn::serializable_t
			хотя он типы не является атомарным. */
		ref_std_type_deque_t	m_builtin_types;

		// Список пользовательских типов.
		ref_std_type_deque_t	m_user_types;

		// Словарь всех типов, упорядоченный по
		// именам типов. Используется для
		// быстрого поиска.
		typedef std::map< std::string, std_type_t *,
			std::less< std::string > >
			type_map_t;

		type_map_t	m_type_map;

		// Ссылка на текущий редактор типа.
		// Принимает корректное значение после
		// успешного вызова start_type_def.
		// Обнуляется после вызовов commit_type_def
		// и rollback_type_def.
		ref_std_type_editor_t	m_ref_type_editor;

		// Добавить тип в словарь типов.
		void
		add_to_map( std_type_t & type );

		// Заполнить список встроенных типов.
		void
		fill_builtin_types();

		// Обработать один встроенный тип с указанным именем.
		void
		add_builtin_type(
			const std::string & name );

		/*!
			Добавить в список встроенных типов описание
			типа oess_1::stdsn::serializable_t.
		*/
		void
		add_builtin_serializable_t();
};

} /* impl */

} /* scheme */

} /* namespace oess_1 */

#endif
