/*

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__FILE__FILE_HPP_ )
#define _OESS_1__FILE__FILE_HPP_

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

#include <auto_ptr_3/h/vect_ptr.hpp>

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

namespace oess_1 {

namespace file {

//
// file_t
//

/*!
	Класс для работы с файлами.
*/
class	OESS_1__FILE__TYPE	file_t :
	public oess_1::io::ibinstream_t,
	public oess_1::io::obinstream_t
{
	public :
		file_t();
		virtual ~file_t();

		/*! Открыть существующий файл. */
		void
		open(
			/*! Имя открываемого файла. */
			const std::string & file_name,
			/*! true, если файл должен быть открыт
				только для чтения. */
			bool is_read_only );

		/*! Создать новый файл или перезаписать
			существующий. */
		void
		create(
			/*! Имя создаваемого файла. */
			const std::string & file_name );

		/*! Закрыть файл.
			Исключения не выпускаются. */
		void
		close();

		/*! Определить текущую позицию в файле. */
		oess_1::uint_t
		tell();

		/*! Перейти на указанную позицию. */
		void
		seek( oess_1::uint_t pos );

		/*! Определить длину файла. */
		oess_1::uint_t
		length();

		/*! Достигнут ли конец файла? */
		virtual bool
		eof() const;

		/*! Усечь файл до указанного размера. */
		void
		chsize(
			oess_1::uint_t size );

		/*! Удалить файл. */
		static void
		remove( const std::string & file_name );

		/*!
			\since v.1.1.0
			\brief Проверить существование файла с указанным именем.

			\return true, если существует файл. false, если файл не
				существует, либо с данным именем связан другой
				объект файловой системы (например, каталог). */
		static bool
		is_file_exists(
			const std::string & file_name );

		/*!
			\since v.1.4.0
			\brief Переименовать файл.

			Если аргумент \a auto_destroy_existing_target == true,
			то проверяет существование \a to и если \a to существует,
			то пытается предварительно удалить \a to.

			Если аргумент \a auto_destroy_existing_target == false,
			то существование \a to воспринимается как ошибка и
			удаление не выполняется, а порождается исключение.
		*/
		static void
		rename_file(
			//! Что переименовывать.
			const std::string & what,
			//! Во что переименовывать.
			const std::string & to,
			//! Нужно ли уничтожать \a to, если \a to существует.
			bool auto_destroy_existing_target = false );

	protected :
		/*
			ВНИМАНИЕ!
			В реализации класса file_t используется
			тот факт, что любая операция ввода/вывода
			использует парные вызовы in_reserve/in_shift
			(out_reserve/out_shift).
			Поэтому метод in_reserve осуществляет загрузку
			требуемого фрагмента в память. Метод out_shift
			осуществляет запись фрагмента в файл.
			Т.е. содержимое считываемого/записываемого
			фрагмента является актуальным во внутреннем буфере
			класса file_t только между вызовами *_reserve/ *_shift.
			В остальное время буфер считается незаполненым.
		*/

		/*! Метод для определения указателя, из которого
			можно считывать данные.
			Если нет достаточного объема данных для чтения
			хотя бы одного элемента, то должно порождаться
			исключение.

			Осуществляет загрузку фрагмента (части фрагмента)
			из файла во внутренний буфер. */
		virtual const oess_1::char_t *
		in_reserve(
			/*! Количество элементов, которые нужно
				прочитать. */
			size_t item_count,
			/*! Размер одного элемента в байтах. */
			size_t item_size,
			/*! Количество элементов, доступных по
				возвращенному указателю. */
			size_t & item_available );

		/*! Сдвинуть указатель. Вызывается после успешного
			чтения из буфера, указатель на который был
			возвращен методом out_reserve.

			Ничего не делает.
		*/
		virtual void
		in_shift(
			/*! Количество успешно прочитанных элементов. */
			size_t item_count,
			/*! Размер одного элемента в байтах. */
			size_t item_size );

		/*! Метод для определения указателя, в который
			можно записывать данные.
			Если нет достаточного объема данных для чтения
			хотя бы одного элемента, то должно порождаться
			исключение.

			Возвращает указатель на начало внутреннего
			буфера. */
		virtual oess_1::char_t *
		out_reserve(
			/*! Количество элементов, которые нужно
				записать. */
			size_t item_count,
			/*! Размер одного элемента в байтах. */
			size_t item_size,
			/*! Количество элементов, доступных для записи по
				возвращенному указателю. */
			size_t & item_available );

		/*! Сдвинуть указатель. Вызывается после успешной
			записи в буфер, указатель на который был
			возвращен методом out_reserve.

			Осуществляет запись фрагмента (части фрагмента)
			из внутреннего буфера в файл. */
		virtual void
		out_shift(
			/*! Количество успешно записанных элементов. */
			size_t item_count,
			/*! Размер одного элемента в байтах. */
			size_t item_size );

	private :
		/*! Буфер для операций ввода-вывода. */
		auto_ptr_3::vect_ptr_t< oess_1::char_t >	m_buf;

		/*! Системный дескриптор файла. */
		int	m_file;
		/*! true, если файл открыт в режиме read-only. */
		bool	m_is_read_only;

		/*! Проверка возможности выполнения операции.
			Если операцию осуществить невозможно, то
			порождается исключение. */
		void
		is_workable(
			/*! true, если операция является read-only
				операцией и не требует изменения содержимого
				файла. */
			bool is_read_only_op ) const;
};

} /*! namespace file */

} /*! namespace oess_1 */

#endif
