/*

cls_2: Curl Like Syntax
Yauheni A. Akhotnikau (C) 2001-2003
eao197@yahoo.com
-------------------------------------------------

Permission is granted to anyone to use this software for any purpose on any
computer system, and to redistribute it freely, subject to the following
restrictions:

1. This software is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

2. The origin of this software must not be misrepresented, either by
   explicit claim or by omission.

3. Altered versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

-------------------------------------------------

*/
#if !defined( _CLS_2__SCALAR__FORMAT_HPP_ )
#define _CLS_2__SCALAR__FORMAT_HPP_

#include <stdio.h>

#include <string>

#include <auto_ptr_3/h/vect_ptr.hpp>

#include <cls_2/h/cls.hpp>
#include <cls_2/h/to_cls_format.hpp>
#include <cls_2/h/_check_digits.hpp>

namespace cls_2 {

//
// scalar_format_t
//

/*
	Template interface for scalar (single) value parsers.
	This templates only defined nesessary operations.
*/
template< class T >
class	scalar_format_t {
	public :
		// Called for processing 'NONSPACE' token
		// Default implementation returns c_ok
		static int
		on_tok_nonspace(
			parser_context_t & context,
			const char * tok_value,
			T & result ) {
			return c_ok;
		}

		// Called for processing 'STRING' token
		// Default implementation returns c_ok
		static int
		on_tok_string(
			parser_context_t & context,
			const char * tok_value,
			T & result ) {
			return c_ok;
		}

		// Called for formating valid value
		const char *
		format( const T & value ) {
			return "";
		}

		// Called for formating disallowed value
		// during error reporting. This method
		// can make several representation of value.
		// For example: disallowed long value
		// may be formated as "<dec_value> (<hex_value>)"
		const char *
		format_disallowed_value( const T & value ) {
			return format( value );
		}
};

//
// scalar_format_t< long >
//
template<>
class	scalar_format_t< long > {
	public :
		static int
		on_tok_nonspace(
			parser_context_t & context,
			const char * tok_value,
			long & result ) {
			if( !parse_digits( tok_value, result ) ) {
				context.show_error( tok_value );
				context.show_error( context.find_msg(
					c_msg_invalid_value ) );

				return c_syntax_error;
			}
			return c_ok;
		}

		static int
		on_tok_string(
			parser_context_t & context,
			const char * tok_value,
			long & result ) {
			context.show_error( context.find_msg(
				c_msg_unexpected_tok_string ) );

			return c_semantic_error;
		}

		const char *
		format(
			const long & value ) {
			sprintf( m_buf, "%ld", value );
			return m_buf;
		}

		const char *
		format_disallowed_value(
			const long & value ) {
			sprintf( m_buf_disallowed_value, "%ld (0x%lx)", value, value );
			return m_buf_disallowed_value;
		}

	protected :
		char	m_buf[ 16 ];
		char	m_buf_disallowed_value[ 32 ];
};

//
// scalar_format_t< unsigned long >
//
template<>
class	scalar_format_t< unsigned long > {
	public :
		static int
		on_tok_nonspace(
			parser_context_t & context,
			const char * tok_value,
			unsigned long & result ) {
			if( !parse_digits( tok_value, result ) ) {
				context.show_error( tok_value );
				context.show_error( context.find_msg(
					c_msg_invalid_value ) );

				return c_syntax_error;
			}
			return c_ok;
		}

		static int
		on_tok_string(
			parser_context_t & context,
			const char * tok_value,
			unsigned long & result ) {
			context.show_error( context.find_msg(
				c_msg_unexpected_tok_string ) );

			return c_semantic_error;
		}

		const char *
		format(
			const unsigned long & value ) {
			sprintf( m_buf, "%lu", value );
			return m_buf;
		}

		const char *
		format_disallowed_value(
			const unsigned long & value ) {
			sprintf( m_buf_disallowed_value, "%lu (0x%lx)", value, value );
			return m_buf_disallowed_value;
		}

	protected :
		char	m_buf[ 16 ];
		char	m_buf_disallowed_value[ 32 ];
};

//
// scalar_format_t< int >
//

/*!
	\since v.2.5.1

	\todo Проверять диапазон значения.

	Специализация шаблона scalar_format_t для int.
*/
template<>
class	scalar_format_t< int >
{
	public :
		static int
		on_tok_nonspace(
			parser_context_t & context,
			const char * tok_value,
			int & result )
		{
			long tmp;
			if( !parse_digits( tok_value, tmp ) )
			{
				context.show_error( tok_value );
				context.show_error( context.find_msg(
					c_msg_invalid_value ) );

				return c_syntax_error;
			}
			result = (int)tmp;
			return c_ok;
		}

		static int
		on_tok_string(
			parser_context_t & context,
			const char * tok_value,
			int & result )
		{
			context.show_error( context.find_msg(
				c_msg_unexpected_tok_string ) );

			return c_semantic_error;
		}

		const char *
		format(
			const int & value )
		{
			sprintf( m_buf, "%d", value );
			return m_buf;
		}

		const char *
		format_disallowed_value(
			const int & value )
		{
			sprintf( m_buf_disallowed_value, "%d (0x%x)", value, value );
			return m_buf_disallowed_value;
		}

	protected :
		char	m_buf[ 16 ];
		char	m_buf_disallowed_value[ 32 ];
};

//
// scalar_format_t< unsigned int >
//
/*!
	\since v.2.5.1

	\todo Проверять диапазон значения.

	Специализация шаблона scalar_format_t для unsigned int.
*/
template<>
class	scalar_format_t< unsigned int > {
	public :
		static int
		on_tok_nonspace(
			parser_context_t & context,
			const char * tok_value,
			unsigned int & result )
		{
			unsigned long tmp;
			if( !parse_digits( tok_value, tmp ) )
			{
				context.show_error( tok_value );
				context.show_error( context.find_msg(
					c_msg_invalid_value ) );

				return c_syntax_error;
			}

			result = (unsigned int)tmp;
			return c_ok;
		}

		static int
		on_tok_string(
			parser_context_t & context,
			const char * tok_value,
			unsigned int & result )
		{
			context.show_error( context.find_msg(
				c_msg_unexpected_tok_string ) );

			return c_semantic_error;
		}

		const char *
		format(
			const unsigned int & value )
		{
			sprintf( m_buf, "%u", value );
			return m_buf;
		}

		const char *
		format_disallowed_value(
			const unsigned int & value )
		{
			sprintf( m_buf_disallowed_value, "%u (0x%x)", value, value );
			return m_buf_disallowed_value;
		}

	protected :
		char	m_buf[ 16 ];
		char	m_buf_disallowed_value[ 32 ];
};

//
// scalar_format_t< double >
//
template<>
class	scalar_format_t< double > {
	public :
		static int
		on_tok_nonspace(
			parser_context_t & context,
			const char * tok_value,
			double & result ) {
			if( !parse_digits( tok_value, result ) ) {
				context.show_error( tok_value );
				context.show_error( context.find_msg(
					c_msg_invalid_value ) );

				return c_syntax_error;
			}
			return c_ok;
		}

		static int
		on_tok_string(
			parser_context_t & context,
			const char * tok_value,
			double & result ) {
			context.show_error( context.find_msg(
				c_msg_unexpected_tok_string ) );

			return c_semantic_error;
		}

		const char *
		format(
			const double & value ) {
			sprintf( m_buf, "%lg", value );
			return m_buf;
		}

		const char *
		format_disallowed_value( const double & value ) {
			return format( value );
		}

	protected :
		char	m_buf[ 32 ];
};

//
// scalar_format_t< std::string >
//
template<>
class	scalar_format_t< std::string > {
	public :
		typedef std::string	value_type_t;

	public :
		scalar_format_t< std::string >() {
		}

		~scalar_format_t< std::string >() {
		}

		static int
		on_tok_nonspace(
			parser_context_t & context,
			const char * tok_value,
			value_type_t & result ) {
			context.show_error( context.find_msg(
				c_msg_unexpected_tok_nonspace ) );

			return c_semantic_error;
		}

		static int
		on_tok_string(
			parser_context_t & context,
			const char * tok_value,
			value_type_t & result ) {
			result = tok_value;

			return c_ok;
		}

		const char *
		format(
			const value_type_t & value ) {
			m_fmt_value.destroy();

			m_fmt_value.set( to_cls_format_t::format_string(
				value.c_str() ), 0 );
			return m_fmt_value.query();
		}

		const char *
		format_disallowed_value(
			const value_type_t & value ) {
			return value.c_str();
		}

	protected :
		// Result of formatting
		auto_ptr_3::vect_ptr_t< char >	m_fmt_value;
};

} /* namespace cls_2 */

#endif
