/*

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/basic_string.hpp
	\brief Класс %oess_1::tlv::basic_string_tlv_t.
*/

#if !defined( _OESS_1__TLV__BASIC_STRING_HPP_ )
#define _OESS_1__TLV__BASIC_STRING_HPP_

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

#include <string>

#include <auto_ptr_3/h/vect_ptr.hpp>

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

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

namespace oess_1
{

namespace tlv
{

//
// basic_string_tlv_t
//

//! TLV для сериализации объектов std::basic_string.
/*!
	Поле Length содержит длину строки, умноженную на
	размер двоичного представления одного символа
	(т.е. для oess_1::char_t длину строки).

	Для пустой строки сохраняются в выходном потоке
	только поле Tag и нулевое поле Length.
*/
template< class Tag_type,
	class Char = oess_1::char_t,
	class Tag_processor = default_tag_processor_t< Tag_type >,
	class Length_processor = default_length_processor_t< Tag_type > >
class	basic_string_tlv_t :
	public tlv_base_t
{
	public :
		//! Синоним для std::basic_string< Char >.
		typedef std::basic_string< Char > string_type_t;

		//! Синоним для string_type_t.
		typedef string_type_t	value_type_t;

		//! Синоним для basic_string_tlv_t< Tag_type, Char,
		//! Tag_processor, Length_processor >.
		typedef basic_string_tlv_t< Tag_type, Char,
				Tag_processor, Length_processor >
			self_t;

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

		//! Обработчик поля Length.
		Length_processor	m_length;

		//! Значение поля Value.
		string_type_t	m_value;

	public :
		//! Присваивает пустое значение полю Value.
		basic_string_tlv_t( Tag_type id )
			:
				m_tag( id )
		{
		}

		//! Назначение значения полю Value.
		basic_string_tlv_t(
			Tag_type id,
			const string_type_t & value )
			:
				m_tag( id ),
				m_value( value )
		{
		}

		//! Конструктор копирования.
		basic_string_tlv_t(
			const self_t & o )
			:
				m_tag( o.m_tag ),
				m_length( o.m_length ),
				m_value( o.m_value )
		{
		}

		virtual ~basic_string_tlv_t()
		{
		}

		//! Оператор копирования.
		self_t &
		operator=( const self_t & o )
		{
			if( &o != this )
			{
				m_tag = o.m_tag;
				m_length = o.m_length;
				m_value = o.m_value;
			}
			return *this;
		}

		//! Получить текущее значение поля Value.
		const string_type_t &
		query_value() const
		{
			return m_value;
		}

		//! Установить значение поля Value.
		void
		set_value(
			//! Новое значение для поля Value.
			const string_type_t & value )
		{
			m_value = value;
		}

		//! Получить значение поля Tag.
		virtual default_tag_type_t
		tlv_tag() const
		{
			return m_tag.query_tag();
		}

		//! Количество байт, которые требуются
		//! для представления всего TLV (с учетом Tag, Length,
		//! Value).
		virtual size_t
		tlv_size() const
		{
			size_t length = m_value.length() *
				oess_1::io::bin_data_size_t< Char >::image_size;
			length += m_length.tlv_length_size( length );
			length += m_tag.tlv_tag_size();

			return length;
		}

		//! Извлечение полей Length и Value из входного потока.
		/*!
			Если поле Length содержит ноль, то из потока
			ничего не считывается, а полю Value сразу
			присваивается пустое значение.
		*/
		virtual void
		tlv_unpack(
			//! Поток, с текущей позиции которого будет
			//! осуществляться чтение полей Length и Value.
			oess_1::io::ibinstream_t & s,
			//! В данном классе игнорируется.
			default_tag_type_t )
		{
			size_t length;
			m_length.tlv_unpack_length( s, length );
			if( length )
			{
				auto_ptr_3::vect_ptr_t< Char > tmp(
					new Char[ length ], length );
				s.read( tmp.query(), length );

				m_value.assign( tmp.query(), length );
			}
			else
				// В VC++ 6.0 в классе basic_string нет метода clear!
				m_value.erase( m_value.begin(), m_value.end() );
		}

		//! Запись TLV в выходной поток.
		/*!
			Записываются все поля (Tag, Length, Value).
			Если длина Value равна 0, то записывается только
			Tag и нулевое значение поля Length.
		*/
		virtual void
		tlv_pack(
			//! Поток, с текущей позиции которого будет
			//! осуществляться запись TLV.
			oess_1::io::obinstream_t & s ) const
		{
			size_t length = m_value.length() *
				oess_1::io::bin_data_size_t< Char >::image_size;

			m_tag.tlv_pack_tag( s );
			m_length.tlv_pack_length( s, length );
			if( length )
				s.write( m_value.data(), m_value.length() );
		}
};

} /* namespace tlv */

} /* namespace oess_1 */

#endif

