/*

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.

*/

/*!
	\since v.1.4.0
	\file
	\brief Объект для вычисления номеров страниц/блоков исходя
		из размера одной страницы и одного блока.
*/

#if !defined( _OESS_1__DB__STORAGE__PAGE_INDEX_CALCULATOR_HPP_ )
#define _OESS_1__DB__STORAGE__PAGE_INDEX_CALCULATOR_HPP_

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

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

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

namespace oess_1 {

namespace db {

namespace storage {

//
// area_ordinal_t
//

/*!
	\since v.1.4.0
	\brief Тип для хранения порядкового номера области.
*/
typedef oess_1::ushort_t area_ordinal_t;

//
// segment_ordinal_t
//

/*!
	\since v.1.4.0
	\brief Тип для хранения порядкового номера сегмента.
*/
typedef oess_1::ushort_t segment_ordinal_t;

//
// page_index_calculator_t
//

/*!
	\since v.1.4.0
	\brief Объект для вычисления номеров страниц/блоков исходя
		из размера одной страницы и одного блока.

	В файле может находиться только целое количество сегментов.
	Последний сегмент, который полностью не помещается в файл
	(из-за наличия страницы общего заголовка) просто игнорируется.
	Т.е. файл БД никогда не достигнет максимального значения.
*/
class	OESS_1__DB__TYPE	page_index_calculator_t
	{
	public :
		//! Инициализирующий конструктор.
		page_index_calculator_t(
			//! Размер одной страницы в байтах.
			oess_1::uint_t page_size,
			//! Размер одного блока цепочки (блока на странице).
			oess_1::uint_t chain_link_size );

		//! Получить номер страницы общего заголовка.
		oess_1::uint_t
		common_header_page() const;

		//! Получить общее количество областей файла.
		area_ordinal_t
		area_count() const;

		//! Получить количество целых сегментов в указанной области.
		segment_ordinal_t
		area_segment_count(
			const area_ordinal_t & area ) const;

		//! Получить порядковый номер страницы заголовка указанной области.
		oess_1::uint_t
		area_header_page(
			const area_ordinal_t & area ) const;

		//! Получить номер страницы заголовка указанного сегмента.
		oess_1::uint_t
		segment_header_page(
			//! Область, к которой относится сегмент.
			const area_ordinal_t & area,
			const segment_ordinal_t & segment ) const;

		//! Получить количество страниц в сегменте с учетом заголовка сегмента.
		oess_1::uint_t
		segment_page_count() const;

		//! Количество блоков на одной странице.
		oess_1::uint_t
		chain_link_on_page_count() const;

		//! Идентификатор первого блока на указанной странице.
		chain_id_t
		first_chain_link_on_page(
			//! Порядковый номер страницы.
			oess_1::uint_t page_ordinal ) const;

		//! Получить номер области, в которой находится указанный блок.
		area_ordinal_t
		chain_link_area(
			const chain_id_t & block ) const;

		//! Получить номер сегмента, в котором находится указанный блок.
		segment_ordinal_t
		chain_link_segment(
			const chain_id_t & block ) const;

		//! Получить номер страницы, на которой находится указанный блок.
		oess_1::uint_t
		chain_link_page(
			const chain_id_t & block ) const;

		//! Получить смещение на странице для указанного блока.
		oess_1::uint_t
		chain_link_page_offset(
			const chain_id_t & block ) const;

		//! Получить номер блока, который в пустом хранилище будет
		//! занят первым.
		/*!
			Это первый блок первого сегмента первой области.
		*/
		chain_id_t
		first_chain_id() const;

	private :
		//! Размер страницы в байтах.
		oess_1::uint_t m_page_size;
		//! Размер блока на странице в байтах.
		oess_1::uint_t m_chain_link_size;
		//! Количество блоков на странице.
		oess_1::uint_t m_page_chain_links;
		//! Количество доступных областей в файле.
		oess_1::uint_t m_areas;
		//! Размер одной полной области в сегментах.
		oess_1::uint_t m_area_segments;
		//! Размер последней области в сегментах.
		oess_1::uint_t m_last_area_segments;
		//! Размер области в страницах.
		oess_1::uint_t m_area_pages;
		//! Размер сегмента в страницах.
		oess_1::uint_t m_segment_pages;
	};

} /* namespace storage */

} /* namespace db */

} /* namespace oess_1 */

#endif

