#include "const.h"
#include "int_to_string.h"

#include <climits>

namespace WFMath {

// This takes a pointer pointing to the character after the end of
// a buffer, prints the number into the tail of the buffer,
// and returns a pointer to the first character in the number.
// Make sure your buffer's big enough, this doesn't check.
static char* DoIntToString(unsigned long val, char* bufhead) {
	// deal with any possible encoding problems
	const char digits[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

	*(--bufhead) = '\0';

	if (val == 0)
		*(--bufhead) = '0';
	else
		do {
			*(--bufhead) = digits[val % 10];
			val /= 10;
		} while (val);

	return bufhead;
}

#ifndef _MSC_VER
// note that all floating point math is done at compile time
static const double log_10_of_2 = 0.30102995664;
static const unsigned ul_max_digits = (unsigned)
		(8 * sizeof(unsigned long) // number of bits
		 * log_10_of_2 // base 10 vs. base 2 digits
		 + 1 // log(1) == 0, have to add one for leading digit
		 + numeric_constants<CoordType>::epsilon()); // err on the safe side of roundoff
#else // _MSC_VER
static const unsigned ul_max_digits = 10;
#endif // _MSC_VER

std::string IntToString(unsigned long val) {
	static const unsigned bufsize = ul_max_digits + 1; // add one for \0
	char buffer[bufsize];

	return DoIntToString(val, buffer + bufsize);
}

// Deals with the fact that while, e.g. 0x80000000 (in 32 bit),
// is a valid (negative) signed value, the negative
// of it can only be expressed as an unsigned quantity.
static unsigned long SafeAbs(long val) {
#if LONG_MAX + LONG_MIN >= 0
	// a signed variable can hold -LONG_MIN, we're completely safe
	return (val >= 0) ? val : -val;
#else
	if (val >= 0)
		return val;
	else if (val >= -LONG_MAX) // -LONG_MAX is a valid signed long
		return -val;
	else // LONG_MAX + val < 0
		return LONG_MAX + (unsigned long) (-(LONG_MAX + val));
#endif
}

std::string IntToString(long val) {
	static const unsigned bufsize = ul_max_digits + 2; // one for \0, one for minus sign
	char buffer[bufsize];

	char* bufhead = DoIntToString(SafeAbs(val), buffer + bufsize);

	if (val < 0)
		*(--bufhead) = '-';

	return bufhead;
}

} // namespace WFMath
