//
// Compare two values.
//
bool SortCompareStrArrayElement::operator()(const CDT & oX, const CDT & oY) const
{
	INT_32 iRC = 0;

	const CDT & oXX = oX.GetCDT(iIndex);
	const CDT & oYY = oY.GetCDT(iIndex);

	if      (oXX.Less(oYY))    { iRC = -1; }
	else if (oXX.Greater(oYY)) { iRC =  1; }

	if (eDirection == CDT::SortingComparator::DESC) { iRC = -iRC; }

return iRC < 0;
}
//
// Compare two values.
//
bool SortCompareNumHashElement::operator()(const CDT & oX, const CDT & oY) const
{
	INT_32 iRC = 0;

	const CDT & oXX = oX.GetCDT(sKey);
	const CDT & oYY = oY.GetCDT(sKey);

	if      (oXX < oYY) { iRC = -1; }
	else if (oXX > oYY) { iRC =  1; }

	if (eDirection == CDT::SortingComparator::DESC) { iRC = -iRC; }

return iRC < 0;
}
//
// Dump to string
//
void DumpData(UINT_32 iLevel, const CDT & oData, std::string &sResult)
{
	CHAR_8 szBuf[512 + 1];

	++iLevel;
	switch (oData.GetType())
	{
		case CDT::UNDEF:
		case CDT::INT_VAL:
		case CDT::REAL_VAL:
		case CDT::STRING_VAL:
		case CDT::POINTER_VAL:
			sResult += "\"" + oData.GetString() + "\"\n";
			break;

		case CDT::ARRAY_VAL:
			{
				sResult += "\n";
				for (UINT_32 iI = 0; iI < oData.Size(); ++iI)
				{
					for (UINT_32 iJ = 0; iJ < iLevel; iJ++) { sResult += "      "; }
					snprintf(szBuf, 512, "%u", iI);
					sResult += szBuf;
					sResult += " : ";
					DumpData(iLevel, oData.GetCDT(iI), sResult);
				}
			}
			break;

		case CDT::HASH_VAL:
			{
				sResult += "\n";
				CDT::ConstIterator itHash = oData.Begin();
				while (itHash != oData.End())
				{
					for (UINT_32 iJ = 0; iJ < iLevel; iJ++) { sResult += "      "; }
					sResult += itHash -> first;
					sResult += " => ";
					DumpData(iLevel, itHash -> second, sResult);
					++itHash;
				}
			}
			break;

		default:
			sResult += "Invalid type";
	}
}
INT_32 FormatString(const STLW::string & sFormatString, STLW::string & sResult, const CDT & oArgs)
{
	using namespace CTPP;
	StringBuffer oBuffer(sResult);

	CCHAR_P sPos = sFormatString.data();
	CCHAR_P sEnd = sFormatString.data() + sFormatString.size();
	CCHAR_P sEndSave = sPos;

	UINT_32 iPos = 0;
	for(;;)
	{
		INT_32   iWidth            = -1;
		INT_32   iPrecision        = -1;
		CHAR_8   chPadSymbol       = ' ';
		UINT_32  iFmtFlags         = 0;
		eFmtLengths   oFmtLengths  = F_NONE;
		eParserState  oParserState = C_INITIAL_STATE;
		// Find "%" at start of token
		while(sPos != sEnd)
		{
			if (*sPos == '%')
			{
				oParserState = C_START_FOUND;
				break;
			}
			++sPos;
		}
		oBuffer.Append(sEndSave, sPos);

		if (oParserState == C_START_FOUND)
		{
			++sPos;
			// Check end of string
			if (sPos == sEnd) { return -1; }

			bool bEndCycle = false;
			while (!bEndCycle)
			{
				// Flags
				switch(*sPos)
				{
					// '-' Left-justify within the given field width; Right justification is the default (see width sub-specifier).
					case '-':
						iFmtFlags |= F_LEFT_ALIGN;
						++sPos;
						break;

					// '+' Forces to preceed the result with a plus or minus sign (+ or -) even for positive numbers.
					//     By default, only negative numbers are preceded with a - sign.
					case '+':
						iFmtFlags |= F_FORCE_SIGN;
						iFmtFlags &= ~F_SIGN_SPACE;
						++sPos;
						break;

					// ' ' (space) If no sign is going to be written, a blank space is inserted before the value.
					case ' ':
						iFmtFlags |= F_SIGN_SPACE;
						iFmtFlags &= ~F_FORCE_SIGN;
						++sPos;
						break;

					// '#' Used with o, x or X specifiers the value is preceeded with 0, 0x or 0X respectively for values different than zero.
					//     Used with e, E and f, it forces the written output to contain a decimal point even if no digits would follow.
					//     By default, if no digits follow, no decimal point is written.
					//     Used with g or G the result is the same as with e or E but trailing zeros are not removed.
					case '#':
						iFmtFlags |= F_HASH_SIGN;
						++sPos;
						break;

					// '0' Left-pads the number with zeroes (0) instead of spaces, where padding is specified (see width sub-specifier).
					case '0':
						chPadSymbol = '0';
						++sPos;
						break;

					default:
						bEndCycle = true;
						break;
				}

				// Check end of string
				if (sPos == sEnd) { return -1; }
			}

			/* Width
			 * number  Minimum number of characters to be printed. If the value to be printed is shorter than this number,
			 *         the result is padded with blank spaces. The value is not truncated even if the result is larger.
			 */
			if (*sPos > '0' && *sPos <= '9')
			{
				iWidth = 0;
				while (sPos != sEnd && (*sPos >= '0' && *sPos <= '9'))
				{
					iWidth = iWidth * 10 + *sPos - '0';
					++sPos;
				}
			}
			/*
			 * '*'     The width is not specified in the format string, but as an additional integer value argument
			 *         preceding the argument that has to be formatted.
			 */
			else if (*sPos == '*')
			{
				iWidth = oArgs.GetCDT(iPos).GetInt();
				++iPos;
				++sPos;
			}

			// Check end of string
			if (sPos == sEnd) { return -1; }

			// .precision
			if (*sPos == '.')
			{
				++sPos;
				if (sPos == sEnd) { return -1; }

				iPrecision = 0;
				if (*sPos >= '0' && *sPos <= '9')
				{
					while (sPos != sEnd && (*sPos >= '0' && *sPos <= '9'))
					{
						iPrecision = iPrecision * 10 + *sPos - '0';
						++sPos;
					}
				}
				else if (*sPos == '*')
				{
					iPrecision = oArgs.GetCDT(iPos).GetInt();
					++iPos;
					++sPos;
				}
			}

			// length
			switch(*sPos)
			{
				// h The argument is interpreted as a short int or unsigned short int (only applies to integer specifiers: i, d, o, u, x and X).
				case 'h':
					oFmtLengths = F_SHORT;
					++sPos;
					break;
				// l The argument is interpreted as a long int or unsigned long int for integer specifiers (i, d, o, u, x and X), and as a wide character or wide character string for specifiers c and s.
				case 'l':
				// L The argument is interpreted as a long double (only applies to floating point specifiers: e, E, f, g and G).
				case 'L':
					{
						oFmtLengths = F_LONG;
						++sPos;
						if (sPos == sEnd) { return -1; }
						if (*sPos == 'l' || *sPos == 'L')
						{
							oFmtLengths = F_LONG_LONG;
							++sPos;
						}
					}
					break;
			}

			// Check end of string
			if (sPos == sEnd) { return -1; }

			// Specifiers
			//  A % followed by another % character will write % to the string.
			if (*sPos == '%') { oBuffer.Append(sPos, 1); }
			else
			{
				const CDT oCurrentArgument = oArgs.GetCDT(iPos);
				++iPos;

				switch(*sPos)
				{
					//  Character 'a'
					case 'c':
						FmtChar(oBuffer, oCurrentArgument, iFmtFlags, iWidth, chPadSymbol);
						break;
					// 'd' or 'i' Signed decimal integer '392'
					case 'd':
					case 'i':
						FmtInt(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, szDigitsLc, F_DECIMAL, 10, iWidth, iPrecision, chPadSymbol);
						break;
					// Scientific notation (mantise/exponent) using e character '3.9265e+2'
					case 'e':
						FmtSci(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, 'e', iWidth, iPrecision, chPadSymbol);
						break;
					// Scientific notation (mantise/exponent) using E character '3.9265E+2'
					case 'E':
						FmtSci(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, 'E', iWidth, iPrecision, chPadSymbol);
						break;
					// Decimal floating point '392.65'
					case 'f':
						FmtFloat(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, 'e', F_FLOAT_F, iWidth, iPrecision, chPadSymbol);
						break;
					// Use the shorter of %e or %f '392.65'
					case 'g':
						FmtFloat(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, 'e', F_FLOAT_G, iWidth, iPrecision, chPadSymbol);
						break;
					case 'F':
						FmtFloat(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, 'E', F_FLOAT_F, iWidth, iPrecision, chPadSymbol);
						break;
					case 'G':
						FmtFloat(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, 'E', F_FLOAT_G, iWidth, iPrecision, chPadSymbol);
						break;
					// Signed octal '610'
					case 'o':
						FmtInt(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, szDigitsLc, F_OCTAL, 8, iWidth, iPrecision, chPadSymbol);
						break;
					// String of characters 'sample'
					case 's':
						FmtString(oBuffer, oCurrentArgument, iFmtFlags, iWidth, iPrecision, chPadSymbol);
						break;
					// Unsigned decimal integer '7235'
					case 'u':
						FmtInt(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, szDigitsLc, F_UNSIGNED, 10, iWidth, iPrecision, chPadSymbol);
						break;
					// Unsigned hexadecimal integer '7fa'
					case 'x':
						FmtInt(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, szDigitsLc, F_HEX, 16, iWidth, iPrecision, chPadSymbol);
						break;
					// Unsigned hexadecimal integer (capital letters) 7FA
					case 'X':
						FmtInt(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, szDigitsUc, F_HEX, 16, iWidth, iPrecision, chPadSymbol);
						break;
					// Pointer address 1a2b3c4e
					case 'p':
						FmtInt(oBuffer, oCurrentArgument, iFmtFlags, oFmtLengths, szDigitsLc, F_POINTER, 16, iWidth, iPrecision, chPadSymbol);
						break;
					// Invalid format; return error code
					default:
						return -1;
				}
				++sPos;
			}

			sEndSave = sPos;
		}

		if (sPos == sEnd) { break; }
	}
	oBuffer.Flush();

return 0;
}