/*

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 oess_1/tlv/h/default_processors.hpp
	\brief Реализации интерфесов
	%oess_1::tlv::tag_processor_t,
	%oess_1::tlv::length_processor_t для простейших
	случаев.
*/

#if !defined( _OESS_1__TLV__DEFAULT_PROCESSORS_HPP_ )
#define _OESS_1__TLV__DEFAULT_PROCESSORS_HPP_

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

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

#include <oess_1/tlv/h/base.hpp>

namespace oess_1
{

namespace tlv
{

//
// default_tag_processor_t
//

//! Реализация интерфейса tag_processor_t.
/*!
	Предназначен для случая, когда поле Tag представлено
	в виде одиночного целочисленного значения.
*/
template< class Tag_type = default_tag_type_t >
class	default_tag_processor_t :
	public tag_processor_t
{
	public :
		//! Синоним для default_tag_processor_t< Tag_type >.
		typedef default_tag_processor_t< Tag_type > self_t;

	private :
		//! Значение поля Tag.
		Tag_type	m_id;

	public :
		//! Конструктор по-умолчанию.
		default_tag_processor_t()
			:
				m_id()
		{
		}

		//! Связывает объект с конкретным значением Tag.
		default_tag_processor_t( Tag_type id )
			:
				m_id( id )
		{
		}
		//! Конструктор копирования.
		default_tag_processor_t( const self_t & o )
			:
				m_id( o.m_id )
		{
		}
		virtual ~default_tag_processor_t()
		{
		}

		//! Конструктор копирования.
		self_t &
		operator=( const self_t & o )
		{
			m_id = o.m_id;
			return this;
		}

		//! Возвращает размер двоичного представления Tag_type.
		virtual size_t
		tlv_tag_size() const
		{
			return oess_1::io::bin_data_size_t< Tag_type >::image_size;
		}

		//! Считывает одиночный объект Tag_type из \a s.
		/*!
			Считанное значение сохраняется внутри
			объекта default_tag_processor_t.
		*/
		virtual void
		tlv_unpack_tag(
			//! Поток, с текущей позиции которого будет
			//! осуществляться чтение поля Tag.
			oess_1::io::ibinstream_t & s )
		{
			s >> m_id;
		}

		//! Записывает одиночный объект Tag_type в \a s.
		/*!
			Записывается текущее значение объекта
			default_tag_type_t.
		*/
		virtual void
		tlv_pack_tag(
			//! Поток, с текущей позиции которого будет
			//! осуществляться запись поля Tag.
			oess_1::io::obinstream_t & s ) const
		{
			s << m_id;
		}

		//! Получить текущее значение.
		virtual default_tag_type_t
		query_tag() const
		{
			return (default_tag_type_t) m_id;
		}

		//! Установить текущее значение.
		virtual void
		set_tag( const default_tag_type_t & value )
		{
			m_id = value;
		}
};

//! Вызывает метод tlv_unpack_tag у \a o.
inline oess_1::io::ibinstream_t &
operator>>(
	//! Поток, с текущей позиции которого будет
	//! осуществляться чтение поля Tag.
	oess_1::io::ibinstream_t & s,
	//! Объект для извлечения.
	tag_processor_t & o )
{
	o.tlv_unpack_tag( s );
	return s;
}

//! Вызывает метод tlv_pack_tag у \a o.
inline oess_1::io::obinstream_t &
operator<<(
	//! Поток, с текущей позиции которого будет
	//! осуществляться запись поля Tag.
	oess_1::io::obinstream_t & s,
	//! Объект для записи.
	const tag_processor_t & o )
{
	o.tlv_pack_tag( s );
	return s;
}

//
// default_length_processor_t
//

//! Реализация интерфейса length_processor_t.
/*!
	Предназначен для случая, когда поле Length представлено
	в виде одиночного целочисленного значения.
*/
template< class Length_type >
class	default_length_processor_t :
	public length_processor_t
{
	public :
		default_length_processor_t()
		{
		}
		
		virtual ~default_length_processor_t()
		{
		}

		//! Возвращает размер двоичного представления
		//! Length_type
		virtual size_t
		tlv_length_size(
			//! Длина тела TLV.
			size_t value_length ) const
		{
			return oess_1::io::bin_data_size_t< Length_type >::image_size;
		}

		//! Считывает одичночный объект Length_type из \a s.
		virtual void
		tlv_unpack_length(
			//! Поток, с текущей позиции которого будет
			//! осуществляться чтение поля Length.
			oess_1::io::ibinstream_t & s,
			//! Приемник значения поля Length
			size_t & value_length )
		{
			Length_type l;
			s >> l;
			value_length = l;
		}

		//! Записывает одиночный объект Length в \a s.
		virtual void
		tlv_pack_length(
			//! Поток, с текущей позиции которого будет
			//! осуществляться запись поля Length.
			oess_1::io::obinstream_t & s,
			//! Значение поля Length.
			size_t value_length ) const
		{
			Length_type l = value_length;
			s << l;
		}
};

} /* namespace tlv */

} /* namespace oess_1 */

#endif

