// Copyright 2011 Baptiste Lepilleur
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE

#if !defined(JSON_IS_AMALGAMATION)
#include "../jsoncpp/assertions.h"
#include "../jsoncpp/value.h"
#include "../jsoncpp/writer.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <math.h>
#include <sstream>
#include <utility>
#include <cstring>
#include <cassert>
#ifdef JSON_USE_CPPTL
#include <cpptl/conststring.h>
#endif
#include <cstddef> // size_t
#include <algorithm> // min()

#define JSON_ASSERT_UNREACHABLE assert(false)

namespace Json {

// This is a walkaround to avoid the static initialization of Value::null.
// kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
// 8 (instead of 4) as a bit of future-proofing.
#if defined(__ARMEL__)
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
#else
#define ALIGNAS(byte_alignment)
#endif
static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
const unsigned char& kNullRef = kNull[0];
const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
const Value& Value::nullRef = null;

const Int Value::minInt = Int(~(UInt(-1) / 2));
const Int Value::maxInt = Int(UInt(-1) / 2);
const UInt Value::maxUInt = UInt(-1);
#if defined(JSON_HAS_INT64)
const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
const UInt64 Value::maxUInt64 = UInt64(-1);
// The constant is hard-coded because some compiler have trouble
// converting Value::maxUInt64 to a double correctly (AIX/xlC).
// Assumes that UInt64 is a 64 bits integer.
static const double maxUInt64AsDouble = 18446744073709551615.0;
#endif // defined(JSON_HAS_INT64)
const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
const LargestUInt Value::maxLargestUInt = LargestUInt(-1);

#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
template<typename T, typename U>
static inline bool InRange(double d, T min, U max) {
	return d >= min && d <= max;
}
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
static inline double integerToDouble(Json::UInt64 value) {
	return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1);
}

template <typename T> static inline double integerToDouble(T value) {
	return static_cast<double>(value);
}

template <typename T, typename U>
static inline bool InRange(double d, T min, U max) {
	return d >= integerToDouble(min) && d <= integerToDouble(max);
}
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)

/** Duplicates the specified string value.
 * @param value Pointer to the string to duplicate. Must be zero-terminated if
 *              length is "unknown".
 * @param length Length of the value. if equals to unknown, then it will be
 *               computed using strlen(value).
 * @return Pointer on the duplicate instance of string.
 */
static inline char* duplicateStringValue(const char* value, size_t length) {
	// Avoid an integer overflow in the call to malloc below by limiting length
	// to a sane value.
	if (length >= (size_t) Value::maxInt)
		length = Value::maxInt - 1;

	char* newString = static_cast<char*>(malloc(length + 1));
	if (newString == NULL) {
		throwRuntimeError("in Json::Value::duplicateStringValue(): "
				"Failed to allocate string value buffer");
	}
	memcpy(newString, value, length);
	newString[length] = 0;
	return newString;
}

/* Record the length as a prefix.
 */
static inline char* duplicateAndPrefixStringValue(const char* value,
		unsigned int length) {
	// Avoid an integer overflow in the call to malloc below by limiting length
	// to a sane value.
	JSON_ASSERT_MESSAGE(
			length <= (unsigned )Value::maxInt - sizeof(unsigned) - 1U,
			"in Json::Value::duplicateAndPrefixStringValue(): "
					"length too big for prefixing");
	unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned))
			+ 1U;
	char* newString = static_cast<char*>(malloc(actualLength));
	if (newString == 0) {
		throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
				"Failed to allocate string value buffer");
	}
	*reinterpret_cast<unsigned*>(newString) = length;
	memcpy(newString + sizeof(unsigned), value, length);
	newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
	return newString;
}
inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
		unsigned* length, char const** value) {
	if (!isPrefixed) {
		*length = static_cast<unsigned>(strlen(prefixed));
		*value = prefixed;
	} else {
		*length = *reinterpret_cast<unsigned const*>(prefixed);
		*value = prefixed + sizeof(unsigned);
	}
}
/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
 */
static inline void releaseStringValue(char* value) {
	free(value);
}

} // namespace Json

// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// ValueInternals...
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
#if !defined(JSON_IS_AMALGAMATION)

#include "../jsoncpp/json_valueiterator.inl"
#endif // if !defined(JSON_IS_AMALGAMATION)

namespace Json {

Exception::Exception(std::string const& msg) :
		msg_(msg) {
}
Exception::~Exception() throw () {
}
char const* Exception::what() const throw () {
	return msg_.c_str();
}
RuntimeError::RuntimeError(std::string const& msg) :
		Exception(msg) {
}
LogicError::LogicError(std::string const& msg) :
		Exception(msg) {
}
void throwRuntimeError(std::string const& msg) {
	throw RuntimeError(msg);
}
void throwLogicError(std::string const& msg) {
	throw LogicError(msg);
}

// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::CommentInfo
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////

Value::CommentInfo::CommentInfo() :
		comment_(0) {
}

Value::CommentInfo::~CommentInfo() {
	if (comment_)
		releaseStringValue(comment_);
}

void Value::CommentInfo::setComment(const char* text, size_t len) {
	if (comment_) {
		releaseStringValue(comment_);
		comment_ = 0;
	}
	JSON_ASSERT(text != 0);
	JSON_ASSERT_MESSAGE(text[0] == '\0' || text[0] == '/',
			"in Json::Value::setComment(): Comments must start with /");
	// It seems that /**/ style comments are acceptable as well.
	comment_ = duplicateStringValue(text, len);
}

// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::CZString
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////

// Notes: policy_ indicates if the string was allocated when
// a string is stored.

Value::CZString::CZString(ArrayIndex aindex) :
		cstr_(0), index_(aindex) {
}

Value::CZString::CZString(char const* str, unsigned ulength,
		DuplicationPolicy allocate) :
		cstr_(str) {
	// allocate != duplicate
	storage_.policy_ = allocate & 0x3;
	storage_.length_ = ulength & 0x3FFFFFFF;
}

Value::CZString::CZString(const CZString& other) :
		cstr_(
				other.storage_.policy_ != noDuplication && other.cstr_ != 0 ?
						duplicateStringValue(other.cstr_,
								other.storage_.length_) :
						other.cstr_) {
	storage_.policy_ = (
			other.cstr_ ?
					(static_cast<DuplicationPolicy>(other.storage_.policy_)
							== noDuplication ? noDuplication : duplicate) :
					static_cast<DuplicationPolicy>(other.storage_.policy_));
	storage_.length_ = other.storage_.length_;
}

Value::CZString::~CZString() {
	if (cstr_ && storage_.policy_ == duplicate)
		releaseStringValue(const_cast<char*>(cstr_));
}

void Value::CZString::swap(CZString& other) {
	std::swap(cstr_, other.cstr_);
	std::swap(index_, other.index_);
}

Value::CZString& Value::CZString::operator=(CZString other) {
	swap(other);
	return *this;
}

bool Value::CZString::operator<(const CZString& other) const {
	if (!cstr_)
		return index_ < other.index_;
	//return strcmp(cstr_, other.cstr_) < 0;
	// Assume both are strings.
	unsigned this_len = this->storage_.length_;
	unsigned other_len = other.storage_.length_;
	unsigned min_len = std::min(this_len, other_len);
	int comp = memcmp(this->cstr_, other.cstr_, min_len);
	if (comp < 0)
		return true;
	if (comp > 0)
		return false;
	return (this_len < other_len);
}

bool Value::CZString::operator==(const CZString& other) const {
	if (!cstr_)
		return index_ == other.index_;
	//return strcmp(cstr_, other.cstr_) == 0;
	// Assume both are strings.
	unsigned this_len = this->storage_.length_;
	unsigned other_len = other.storage_.length_;
	if (this_len != other_len)
		return false;
	int comp = memcmp(this->cstr_, other.cstr_, this_len);
	return comp == 0;
}

ArrayIndex Value::CZString::index() const {
	return index_;
}

//const char* Value::CZString::c_str() const { return cstr_; }
const char* Value::CZString::data() const {
	return cstr_;
}
unsigned Value::CZString::length() const {
	return storage_.length_;
}
bool Value::CZString::isStaticString() const {
	return storage_.policy_ == noDuplication;
}

// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class Value::Value
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////

/*! \internal Default constructor initialization must be equivalent to:
 * memset( this, 0, sizeof(Value) )
 * This optimization is used in ValueInternalMap fast allocator.
 */
Value::Value(ValueType vtype) {
	initBasic(vtype);
	switch (vtype) {
	case nullValue:
		break;
	case intValue:
	case uintValue:
		value_.int_ = 0;
		break;
	case realValue:
		value_.real_ = 0.0;
		break;
	case stringValue:
		value_.string_ = 0;
		break;
	case arrayValue:
	case objectValue:
		value_.map_ = new ObjectValues();
		break;
	case booleanValue:
		value_.bool_ = false;
		break;
	default:
		JSON_ASSERT_UNREACHABLE;
	}
}

Value::Value(Int value) {
	initBasic(intValue);
	value_.int_ = value;
}

Value::Value(UInt value) {
	initBasic(uintValue);
	value_.uint_ = value;
}
#if defined(JSON_HAS_INT64)
Value::Value(Int64 value) {
	initBasic(intValue);
	value_.int_ = value;
}
Value::Value(UInt64 value) {
	initBasic(uintValue);
	value_.uint_ = value;
}
#endif // defined(JSON_HAS_INT64)

Value::Value(double value) {
	initBasic(realValue);
	value_.real_ = value;
}

Value::Value(const char* value) {
	initBasic(stringValue, true);
	value_.string_ = duplicateAndPrefixStringValue(value,
			static_cast<unsigned>(strlen(value)));
}

Value::Value(const char* beginValue, const char* endValue) {
	initBasic(stringValue, true);
	value_.string_ = duplicateAndPrefixStringValue(beginValue,
			static_cast<unsigned>(endValue - beginValue));
}

Value::Value(const std::string& value) {
	initBasic(stringValue, true);
	value_.string_ = duplicateAndPrefixStringValue(value.data(),
			static_cast<unsigned>(value.length()));
}

Value::Value(const StaticString& value) {
	initBasic(stringValue);
	value_.string_ = const_cast<char*>(value.c_str());
}

#ifdef JSON_USE_CPPTL
Value::Value(const CppTL::ConstString& value) {
	initBasic(stringValue, true);
	value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(value.length()));
}
#endif

Value::Value(bool value) {
	initBasic(booleanValue);
	value_.bool_ = value;
}

Value::Value(Value const& other) :
		type_(other.type_), allocated_(false), comments_(0), start_(
				other.start_), limit_(other.limit_) {
	switch (type_) {
	case nullValue:
	case intValue:
	case uintValue:
	case realValue:
	case booleanValue:
		value_ = other.value_;
		break;
	case stringValue:
		if (other.value_.string_ && other.allocated_) {
			unsigned len;
			char const* str;
			decodePrefixedString(other.allocated_, other.value_.string_, &len,
					&str);
			value_.string_ = duplicateAndPrefixStringValue(str, len);
			allocated_ = true;
		} else {
			value_.string_ = other.value_.string_;
			allocated_ = false;
		}
		break;
	case arrayValue:
	case objectValue:
		value_.map_ = new ObjectValues(*other.value_.map_);
		break;
	default:
		JSON_ASSERT_UNREACHABLE;
	}
	if (other.comments_) {
		comments_ = new CommentInfo[numberOfCommentPlacement];
		for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
			const CommentInfo& otherComment = other.comments_[comment];
			if (otherComment.comment_)
				comments_[comment].setComment(otherComment.comment_,
						strlen(otherComment.comment_));
		}
	}
}

Value::~Value() {
	switch (type_) {
	case nullValue:
	case intValue:
	case uintValue:
	case realValue:
	case booleanValue:
		break;
	case stringValue:
		if (allocated_)
			releaseStringValue(value_.string_);
		break;
	case arrayValue:
	case objectValue:
		delete value_.map_;
		break;
	default:
		JSON_ASSERT_UNREACHABLE;
	}

	if (comments_)
		delete[] comments_;
}

Value& Value::operator=(Value other) {
	swap(other);
	return *this;
}

void Value::swapPayload(Value& other) {
	ValueType temp = type_;
	type_ = other.type_;
	other.type_ = temp;
	std::swap(value_, other.value_);
	int temp2 = allocated_;
	allocated_ = other.allocated_;
	other.allocated_ = temp2 & 0x1;
}

void Value::swap(Value& other) {
	swapPayload(other);
	std::swap(comments_, other.comments_);
	std::swap(start_, other.start_);
	std::swap(limit_, other.limit_);
}

ValueType Value::type() const {
	return type_;
}

int Value::compare(const Value& other) const {
	if (*this < other)
		return -1;
	if (*this > other)
		return 1;
	return 0;
}

bool Value::operator<(const Value& other) const {
	int typeDelta = type_ - other.type_;
	if (typeDelta)
		return typeDelta < 0 ? true : false;
	switch (type_) {
	case nullValue:
		return false;
	case intValue:
		return value_.int_ < other.value_.int_;
	case uintValue:
		return value_.uint_ < other.value_.uint_;
	case realValue:
		return value_.real_ < other.value_.real_;
	case booleanValue:
		return value_.bool_ < other.value_.bool_;
	case stringValue: {
		if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
			if (other.value_.string_)
				return true;
			else
				return false;
		}
		unsigned this_len;
		unsigned other_len;
		char const* this_str;
		char const* other_str;
		decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
				&this_str);
		decodePrefixedString(other.allocated_, other.value_.string_, &other_len,
				&other_str);
		unsigned min_len = std::min(this_len, other_len);
		int comp = memcmp(this_str, other_str, min_len);
		if (comp < 0)
			return true;
		if (comp > 0)
			return false;
		return (this_len < other_len);
	}
	case arrayValue:
	case objectValue: {
		int delta = int(value_.map_->size() - other.value_.map_->size());
		if (delta)
			return delta < 0;
		return (*value_.map_) < (*other.value_.map_);
	}
	default:
		JSON_ASSERT_UNREACHABLE;
	}
	return false; // unreachable
}

bool Value::operator<=(const Value& other) const {
	return !(other < *this);
}

bool Value::operator>=(const Value& other) const {
	return !(*this < other);
}

bool Value::operator>(const Value& other) const {
	return other < *this;
}

bool Value::operator==(const Value& other) const {
	// if ( type_ != other.type_ )
	// GCC 2.95.3 says:
	// attempt to take address of bit-field structure member `Json::Value::type_'
	// Beats me, but a temp solves the problem.
	int temp = other.type_;
	if (type_ != temp)
		return false;
	switch (type_) {
	case nullValue:
		return true;
	case intValue:
		return value_.int_ == other.value_.int_;
	case uintValue:
		return value_.uint_ == other.value_.uint_;
	case realValue:
		return value_.real_ == other.value_.real_;
	case booleanValue:
		return value_.bool_ == other.value_.bool_;
	case stringValue: {
		if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
			return (value_.string_ == other.value_.string_);
		}
		unsigned this_len;
		unsigned other_len;
		char const* this_str;
		char const* other_str;
		decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
				&this_str);
		decodePrefixedString(other.allocated_, other.value_.string_, &other_len,
				&other_str);
		if (this_len != other_len)
			return false;
		int comp = memcmp(this_str, other_str, this_len);
		return comp == 0;
	}
	case arrayValue:
	case objectValue:
		return value_.map_->size() == other.value_.map_->size()
				&& (*value_.map_) == (*other.value_.map_);
	default:
		JSON_ASSERT_UNREACHABLE;
	}
	return false; // unreachable
}

bool Value::operator!=(const Value& other) const {
	return !(*this == other);
}

const char* Value::asCString() const {
	JSON_ASSERT_MESSAGE(type_ == stringValue,
			"in Json::Value::asCString(): requires stringValue");
	if (value_.string_ == 0)
		return 0;
	unsigned this_len;
	char const* this_str;
	decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
			&this_str);
	return this_str;
}

bool Value::getString(char const** str, char const** cend) const {
	if (type_ != stringValue)
		return false;
	if (value_.string_ == 0)
		return false;
	unsigned length;
	decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
	*cend = *str + length;
	return true;
}

std::string Value::asString() const {
	switch (type_) {
	case nullValue:
		return "";
	case stringValue: {
		if (value_.string_ == 0)
			return "";
		unsigned this_len;
		char const* this_str;
		decodePrefixedString(this->allocated_, this->value_.string_, &this_len,
				&this_str);
		return std::string(this_str, this_len);
	}
	case booleanValue:
		return value_.bool_ ? "true" : "false";
	case intValue:
		return valueToString(value_.int_);
	case uintValue:
		return valueToString(value_.uint_);
	case realValue:
		return valueToString(value_.real_);
	default: {
		JSON_FAIL_MESSAGE("Type is not convertible to string");
		return "Type is not convertible to string";
	}
	}
}

#ifdef JSON_USE_CPPTL
CppTL::ConstString Value::asConstString() const {
	unsigned len;
	char const* str;
	decodePrefixedString(allocated_, value_.string_,
			&len, &str);
	return CppTL::ConstString(str, len);
}
#endif

Value::Int Value::asInt() const {
	switch (type_) {
	case intValue:
		JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range")
		;
		return Int(value_.int_);
	case uintValue:
		JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range")
		;
		return Int(value_.uint_);
	case realValue:
		JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
				"double out of Int range")
		;
		return Int(value_.real_);
	case nullValue:
		return 0;
	case booleanValue:
		return value_.bool_ ? 1 : 0;
	default:
		break;
	}
	JSON_FAIL_MESSAGE("Value is not convertible to Int.");
	return false;
}

Value::UInt Value::asUInt() const {
	switch (type_) {
	case intValue:
		JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range")
		;
		return UInt(value_.int_);
	case uintValue:
		JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range")
		;
		return UInt(value_.uint_);
	case realValue:
		JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
				"double out of UInt range")
		;
		return UInt(value_.real_);
	case nullValue:
		return 0;
	case booleanValue:
		return value_.bool_ ? 1 : 0;
	default:
		break;
	}
	JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
	return false;
}

#if defined(JSON_HAS_INT64)

Value::Int64 Value::asInt64() const {
	switch (type_) {
	case intValue:
		return Int64(value_.int_);
	case uintValue:
		JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range")
		;
		return Int64(value_.uint_);
	case realValue:
		JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
				"double out of Int64 range")
		;
		return Int64(value_.real_);
	case nullValue:
		return 0;
	case booleanValue:
		return value_.bool_ ? 1 : 0;
	default:
		break;
	}
	JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
	return false;
}

Value::UInt64 Value::asUInt64() const {
	switch (type_) {
	case intValue:
		JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range")
		;
		return UInt64(value_.int_);
	case uintValue:
		return UInt64(value_.uint_);
	case realValue:
		JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
				"double out of UInt64 range")
		;
		return UInt64(value_.real_);
	case nullValue:
		return 0;
	case booleanValue:
		return value_.bool_ ? 1 : 0;
	default:
		break;
	}
	JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
	return false;
}
#endif // if defined(JSON_HAS_INT64)

LargestInt Value::asLargestInt() const {
#if defined(JSON_NO_INT64)
	return asInt();
#else
	return asInt64();
#endif
}

LargestUInt Value::asLargestUInt() const {
#if defined(JSON_NO_INT64)
	return asUInt();
#else
	return asUInt64();
#endif
}

double Value::asDouble() const {
	switch (type_) {
	case intValue:
		return static_cast<double>(value_.int_);
	case uintValue:
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
		return static_cast<double>(value_.uint_);
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
		return integerToDouble(value_.uint_);
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
	case realValue:
		return value_.real_;
	case nullValue:
		return 0.0;
	case booleanValue:
		return value_.bool_ ? 1.0 : 0.0;
	default:
		break;
	}
	JSON_FAIL_MESSAGE("Value is not convertible to double.");
	return false;
}

float Value::asFloat() const {
	switch (type_) {
	case intValue:
		return static_cast<float>(value_.int_);
	case uintValue:
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
		return static_cast<float>(value_.uint_);
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
		return integerToDouble(value_.uint_);
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
	case realValue:
		return static_cast<float>(value_.real_);
	case nullValue:
		return 0.0;
	case booleanValue:
		return value_.bool_ ? 1.0f : 0.0f;
	default:
		break;
	}
	JSON_FAIL_MESSAGE("Value is not convertible to float.");
	return false;
}

bool Value::asBool() const {
	switch (type_) {
	case booleanValue:
		return value_.bool_;
	case nullValue:
		return false;
	case intValue:
		return value_.int_ ? true : false;
	case uintValue:
		return value_.uint_ ? true : false;
	case realValue:
		// This is kind of strange. Not recommended.
		return (value_.real_ != 0.0) ? true : false;
	default:
		break;
	}
	JSON_FAIL_MESSAGE("Value is not convertible to bool.");
	return false;
}

bool Value::isConvertibleTo(ValueType other) const {
	switch (other) {
	case nullValue:
		return (isNumeric() && asDouble() == 0.0)
				|| (type_ == booleanValue && value_.bool_ == false)
				|| (type_ == stringValue && asString() == "")
				|| (type_ == arrayValue && value_.map_->size() == 0)
				|| (type_ == objectValue && value_.map_->size() == 0)
				|| type_ == nullValue;
	case intValue:
		return isInt()
				|| (type_ == realValue && InRange(value_.real_, minInt, maxInt))
				|| type_ == booleanValue || type_ == nullValue;
	case uintValue:
		return isUInt()
				|| (type_ == realValue && InRange(value_.real_, 0, maxUInt))
				|| type_ == booleanValue || type_ == nullValue;
	case realValue:
		return isNumeric() || type_ == booleanValue || type_ == nullValue;
	case booleanValue:
		return isNumeric() || type_ == booleanValue || type_ == nullValue;
	case stringValue:
		return isNumeric() || type_ == booleanValue || type_ == stringValue
				|| type_ == nullValue;
	case arrayValue:
		return type_ == arrayValue || type_ == nullValue;
	case objectValue:
		return type_ == objectValue || type_ == nullValue;
	}
	JSON_ASSERT_UNREACHABLE;
	return false;
}

/// Number of values in array or object
ArrayIndex Value::size() const {
	switch (type_) {
	case nullValue:
	case intValue:
	case uintValue:
	case realValue:
	case booleanValue:
	case stringValue:
		return 0;
	case arrayValue: // size of the array is highest index + 1
		if (!value_.map_->empty()) {
			ObjectValues::const_iterator itLast = value_.map_->end();
			--itLast;
			return (*itLast).first.index() + 1;
		}
		return 0;
	case objectValue:
		return ArrayIndex(value_.map_->size());
	}
	JSON_ASSERT_UNREACHABLE;
	return 0; // unreachable;
}

bool Value::empty() const {
	if (isNull() || isArray() || isObject())
		return size() == 0u;
	else
		return false;
}

bool Value::operator!() const {
	return isNull();
}

void Value::clear() {
	JSON_ASSERT_MESSAGE(
			type_ == nullValue || type_ == arrayValue || type_ == objectValue,
			"in Json::Value::clear(): requires complex value");
	start_ = 0;
	limit_ = 0;
	switch (type_) {
	case arrayValue:
	case objectValue:
		value_.map_->clear();
		break;
	default:
		break;
	}
}

void Value::resize(ArrayIndex newSize) {
	JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
			"in Json::Value::resize(): requires arrayValue");
	if (type_ == nullValue)
		*this = Value(arrayValue);
	ArrayIndex oldSize = size();
	if (newSize == 0)
		clear();
	else if (newSize > oldSize)
		(*this)[newSize - 1];
	else {
		for (ArrayIndex index = newSize; index < oldSize; ++index) {
			value_.map_->erase(index);
		}
		assert(size() == newSize);
	}
}

Value& Value::operator[](ArrayIndex index) {
	JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
			"in Json::Value::operator[](ArrayIndex): requires arrayValue");
	if (type_ == nullValue)
		*this = Value(arrayValue);
	CZString key(index);
	ObjectValues::iterator it = value_.map_->lower_bound(key);
	if (it != value_.map_->end() && (*it).first == key)
		return (*it).second;

	ObjectValues::value_type defaultValue(key, nullRef);
	it = value_.map_->insert(it, defaultValue);
	return (*it).second;
}

Value& Value::operator[](int index) {
	JSON_ASSERT_MESSAGE(index >= 0,
			"in Json::Value::operator[](int index): index cannot be negative");
	return (*this)[ArrayIndex(index)];
}

const Value& Value::operator[](ArrayIndex index) const {
	JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
			"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
	if (type_ == nullValue)
		return nullRef;
	CZString key(index);
	ObjectValues::const_iterator it = value_.map_->find(key);
	if (it == value_.map_->end())
		return nullRef;
	return (*it).second;
}

const Value& Value::operator[](int index) const {
	JSON_ASSERT_MESSAGE(index >= 0,
			"in Json::Value::operator[](int index) const: index cannot be negative");
	return (*this)[ArrayIndex(index)];
}

void Value::initBasic(ValueType vtype, bool allocated) {
	type_ = vtype;
	allocated_ = allocated;
	comments_ = 0;
	start_ = 0;
	limit_ = 0;
}

// Access an object value by name, create a null member if it does not exist.
// @pre Type of '*this' is object or null.
// @param key is null-terminated.
Value& Value::resolveReference(const char* key) {
	JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
			"in Json::Value::resolveReference(): requires objectValue");
	if (type_ == nullValue)
		*this = Value(objectValue);
	CZString actualKey(key, static_cast<unsigned>(strlen(key)),
			CZString::noDuplication); // NOTE!
	ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
	if (it != value_.map_->end() && (*it).first == actualKey)
		return (*it).second;

	ObjectValues::value_type defaultValue(actualKey, nullRef);
	it = value_.map_->insert(it, defaultValue);
	Value& value = (*it).second;
	return value;
}

// @param key is not null-terminated.
Value& Value::resolveReference(char const* key, char const* cend) {
	JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
			"in Json::Value::resolveReference(key, end): requires objectValue");
	if (type_ == nullValue)
		*this = Value(objectValue);
	CZString actualKey(key, static_cast<unsigned>(cend - key),
			CZString::duplicateOnCopy);
	ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
	if (it != value_.map_->end() && (*it).first == actualKey)
		return (*it).second;

	ObjectValues::value_type defaultValue(actualKey, nullRef);
	it = value_.map_->insert(it, defaultValue);
	Value& value = (*it).second;
	return value;
}

Value Value::get(ArrayIndex index, const Value& defaultValue) const {
	const Value* value = &((*this)[index]);
	return value == &nullRef ? defaultValue : *value;
}

bool Value::isValidIndex(ArrayIndex index) const {
	return index < size();
}

Value const* Value::find(char const* key, char const* cend) const {
	JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
			"in Json::Value::find(key, end, found): requires objectValue or nullValue");
	if (type_ == nullValue)
		return NULL;
	CZString actualKey(key, static_cast<unsigned>(cend - key),
			CZString::noDuplication);
	ObjectValues::const_iterator it = value_.map_->find(actualKey);
	if (it == value_.map_->end())
		return NULL;
	return &(*it).second;
}
const Value& Value::operator[](const char* key) const {
	Value const* found = find(key, key + strlen(key));
	if (!found)
		return nullRef;
	return *found;
}
Value const& Value::operator[](std::string const& key) const {
	Value const* found = find(key.data(), key.data() + key.length());
	if (!found)
		return nullRef;
	return *found;
}

Value& Value::operator[](const char* key) {
	return resolveReference(key, key + strlen(key));
}

Value& Value::operator[](const std::string& key) {
	return resolveReference(key.data(), key.data() + key.length());
}

Value& Value::operator[](const StaticString& key) {
	return resolveReference(key.c_str());
}

#ifdef JSON_USE_CPPTL
Value& Value::operator[](const CppTL::ConstString& key) {
	return resolveReference(key.c_str(), key.end_c_str());
}
Value const& Value::operator[](CppTL::ConstString const& key) const
{
	Value const* found = find(key.c_str(), key.end_c_str());
	if (!found) return nullRef;
	return *found;
}
#endif

Value& Value::append(const Value& value) {
	return (*this)[size()] = value;
}

Value Value::get(char const* key, char const* cend,
		Value const& defaultValue) const {
	Value const* found = find(key, cend);
	return !found ? defaultValue : *found;
}
Value Value::get(char const* key, Value const& defaultValue) const {
	return get(key, key + strlen(key), defaultValue);
}
Value Value::get(std::string const& key, Value const& defaultValue) const {
	return get(key.data(), key.data() + key.length(), defaultValue);
}

bool Value::removeMember(const char* key, const char* cend, Value* removed) {
	if (type_ != objectValue) {
		return false;
	}
	CZString actualKey(key, static_cast<unsigned>(cend - key),
			CZString::noDuplication);
	ObjectValues::iterator it = value_.map_->find(actualKey);
	if (it == value_.map_->end())
		return false;
	*removed = it->second;
	value_.map_->erase(it);
	return true;
}
bool Value::removeMember(const char* key, Value* removed) {
	return removeMember(key, key + strlen(key), removed);
}
bool Value::removeMember(std::string const& key, Value* removed) {
	return removeMember(key.data(), key.data() + key.length(), removed);
}
Value Value::removeMember(const char* key) {
	JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
			"in Json::Value::removeMember(): requires objectValue");
	if (type_ == nullValue)
		return nullRef;

	Value removed;  // null
	removeMember(key, key + strlen(key), &removed);
	return removed; // still null if removeMember() did nothing
}
Value Value::removeMember(const std::string& key) {
	return removeMember(key.c_str());
}

bool Value::removeIndex(ArrayIndex index, Value* removed) {
	if (type_ != arrayValue) {
		return false;
	}
	CZString key(index);
	ObjectValues::iterator it = value_.map_->find(key);
	if (it == value_.map_->end()) {
		return false;
	}
	*removed = it->second;
	ArrayIndex oldSize = size();
	// shift left all items left, into the place of the "removed"
	for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
		CZString keey(i);
		(*value_.map_)[keey] = (*this)[i + 1];
	}
	// erase the last one ("leftover")
	CZString keyLast(oldSize - 1);
	ObjectValues::iterator itLast = value_.map_->find(keyLast);
	value_.map_->erase(itLast);
	return true;
}

#ifdef JSON_USE_CPPTL
Value Value::get(const CppTL::ConstString& key,
		const Value& defaultValue) const {
	return get(key.c_str(), key.end_c_str(), defaultValue);
}
#endif

bool Value::isMember(char const* key, char const* cend) const {
	Value const* value = find(key, cend);
	return NULL != value;
}
bool Value::isMember(char const* key) const {
	return isMember(key, key + strlen(key));
}
bool Value::isMember(std::string const& key) const {
	return isMember(key.data(), key.data() + key.length());
}

#ifdef JSON_USE_CPPTL
bool Value::isMember(const CppTL::ConstString& key) const {
	return isMember(key.c_str(), key.end_c_str());
}
#endif

Value::Members Value::getMemberNames() const {
	JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
			"in Json::Value::getMemberNames(), value must be objectValue");
	if (type_ == nullValue)
		return Value::Members();
	Members members;
	members.reserve(value_.map_->size());
	ObjectValues::const_iterator it = value_.map_->begin();
	ObjectValues::const_iterator itEnd = value_.map_->end();
	for (; it != itEnd; ++it) {
		members.push_back(
				std::string((*it).first.data(), (*it).first.length()));
	}
	return members;
}
//
//# ifdef JSON_USE_CPPTL
// EnumMemberNames
// Value::enumMemberNames() const
//{
//   if ( type_ == objectValue )
//   {
//      return CppTL::Enum::any(  CppTL::Enum::transform(
//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
//         MemberNamesTransform() ) );
//   }
//   return EnumMemberNames();
//}
//
//
// EnumValues
// Value::enumValues() const
//{
//   if ( type_ == objectValue  ||  type_ == arrayValue )
//      return CppTL::Enum::anyValues( *(value_.map_),
//                                     CppTL::Type<const Value &>() );
//   return EnumValues();
//}
//
//# endif

static bool IsIntegral(double d) {
	double integral_part;
	return modf(d, &integral_part) == 0.0;
}

bool Value::isNull() const {
	return type_ == nullValue;
}

bool Value::isBool() const {
	return type_ == booleanValue;
}

bool Value::isInt() const {
	switch (type_) {
	case intValue:
		return value_.int_ >= minInt && value_.int_ <= maxInt;
	case uintValue:
		return value_.uint_ <= UInt(maxInt);
	case realValue:
		return value_.real_ >= minInt && value_.real_ <= maxInt
				&& IsIntegral(value_.real_);
	default:
		break;
	}
	return false;
}

bool Value::isUInt() const {
	switch (type_) {
	case intValue:
		return value_.int_ >= 0
				&& LargestUInt(value_.int_) <= LargestUInt(maxUInt);
	case uintValue:
		return value_.uint_ <= maxUInt;
	case realValue:
		return value_.real_ >= 0 && value_.real_ <= maxUInt
				&& IsIntegral(value_.real_);
	default:
		break;
	}
	return false;
}

bool Value::isInt64() const {
#if defined(JSON_HAS_INT64)
	switch (type_) {
	case intValue:
		return true;
	case uintValue:
		return value_.uint_ <= UInt64(maxInt64);
	case realValue:
		// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
		// double, so double(maxInt64) will be rounded up to 2^63. Therefore we
		// require the value to be strictly less than the limit.
		return value_.real_ >= double(minInt64)
				&& value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
	default:
		break;
	}
#endif // JSON_HAS_INT64
	return false;
}

bool Value::isUInt64() const {
#if defined(JSON_HAS_INT64)
	switch (type_) {
	case intValue:
		return value_.int_ >= 0;
	case uintValue:
		return true;
	case realValue:
		// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
		// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
		// require the value to be strictly less than the limit.
		return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble
				&& IsIntegral(value_.real_);
	default:
		break;
	}
#endif // JSON_HAS_INT64
	return false;
}

bool Value::isIntegral() const {
#if defined(JSON_HAS_INT64)
	return isInt64() || isUInt64();
#else
	return isInt() || isUInt();
#endif
}

bool Value::isDouble() const {
	return type_ == realValue || isIntegral();
}

bool Value::isNumeric() const {
	return isIntegral() || isDouble();
}

bool Value::isString() const {
	return type_ == stringValue;
}

bool Value::isArray() const {
	return type_ == arrayValue;
}

bool Value::isObject() const {
	return type_ == objectValue;
}

void Value::setComment(const char* comment, size_t len,
		CommentPlacement placement) {
	if (!comments_)
		comments_ = new CommentInfo[numberOfCommentPlacement];
	if ((len > 0) && (comment[len - 1] == '\n')) {
		// Always discard trailing newline, to aid indentation.
		len -= 1;
	}
	comments_[placement].setComment(comment, len);
}

void Value::setComment(const char* comment, CommentPlacement placement) {
	setComment(comment, strlen(comment), placement);
}

void Value::setComment(const std::string& comment, CommentPlacement placement) {
	setComment(comment.c_str(), comment.length(), placement);
}

bool Value::hasComment(CommentPlacement placement) const {
	return comments_ != 0 && comments_[placement].comment_ != 0;
}

std::string Value::getComment(CommentPlacement placement) const {
	if (hasComment(placement))
		return comments_[placement].comment_;
	return "";
}

void Value::setOffsetStart(size_t start) {
	start_ = start;
}

void Value::setOffsetLimit(size_t limit) {
	limit_ = limit;
}

size_t Value::getOffsetStart() const {
	return start_;
}

size_t Value::getOffsetLimit() const {
	return limit_;
}

std::string Value::toStyledString() const {
	StyledWriter writer;
	return writer.write(*this);
}

Value::const_iterator Value::begin() const {
	switch (type_) {
	case arrayValue:
	case objectValue:
		if (value_.map_)
			return const_iterator(value_.map_->begin());
		break;
	default:
		break;
	}
	return const_iterator();
}

Value::const_iterator Value::end() const {
	switch (type_) {
	case arrayValue:
	case objectValue:
		if (value_.map_)
			return const_iterator(value_.map_->end());
		break;
	default:
		break;
	}
	return const_iterator();
}

Value::iterator Value::begin() {
	switch (type_) {
	case arrayValue:
	case objectValue:
		if (value_.map_)
			return iterator(value_.map_->begin());
		break;
	default:
		break;
	}
	return iterator();
}

Value::iterator Value::end() {
	switch (type_) {
	case arrayValue:
	case objectValue:
		if (value_.map_)
			return iterator(value_.map_->end());
		break;
	default:
		break;
	}
	return iterator();
}

// class PathArgument
// //////////////////////////////////////////////////////////////////

PathArgument::PathArgument() :
		key_(), index_(), kind_(kindNone) {
}

PathArgument::PathArgument(ArrayIndex index) :
		key_(), index_(index), kind_(kindIndex) {
}

PathArgument::PathArgument(const char* key) :
		key_(key), index_(), kind_(kindKey) {
}

PathArgument::PathArgument(const std::string& key) :
		key_(key.c_str()), index_(), kind_(kindKey) {
}

// class Path
// //////////////////////////////////////////////////////////////////

Path::Path(const std::string& path, const PathArgument& a1,
		const PathArgument& a2, const PathArgument& a3, const PathArgument& a4,
		const PathArgument& a5) {
	InArgs in;
	in.push_back(&a1);
	in.push_back(&a2);
	in.push_back(&a3);
	in.push_back(&a4);
	in.push_back(&a5);
	makePath(path, in);
}

void Path::makePath(const std::string& path, const InArgs& in) {
	const char* current = path.c_str();
	const char* end = current + path.length();
	InArgs::const_iterator itInArg = in.begin();
	while (current != end) {
		if (*current == '[') {
			++current;
			if (*current == '%')
				addPathInArg(path, in, itInArg, PathArgument::kindIndex);
			else {
				ArrayIndex index = 0;
				for (; current != end && *current >= '0' && *current <= '9';
						++current)
					index = index * 10 + ArrayIndex(*current - '0');
				args_.push_back(index);
			}
			if (current == end || *current++ != ']')
				invalidPath(path, int(current - path.c_str()));
		} else if (*current == '%') {
			addPathInArg(path, in, itInArg, PathArgument::kindKey);
			++current;
		} else if (*current == '.') {
			++current;
		} else {
			const char* beginName = current;
			while (current != end && !strchr("[.", *current))
				++current;
			args_.push_back(std::string(beginName, current));
		}
	}
}

void Path::addPathInArg(const std::string& /*path*/, const InArgs& in,
		InArgs::const_iterator& itInArg, PathArgument::Kind kind) {
	if (itInArg == in.end()) {
		// Error: missing argument %d
	} else if ((*itInArg)->kind_ != kind) {
		// Error: bad argument type
	} else {
		args_.push_back(**itInArg);
	}
}

void Path::invalidPath(const std::string& /*path*/, int /*location*/) {
	// Error: invalid path.
}

const Value& Path::resolve(const Value& root) const {
	const Value* node = &root;
	for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
		const PathArgument& arg = *it;
		if (arg.kind_ == PathArgument::kindIndex) {
			if (!node->isArray() || !node->isValidIndex(arg.index_)) {
				// Error: unable to resolve path (array value expected at position...
			}
			node = &((*node)[arg.index_]);
		} else if (arg.kind_ == PathArgument::kindKey) {
			if (!node->isObject()) {
				// Error: unable to resolve path (object value expected at position...)
			}
			node = &((*node)[arg.key_]);
			if (node == &Value::nullRef) {
				// Error: unable to resolve path (object has no member named '' at
				// position...)
			}
		}
	}
	return *node;
}

Value Path::resolve(const Value& root, const Value& defaultValue) const {
	const Value* node = &root;
	for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
		const PathArgument& arg = *it;
		if (arg.kind_ == PathArgument::kindIndex) {
			if (!node->isArray() || !node->isValidIndex(arg.index_))
				return defaultValue;
			node = &((*node)[arg.index_]);
		} else if (arg.kind_ == PathArgument::kindKey) {
			if (!node->isObject())
				return defaultValue;
			node = &((*node)[arg.key_]);
			if (node == &Value::nullRef)
				return defaultValue;
		}
	}
	return *node;
}

Value& Path::make(Value& root) const {
	Value* node = &root;
	for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
		const PathArgument& arg = *it;
		if (arg.kind_ == PathArgument::kindIndex) {
			if (!node->isArray()) {
				// Error: node is not an array at position ...
			}
			node = &((*node)[arg.index_]);
		} else if (arg.kind_ == PathArgument::kindKey) {
			if (!node->isObject()) {
				// Error: node is not an object at position...
			}
			node = &((*node)[arg.key_]);
		}
	}
	return *node;
}

} // namespace Json
