/*
 *  The contents of this file are subject to the Initial
 *  Developer's Public License Version 1.0 (the "License");
 *  you may not use this file except in compliance with the
 *  License. You may obtain a copy of the License at
 *  http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
 *
 *  Software distributed under the License is distributed AS IS,
 *  WITHOUT WARRANTY OF ANY KIND, either express or implied.
 *  See the License for the specific language governing rights
 *  and limitations under the License.
 *
 *  The Original Code was created by Claudio Valderrama on 3-Mar-2007
 *  for the Firebird Open Source RDBMS project.
 *
 *  Copyright (c) 2007 Claudio Valderrama
 *  and all contributors signed below.
 *
 *  The author thanks specially Fred Polizo Jr and Adriano dos Santos Fernandes
 *  for comments and corrections.
 *
 *  All Rights Reserved.
 *  Contributor(s): ______________________________________.
 *
 */


// Localized messages type-safe printing facility.

#ifndef FB_SAFEARG_H
#define FB_SAFEARG_H

// Definitions to generate fixed-length integral data types.
#ifdef _MSC_VER
typedef _int64 int64_t;
typedef unsigned _int64 uint64_t;
typedef _int32 int32_t;
typedef unsigned _int32 uint32_t;
typedef _int16 int16_t;
typedef unsigned _int16 uint16_t;
/* These macros were used to generate constants for testing.
#define c64(n) (n)
#define uc64(n) (n)
#else
#define c64(n) (n##LL)
#define uc64(n) (n##ULL)
*/
#endif

#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif

// Just an emulation of 128-bit numbers for now.
struct DoubleQuad
{
	int64_t high;
	uint64_t low;
};

typedef DoubleQuad SINT128;


namespace MsgFormat
{

// For now we allow 9 parameters; @1..@9 in MsgPrint.
const FB_SIZE_T SAFEARG_MAX_ARG = 9;

// This is the unit that represents one parameter in the format routines.
// The user of the routines rarely needs to be concerned with it.
// For now it contains only the data type and the value.
struct safe_cell
{
	enum arg_type
	{
		at_none,
		at_char,
		at_uchar,
		//at_int16,
		//at_int32,
		at_int64,
		at_uint64,
		at_int128,
		at_double,
		at_str,
		at_ptr
	};

	struct safe_str
	{
		const char* s_string;
	};


	arg_type type;
	union
	{
		unsigned char c_value;
		int64_t i_value;
		SINT128 i128_value;
		double d_value;
		safe_str st_value;
		void* p_value;
	};
};



class BaseStream;

// This is the main class that does the magic of receiving a chain of type-safe
// parameters. All parameters should be appended to it using the << operator.
// Only basic data types are supported.
// The allowed types are char, UCHAR, all lengths of signed/unsigned integral values,
// the SINT128 fake type (a struct, really), double, strings, UCHAR strings and the
// (non-const) void pointer. Care should be taken to not pass something by address
// (except char* and UCHAR* types) because the compiler may route it to the overload
// for the void pointer and it will be printed as an address in hex.
// An object of this class can be created, filled and passed later to the printing
// routines, cleaned with clear(), refilled and passed again to the printing routines
// or simply constructed as an anonymous object and being filled at the same time
// that it serves as input to the printing routines (the MsgPrint family).
// Using << to pass more than 7 parameters will ignore the rest of the parameters
// silently instead of throwing exceptions or crashing.
// Only the full MsgPrint is declared a friend below, so the other routines should
// work through it.
// Typically the construction doesn't have parameters, but there's an overload
// that takes an array of integers. If the array has more than 7 elements, the
// rest are ignored. Then probably no more parameters will be pushed using <<.
// A dump() method is provided to dump all the parameters to a TEXT array or up
// to the number of elements in the target array if it's smallers than the number
// of parameters in SafeArg. In case it's bigger, the elements are set to NULL.
// Finally getCount() and getCell() are provided for the rare need to loop
// retrieving individual parameters as safe_cell structures. No provision is
// made to modify parameters once pushed into a SafeArg object.
// The parameter formatting is just an indication for the future, thus the
// m_extras pointer is not used for now. No need for parameter formatting (like
// alignment, width, precision, padding, numeric base) was evident as the msg.fdb
// contains rather simple format strings.
// Usage examples appear in the MsgPrint.h file.
class SafeArg
{
public:
	SafeArg();
	SafeArg(const int val[], FB_SIZE_T v_size);
	SafeArg& clear();
	SafeArg& operator<<(char c);
	SafeArg& operator<<(unsigned char c);
	//SafeArg& operator<<(int16_t c);
	SafeArg& operator<<(short c);
	SafeArg& operator<<(unsigned short c);
	//SafeArg& operator<<(int32_t c);
	SafeArg& operator<<(int c);
	SafeArg& operator<<(unsigned int c);
	SafeArg& operator<<(long int c);
	SafeArg& operator<<(unsigned long int c);
	SafeArg& operator<<(SINT64 c);
	SafeArg& operator<<(FB_UINT64 c);
	//SafeArg& operator<<(long c);
	SafeArg& operator<<(SINT128 c);
	SafeArg& operator<<(double c);
	SafeArg& operator<<(const char* c);
	SafeArg& operator<<(const unsigned char* c);
	SafeArg& operator<<(void* c);
	void dump(const TEXT* target[], FB_SIZE_T v_size) const;
	const safe_cell& getCell(FB_SIZE_T index) const;
	FB_SIZE_T getCount() const throw();

private:
	FB_SIZE_T m_count;
	safe_cell m_arguments[SAFEARG_MAX_ARG];
	const void* m_extras; // Formatting, etc.

	friend int MsgPrint(BaseStream& out_stream, const char* format, const SafeArg& arg,
		bool userFormatting);
};

inline SafeArg::SafeArg()
	: m_count(0), m_extras(0)
{
}

inline SafeArg& SafeArg::clear()
{
	m_count = 0;
	m_extras = 0;
	return *this;
}

inline FB_SIZE_T SafeArg::getCount() const throw()
{
	return m_count;
}

} // namespace

#endif // FB_SAFEARG_H
