/// \file json.cpp Holds all JSON-related code.

#include "json.h"
#include "defines.h"
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include <stdint.h> //for uint64_t
#include <string.h> //for memcpy
#include <arpa/inet.h> //for htonl

/// Construct from a root Value to iterate over.
JSON::Iter::Iter(Value & root){
  myType = root.myType;
  i = 0;
  r = &root;
  if (!root.size()){myType = JSON::EMPTY;}
  if (myType == JSON::ARRAY){
    aIt = root.arrVal.begin();
  }
  if (myType == JSON::OBJECT){
    oIt = root.objVal.begin();
  }
}

/// Dereferences into a Value reference.
/// If invalid iterator, returns an empty reference and prints a warning message.
JSON::Value & JSON::Iter::operator*() const{
  if (myType == JSON::ARRAY && aIt != r->arrVal.end()){
    return **aIt;
  }
  if (myType == JSON::OBJECT && oIt != r->objVal.end()){
    return *(oIt->second);
  }
  static JSON::Value error;
  WARN_MSG("Dereferenced invalid JSON iterator");
  return error;
}

/// Dereferences into a Value reference.
/// If invalid iterator, returns an empty reference and prints a warning message.
JSON::Value * JSON::Iter::operator->() const{
  return &(operator*());
}

/// True if not done iterating.
JSON::Iter::operator bool() const{
  return ((myType == JSON::ARRAY && aIt != r->arrVal.end()) || (myType == JSON::OBJECT && oIt != r->objVal.end()));
}

/// Go to next iteration.
JSON::Iter & JSON::Iter::operator++(){
  if (*this){
    ++i;
    if (myType == JSON::ARRAY){
      ++aIt;
    }
    if (myType == JSON::OBJECT){
      ++oIt;
    }
  }
  return *this;
}

/// Return the name of the current indice.
const std::string & JSON::Iter::key() const{
  if (myType == JSON::OBJECT && *this){
    return oIt->first;
  }
  static const std::string empty;
  WARN_MSG("Got key from invalid JSON iterator");
  return empty;
}

/// Return the number of the current indice.
unsigned int JSON::Iter::num() const{
  return i;
}

/// Delete the current indice from the parent JSON::Value.
void JSON::Iter::remove(){
  if (*this){
    if (myType == JSON::ARRAY){
      r->removeMember(aIt);
      return;
    }
    if (myType == JSON::OBJECT){
      r->removeMember(oIt);
      return;
    }
  }
}

/// Construct from a root Value to iterate over.
JSON::ConstIter::ConstIter(const Value & root){
  myType = root.myType;
  i = 0;
  r = &root;
  if (!root.size()){myType = JSON::EMPTY;}
  if (myType == JSON::ARRAY){
    aIt = root.arrVal.begin();
  }
  if (myType == JSON::OBJECT){
    oIt = root.objVal.begin();
  }
}

/// Dereferences into a Value reference.
/// If invalid iterator, returns an empty reference and prints a warning message.
const JSON::Value & JSON::ConstIter::operator*() const{
  if (myType == JSON::ARRAY && aIt != r->arrVal.end()){
    return **aIt;
  }
  if (myType == JSON::OBJECT && oIt != r->objVal.end()){
    return *(oIt->second);
  }
  static JSON::Value error;
  WARN_MSG("Dereferenced invalid JSON iterator");
  return error;
}

/// Dereferences into a Value reference.
/// If invalid iterator, returns an empty reference and prints a warning message.
const JSON::Value * JSON::ConstIter::operator->() const{
  return &(operator*());
}

/// True if not done iterating.
JSON::ConstIter::operator bool() const{
  return ((myType == JSON::ARRAY && aIt != r->arrVal.end()) || (myType == JSON::OBJECT && oIt != r->objVal.end()));
}

/// Go to next iteration.
JSON::ConstIter & JSON::ConstIter::operator++(){
  if (*this){
    ++i;
    if (myType == JSON::ARRAY){
      ++aIt;
    }
    if (myType == JSON::OBJECT){
      ++oIt;
    }
  }
  return *this;
}

/// Return the name of the current indice.
const std::string & JSON::ConstIter::key() const{
  if (myType == JSON::OBJECT && *this){
    return oIt->first;
  }
  static const std::string empty;
  WARN_MSG("Got key from invalid JSON iterator");
  return empty;
}

/// Return the number of the current indice.
unsigned int JSON::ConstIter::num() const{
  return i;
}

static inline char c2hex(char c) {
  if (c >= '0' && c <= '9') return c - '0';
  if (c >= 'a' && c <= 'f') return c - 'a' + 10;
  if (c >= 'A' && c <= 'F') return c - 'A' + 10;
  return 0;
}

static inline char hex2c(char c) {
  if (c < 10) {
    return '0' + c;
  }
  if (c < 16) {
    return 'A' + (c - 10);
  }
  return '0';
}

static std::string UTF8(uint32_t c){
  std::string r;
  if (c <= 0x7F){
    r.append(1, c);
    return r;
  }
  if (c <= 0x7FF){
    r.append(1, 0xC0 | (c >> 6));
    r.append(1, 0x80 | (c & 0x3F));
    return r;
  }
  if (c <= 0x7FF){
    r.append(1, 0xC0 | (c >> 12));
    r.append(1, 0x80 | ((c >> 6) & 0x3F));
    r.append(1, 0x80 | (c & 0x3F));
    return r;
  }
  r.append(1, 0xC0 | (c >> 18));
  r.append(1, 0x80 | ((c >> 12) & 0x3F));
  r.append(1, 0x80 | ((c >> 6) & 0x3F));
  r.append(1, 0x80 | (c & 0x3F));
  return r;
}

static std::string read_string(int separator, std::istream & fromstream) {
  std::string out;
  bool escaped = false;
  uint32_t fullChar = 0;
  while (fromstream.good()) {
    char c;
    fromstream.get(c);
    if (c == '\\') {
      escaped = true;
      continue;
    }
    if (escaped) {
      if (fullChar && c != 'u'){
        out += UTF8(fullChar >> 16);
        fullChar = 0;
      }
      switch (c) {
        case 'b':
          out += '\b';
          break;
        case 'f':
          out += '\f';
          break;
        case 'n':
          out += '\n';
          break;
        case 'r':
          out += '\r';
          break;
        case 't':
          out += '\t';
          break;
        case 'x':
            char d1, d2;
            fromstream.get(d1);
            fromstream.get(d2);
            out.append(1, (c2hex(d2) + (c2hex(d1) << 4)));
          break;
        case 'u': {
            char d1, d2, d3, d4;
            fromstream.get(d1);
            fromstream.get(d2);
            fromstream.get(d3);
            fromstream.get(d4);
            uint32_t tmpChar = (c2hex(d4) + (c2hex(d3) << 4) + (c2hex(d2) << 8) + (c2hex(d1) << 16));
            if (fullChar && (tmpChar < 0xDC00 || tmpChar > 0xDFFF)){
              //not a low surrogate - handle high surrogate separately!
              out += UTF8(fullChar >> 16);
              fullChar = 0;
            }
            fullChar |= tmpChar;
            if (fullChar >= 0xD800 && fullChar <= 0xDBFF){
              //possibly high surrogate! Read next characters before handling...
              fullChar <<= 16;//save as high surrogate
            }else{
              out += UTF8(fullChar);
              fullChar = 0;
            }
            break;
          }
        default:
          out.append(1, c);
          break;
      }
      escaped = false;
    } else {
      if (fullChar){
        out += UTF8(fullChar >> 16);
        fullChar = 0;
      }
      if (c == separator) {
        return out;
      } else {
        out.append(1, c);
      }
    }
  }
  if (fullChar){
    out += UTF8(fullChar >> 16);
    fullChar = 0;
  }
  return out;
}

static std::string UTF16(uint32_t c){
  if (c > 0xFFFF){
    c -= 0x010000;
    return UTF16(0xD800 + ((c >> 10) & 0x3FF)) + UTF16(0xDC00 + (c & 0x3FF));
  }else{
    std::string ret = "\\u";
    ret += hex2c((c >> 12) & 0xf);
    ret += hex2c((c >> 8) & 0xf);
    ret += hex2c((c >> 4) & 0xf);
    ret += hex2c(c & 0xf);
    return ret;
  }
}

std::string JSON::string_escape(const std::string & val) {
  std::string out = "\"";
  for (unsigned int i = 0; i < val.size(); ++i) {
    const char & c = val.data()[i];
    switch (c) {
      case '"':
        out += "\\\"";
        break;
      case '\\':
        out += "\\\\";
        break;
      case '\n':
        out += "\\n";
        break;
      case '\b':
        out += "\\b";
        break;
      case '\f':
        out += "\\f";
        break;
      case '\r':
        out += "\\r";
        break;
      case '\t':
        out += "\\t";
        break;
      default:
        if (c < 32 || c > 126) {
          //we assume our data is UTF-8 encoded internally.
          //JavaScript expects UTF-16, so if we recognize a valid UTF-8 sequence, we turn it into UTF-16 for JavaScript.
          //Anything else is escaped as a single character UTF-16 escape.
          if ((c & 0xC0) == 0xC0){
            //possible UTF-8 sequence
            //check for 2-byte sequence
            if (((c & 0xE0) == 0XC0) && (i+1 < val.size()) && ((val.data()[i+1] & 0xC0) == 0x80)){
              //valid 2-byte sequence
              out += UTF16(((c & 0x1F) << 6) | (val.data()[i+1] & 0x3F));
              i += 1;
              break;
            }
            //check for 3-byte sequence
            if (((c & 0xF0) == 0XE0) && (i+2 < val.size()) && ((val.data()[i+1] & 0xC0) == 0x80) && ((val.data()[i+2] & 0xC0) == 0x80)){
              //valid 3-byte sequence
              out += UTF16(((c & 0x1F) << 12) | ((val.data()[i+1] & 0x3F) << 6) | (val.data()[i+2] & 0x3F));
              i += 2;
              break;
            }
            //check for 4-byte sequence
            if (((c & 0xF8) == 0XF0) && (i+3 < val.size()) && ((val.data()[i+1] & 0xC0) == 0x80) && ((val.data()[i+2] & 0xC0) == 0x80) && ((val.data()[i+3] & 0xC0) == 0x80)){
              //valid 4-byte sequence
              out += UTF16(((c & 0x1F) << 18) | ((val.data()[i+1] & 0x3F) << 12) | ((val.data()[i+2] & 0x3F) << 6) | (val.data()[i+3] & 0x3F));
              i += 3;
              break;
            }
          }
          //Anything else, we encode as a single UTF-16 character.
          out += "\\u00";
          out += hex2c((val.data()[i] >> 4) & 0xf);
          out += hex2c(val.data()[i] & 0xf);
        } else {
          out += val.data()[i];
        }
        break;
    }
  }
  out += "\"";
  return out;
}

/// Skips an std::istream forward until any of the following characters is seen: ,]}
static void skipToEnd(std::istream & fromstream) {
  while (fromstream.good()) {
    char peek = fromstream.peek();
    if (peek == ',') {
      return;
    }
    if (peek == ']') {
      return;
    }
    if (peek == '}') {
      return;
    }
    peek = fromstream.get();
  }
}

/// Sets this JSON::Value to null;
JSON::Value::Value() {
  null();
}

/// Sets this JSON::Value to null
JSON::Value::~Value() {
  null();
}

JSON::Value::Value(const Value & rhs) {
  null();
  *this = rhs;
}

/// Sets this JSON::Value to read from this position in the std::istream
JSON::Value::Value(std::istream & fromstream) {
  null();
  bool reading_object = false;
  bool reading_array = false;
  bool negative = false;
  bool stop = false;
  while (!stop && fromstream.good()) {
    int c = fromstream.peek();
    switch (c) {
      case '{':
        reading_object = true;
        c = fromstream.get();
        myType = OBJECT;
        break;
      case '[': {
          reading_array = true;
          c = fromstream.get();
          myType = ARRAY;
          Value tmp = JSON::Value(fromstream);
          if (tmp.myType != EMPTY) {
            append(tmp);
          }
          break;
        }
      case '\'':
      case '"':
        c = fromstream.get();
        if (!reading_object) {
          myType = STRING;
          strVal = read_string(c, fromstream);
          stop = true;
        } else {
          std::string tmpstr = read_string(c, fromstream);
          (*this)[tmpstr] = JSON::Value(fromstream);
        }
        break;
      case '-':
        c = fromstream.get();
        negative = true;
        break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        c = fromstream.get();
        if (myType != INTEGER && myType != DOUBLE){
          myType = INTEGER;
        }
        if (myType == INTEGER){
          intVal *= 10;
          intVal += c - '0';
        }else{
          dblDivider *= 10;
          dblVal += ((double)((c - '0')) / dblDivider);
        }
        break;
      case '.':
        c = fromstream.get();
        myType = DOUBLE;
        if (negative){
          dblVal = -intVal;
          dblDivider = -1;
        }else{
          dblVal = intVal;
          dblDivider = 1;
        }
        break;
      case ',':
        if (!reading_object && !reading_array) {
          stop = true;
          break;
        }
        c = fromstream.get();
        if (reading_array) {
          append(JSON::Value(fromstream));
        }
        break;
      case '}':
        if (reading_object) {
          c = fromstream.get();
        }
        stop = true;
        break;
      case ']':
        if (reading_array) {
          c = fromstream.get();
        }
        stop = true;
        break;
      case 't':
      case 'T':
        skipToEnd(fromstream);
        myType = BOOL;
        intVal = 1;
        stop = true;
        break;
      case 'f':
      case 'F':
        skipToEnd(fromstream);
        myType = BOOL;
        intVal = 0;
        stop = true;
        break;
      case 'n':
      case 'N':
        skipToEnd(fromstream);
        myType = EMPTY;
        stop = true;
        break;
      default:
        c = fromstream.get(); //ignore this character
        continue;
        break;
    }
  }
  if (negative) {
    intVal *= -1;
  }
}

/// Sets this JSON::Value to the given string.
JSON::Value::Value(const std::string & val) {
  myType = STRING;
  strVal = val;
  intVal = 0;
}

/// Sets this JSON::Value to the given string.
JSON::Value::Value(const char * val) {
  myType = STRING;
  strVal = val;
  intVal = 0;
}

/// Sets this JSON::Value to the given integer.
JSON::Value::Value(long long int val) {
  myType = INTEGER;
  intVal = val;
}

/// Sets this JSON::Value to the given double.
JSON::Value::Value(double val) {
  myType = DOUBLE;
  dblVal = val;
}

/// Sets this JSON::Value to the given integer.
JSON::Value::Value(bool val) {
  myType = BOOL;
  if (val){
    intVal = 1;
  }else{
    intVal = 0;
  }
}

/// Compares a JSON::Value to another for equality.
bool JSON::Value::operator==(const JSON::Value & rhs) const {
  if (myType != rhs.myType){
    return false;
  }
  if (myType == INTEGER || myType == BOOL) {
    return intVal == rhs.intVal;
  }
  if (myType == DOUBLE) {
    return dblVal == rhs.dblVal;
  }
  if (myType == STRING) {
    return strVal == rhs.strVal;
  }
  if (myType == EMPTY) {
    return true;
  }
  if (size() != rhs.size()){
    return false;
  }
  if (myType == OBJECT) {
    jsonForEachConst(*this, it){
      if (!rhs.isMember(it.key()) || *it != rhs[it.key()]) {
        return false;
      }
    }
    return true;
  }
  if (myType == ARRAY) {
    jsonForEachConst(*this, it){
      if (*it != rhs[it.num()]) {
        return false;
      }
    }
    return true;
  }
  return true;
}

/// Compares a JSON::Value to another for equality.
bool JSON::Value::operator!=(const JSON::Value & rhs) const {
  return !((*this) == rhs);
}

bool JSON::Value::compareExcept(const Value & rhs, const std::set<std::string> & skip) const {
  if (myType != OBJECT) {
    return ((*this) == rhs);
  }
  jsonForEachConst(*this, it){
    if (skip.count(it.key())){continue;}
    if (!rhs.isMember(it.key()) || !(*it).compareExcept(rhs[it.key()], skip)) {
      return false;
    }
  }
  jsonForEachConst(rhs, it){
    if (skip.count(it.key())){continue;}
    if (!(*this).isMember(it.key())){return false;}
  }
  return true;
}

bool JSON::Value::compareOnly(const Value & rhs, const std::set<std::string> & check) const {
  if (myType != OBJECT) {
    return ((*this) == rhs);
  }
  jsonForEachConst(*this, it){
    if (!check.count(it.key())){continue;}
    if (!rhs.isMember(it.key()) || !(*it).compareOnly(rhs[it.key()], check)) {
      return false;
    }
  }
  jsonForEachConst(rhs, it){
    if (!check.count(it.key())){continue;}
    if (!(*this).isMember(it.key())){return false;}
  }
  return true;
}

/// Completely clears the contents of this value,
/// changing its type to NULL in the process.
void JSON::Value::null() {
  shrink(0);
  strVal.clear();
  intVal = 0;
  dblVal = 0;
  dblDivider = 1;
  myType = EMPTY;
}

/// Assigns this JSON::Value to the given JSON::Value, skipping given member recursively.
JSON::Value & JSON::Value::assignFrom(const Value & rhs, const std::set<std::string> & skip){
  null();
  myType = rhs.myType;
  if (myType == STRING){
    strVal = rhs.strVal;
  }
  if (myType == BOOL || myType == INTEGER){
    intVal = rhs.intVal;
  }
  if (myType == DOUBLE){
    dblVal = rhs.dblVal;
  }
  if (myType == OBJECT){
    jsonForEachConst(rhs, i){
      if (!skip.count(i.key())){
        JSON::Value tmp;
        tmp.assignFrom(*i, skip);
        (*this)[i.key()] = tmp;
      }
    }
  }
  if (myType == ARRAY){
    jsonForEachConst(rhs, i){
      JSON::Value tmp;
      tmp.assignFrom(*i, skip);
      append(tmp);
    }
  }
  return *this;
}

/// Sets this JSON::Value to be equal to the given JSON::Value.
JSON::Value & JSON::Value::operator=(const JSON::Value & rhs) {
  null();
  myType = rhs.myType;
  if (myType == STRING){
    strVal = rhs.strVal;
  }
  if (myType == BOOL || myType == INTEGER){
    intVal = rhs.intVal;
  }
  if (myType == DOUBLE){
    dblVal = rhs.dblVal;
  }
  if (myType == OBJECT){
    jsonForEachConst(rhs, i){
      (*this)[i.key()] = *i;
    }
  }
  if (myType == ARRAY){
    jsonForEachConst(rhs, i){
      append(*i);
    }
  }
  return *this;
}

/// Sets this JSON::Value to the given boolean.
JSON::Value & JSON::Value::operator=(const bool & rhs) {
  null();
  myType = BOOL;
  if (rhs) intVal = 1;
  return *this;
}

/// Sets this JSON::Value to the given string.
JSON::Value & JSON::Value::operator=(const std::string & rhs) {
  null();
  myType = STRING;
  strVal = rhs;
  return *this;
}

/// Sets this JSON::Value to the given string.
JSON::Value & JSON::Value::operator=(const char * rhs) {
  return ((*this) = (std::string)rhs);
}

/// Sets this JSON::Value to the given integer.
JSON::Value & JSON::Value::operator=(const long long int & rhs) {
  null();
  myType = INTEGER;
  intVal = rhs;
  return *this;
}

/// Sets this JSON::Value to the given integer.
JSON::Value & JSON::Value::operator=(const int & rhs) {
  return ((*this) = (long long int)rhs);
}

/// Sets this JSON::Value to the given double.
JSON::Value & JSON::Value::operator=(const double & rhs) {
  null();
  myType = DOUBLE;
  dblVal = rhs;
  return *this;
}

/// Sets this JSON::Value to the given integer.
JSON::Value & JSON::Value::operator=(const unsigned int & rhs) {
  return ((*this) = (long long int)rhs);
}

/// Automatic conversion to long long int - returns 0 if not convertable.
JSON::Value::operator long long int() const {
  if (myType == INTEGER) {
    return intVal;
  }
  if (myType == DOUBLE) {
    return (long long int)dblVal;
  }
  if (myType == STRING) {
    return atoll(strVal.c_str());
  }
  return 0;
}

/// Automatic conversion to double - returns 0 if not convertable.
JSON::Value::operator double() const {
  if (myType == INTEGER) {
    return (double)intVal;
  }
  if (myType == DOUBLE) {
    return dblVal;
  }
  if (myType == STRING) {
    return atof(strVal.c_str());
  }
  return 0;
}

/// Automatic conversion to std::string.
/// Returns the raw string value if available, otherwise calls toString().
JSON::Value::operator std::string() const {
  if (myType == STRING) {
    return strVal;
  } else {
    if (myType == EMPTY) {
      return "";
    } else {
      return toString();
    }
  }
}

/// Automatic conversion to bool.
/// Returns true if there is anything meaningful stored into this value.
JSON::Value::operator bool() const {
  if (myType == STRING) {
    return strVal != "";
  }
  if (myType == INTEGER) {
    return intVal != 0;
  }
  if (myType == DOUBLE) {
    return dblVal != 0;
  }
  if (myType == BOOL) {
    return intVal != 0;
  }
  if (myType == OBJECT) {
    return size() > 0;
  }
  if (myType == ARRAY) {
    return size() > 0;
  }
  if (myType == EMPTY) {
    return false;
  }
  return false; //unimplemented? should never happen...
}

/// Explicit conversion to std::string.
const std::string JSON::Value::asString() const {
  return (std::string) * this;
}
/// Explicit conversion to long long int.
const long long int JSON::Value::asInt() const {
  return (long long int) * this;
}
/// Explicit conversion to double.
const double JSON::Value::asDouble() const {
  return (double) * this;
}
/// Explicit conversion to bool.
const bool JSON::Value::asBool() const {
  return (bool) * this;
}

/// Explicit conversion to std::string reference.
/// Returns a direct reference for string type JSON::Value objects,
/// but a reference to a static empty string otherwise.
/// \warning Only save to use when the JSON::Value is a string type!
const std::string & JSON::Value::asStringRef() const {
  static std::string ugly_buffer;
  if (myType == STRING) {
    return strVal;
  }
  return ugly_buffer;
}

/// Explicit conversion to c-string.
/// Returns a direct reference for string type JSON::Value objects,
/// a reference to an empty string otherwise.
/// \warning Only save to use when the JSON::Value is a string type!
const char * JSON::Value::c_str() const {
  if (myType == STRING) {
    return strVal.c_str();
  }
  return "";
}

/// Retrieves or sets the JSON::Value at this position in the object.
/// Converts destructively to object if not already an object.
JSON::Value & JSON::Value::operator[](const std::string i) {
  if (myType != OBJECT) {
    null();
    myType = OBJECT;
  }
  Value * pntr = objVal[i];
  if (!pntr){
    objVal[i] = new JSON::Value();
    pntr = objVal[i];
  }
  return *pntr;
}

/// Retrieves or sets the JSON::Value at this position in the object.
/// Converts destructively to object if not already an object.
JSON::Value & JSON::Value::operator[](const char * i) {
  if (myType != OBJECT) {
    null();
    myType = OBJECT;
  }
  Value * pntr = objVal[i];
  if (!pntr){
    objVal[i] = new JSON::Value();
    pntr = objVal[i];
  }
  return *pntr;
}

/// Retrieves or sets the JSON::Value at this position in the array.
/// Converts destructively to array if not already an array.
JSON::Value & JSON::Value::operator[](unsigned int i) {
  static JSON::Value empty;
  if (myType != ARRAY) {
    null();
    myType = ARRAY;
  }
  while (i >= arrVal.size()) {
    append(empty);
  }
  return *arrVal[i];
}

/// Retrieves the JSON::Value at this position in the object.
/// Fails horribly if that values does not exist.
const JSON::Value & JSON::Value::operator[](const std::string i) const {
  return *objVal.find(i)->second;
}

/// Retrieves the JSON::Value at this position in the object.
/// Fails horribly if that values does not exist.
const JSON::Value & JSON::Value::operator[](const char * i) const {
  return *objVal.find(i)->second;
}

/// Retrieves the JSON::Value at this position in the array.
/// Fails horribly if that values does not exist.
const JSON::Value & JSON::Value::operator[](unsigned int i) const {
  return *arrVal[i];
}

/// Packs to a std::string for transfer over the network.
/// If the object is a container type, this function will call itself recursively and contain all contents.
/// As a side effect, this function clear the internal buffer of any object-types.
std::string JSON::Value::toPacked() const {
  std::string r;
  if (isInt() || isNull() || isBool()) {
    r += 0x01;
    uint64_t numval = intVal;
    r += *(((char *) &numval) + 7);
    r += *(((char *) &numval) + 6);
    r += *(((char *) &numval) + 5);
    r += *(((char *) &numval) + 4);
    r += *(((char *) &numval) + 3);
    r += *(((char *) &numval) + 2);
    r += *(((char *) &numval) + 1);
    r += *(((char *) &numval));
  }
  if (isString()) {
    r += 0x02;
    r += strVal.size() / (256 * 256 * 256);
    r += strVal.size() / (256 * 256);
    r += strVal.size() / 256;
    r += strVal.size() % 256;
    r += strVal;
  }
  if (isObject()) {
    r += 0xE0;
    if (objVal.size() > 0) {
      jsonForEachConst(*this, i){
        if (i.key().size() > 0) {
          r += i.key().size() / 256;
          r += i.key().size() % 256;
          r += i.key();
          r += i->toPacked();
        }
      }
    }
    r += (char)0x0;
    r += (char)0x0;
    r += (char)0xEE;
  }
  if (isArray()) {
    r += 0x0A;
    jsonForEachConst(*this, i){
      r += i->toPacked();
    }
    r += (char)0x0;
    r += (char)0x0;
    r += (char)0xEE;
  }
  return r;
}
//toPacked

/// Packs and transfers over the network.
/// If the object is a container type, this function will call itself recursively for all contents.
void JSON::Value::sendTo(Socket::Connection & socket) const {
  if (isInt() || isNull() || isBool()) {
    socket.SendNow("\001", 1);
    int tmpHalf = htonl((int)(intVal >> 32));
    socket.SendNow((char *)&tmpHalf, 4);
    tmpHalf = htonl((int)(intVal & 0xFFFFFFFF));
    socket.SendNow((char *)&tmpHalf, 4);
    return;
  }
  if (isString()) {
    socket.SendNow("\002", 1);
    int tmpVal = htonl((int)strVal.size());
    socket.SendNow((char *)&tmpVal, 4);
    socket.SendNow(strVal);
    return;
  }
  if (isObject()) {
    if (isMember("trackid") && isMember("time")) {
      unsigned int trackid = objVal.find("trackid")->second->asInt();
      long long time = objVal.find("time")->second->asInt();
      unsigned int size = 16;
      if (objVal.size() > 0) {
        jsonForEachConst(*this, i){
          if (i.key().size() > 0 && i.key() != "trackid" && i.key() != "time" && i.key() != "datatype") {
            size += 2 + i.key().size() + i->packedSize();
          }
        }
      }
      socket.SendNow("DTP2", 4);
      size = htonl(size);
      socket.SendNow((char *)&size, 4);
      trackid = htonl(trackid);
      socket.SendNow((char *)&trackid, 4);
      int tmpHalf = htonl((int)(time >> 32));
      socket.SendNow((char *)&tmpHalf, 4);
      tmpHalf = htonl((int)(time & 0xFFFFFFFF));
      socket.SendNow((char *)&tmpHalf, 4);
      socket.SendNow("\340", 1);
      if (objVal.size() > 0) {
        jsonForEachConst(*this, i){
          if (i.key().size() > 0 && i.key() != "trackid" && i.key() != "time" && i.key() != "datatype") {
            char sizebuffer[2] = {0, 0};
            sizebuffer[0] = (i.key().size() >> 8) & 0xFF;
            sizebuffer[1] = i.key().size() & 0xFF;
            socket.SendNow(sizebuffer, 2);
            socket.SendNow(i.key());
            i->sendTo(socket);
          }
        }
      }
      socket.SendNow("\000\000\356", 3);
      return;
    }
    if (isMember("tracks")) {
      socket.SendNow("DTSC", 4);
      unsigned int size = htonl(packedSize());
      socket.SendNow((char *)&size, 4);
    }
    socket.SendNow("\340", 1);
    if (objVal.size() > 0) {
      jsonForEachConst(*this, i){
        if (i.key().size() > 0) {
          char sizebuffer[2] = {0, 0};
          sizebuffer[0] = (i.key().size() >> 8) & 0xFF;
          sizebuffer[1] = i.key().size() & 0xFF;
          socket.SendNow(sizebuffer, 2);
          socket.SendNow(i.key());
          i->sendTo(socket);
        }
      }
    }
    socket.SendNow("\000\000\356", 3);
    return;
  }
  if (isArray()) {
    socket.SendNow("\012", 1);
    jsonForEachConst(*this, i){
      i->sendTo(socket);
    }
    socket.SendNow("\000\000\356", 3);
    return;
  }
}//sendTo

/// Returns the packed size of this Value.
unsigned int JSON::Value::packedSize() const {
  if (isInt() || isNull() || isBool()) {
    return 9;
  }
  if (isString()) {
    return 5 + strVal.size();
  }
  if (isObject()) {
    unsigned int ret = 4;
    if (objVal.size() > 0) {
      jsonForEachConst(*this, i){
        if (i.key().size() > 0) {
          ret += 2 + i.key().size() + i->packedSize();
        }
      }
    }
    return ret;
  }
  if (isArray()) {
    unsigned int ret = 4;
    jsonForEachConst(*this, i){
      ret += i->packedSize();
    }
    return ret;
  }
  return 0;
}//packedSize

/// Pre-packs any object-type JSON::Value to a std::string for transfer over the network, including proper DTMI header.
/// Non-object-types will print an error.
/// The internal buffer is guaranteed to be up-to-date after this function is called.
void JSON::Value::netPrepare() {
  if (myType != OBJECT) {
    DEBUG_MSG(DLVL_ERROR, "Only objects may be netpacked!");
    return;
  }
  std::string packed = toPacked();
  //insert proper header for this type of data
  int packID = -1;
  long long unsigned int time = (*this)["time"].asInt();
  std::string dataType;
  if (isMember("datatype") || isMember("trackid")) {
    dataType = (*this)["datatype"].asString();
    if (isMember("trackid")) {
      packID = (*this)["trackid"].asInt();
    } else {
      if ((*this)["datatype"].asString() == "video") {
        packID = 1;
      }
      if ((*this)["datatype"].asString() == "audio") {
        packID = 2;
      }
      if ((*this)["datatype"].asString() == "meta") {
        packID = 3;
      }
      //endmark and the likes...
      if (packID == -1) {
        packID = 0;
      }
    }
    removeMember("time");
    if (packID != 0) {
      removeMember("datatype");
    }
    removeMember("trackid");
    packed = toPacked();
    (*this)["time"] = (long long int)time;
    (*this)["datatype"] = dataType;
    (*this)["trackid"] = packID;
    strVal.resize(packed.size() + 20);
    memcpy((void *)strVal.c_str(), "DTP2", 4);
  } else {
    packID = -1;
    strVal.resize(packed.size() + 8);
    memcpy((void *)strVal.c_str(), "DTSC", 4);
  }
  //insert the packet length at bytes 4-7
  unsigned int size = packed.size();
  if (packID != -1) {
    size += 12;
  }
  size = htonl(size);
  memcpy((void *)(strVal.c_str() + 4), (void *) &size, 4);
  //copy the rest of the string
  if (packID == -1) {
    memcpy((void *)(strVal.c_str() + 8), packed.c_str(), packed.size());
    return;
  }
  packID = htonl(packID);
  memcpy((void *)(strVal.c_str() + 8), (void *) &packID, 4);
  int tmpHalf = htonl((int)(time >> 32));
  memcpy((void *)(strVal.c_str() + 12), (void *) &tmpHalf, 4);
  tmpHalf = htonl((int)(time & 0xFFFFFFFF));
  memcpy((void *)(strVal.c_str() + 16), (void *) &tmpHalf, 4);
  memcpy((void *)(strVal.c_str() + 20), packed.c_str(), packed.size());
}

/// Packs any object-type JSON::Value to a std::string for transfer over the network, including proper DTMI header.
/// Non-object-types will print an error and return an empty string.
/// This function returns a reference to an internal buffer where the prepared data is kept.
/// The internal buffer is *not* made stale if any changes occur inside the object - subsequent calls to toPacked() will clear the buffer,
/// calls to netPrepare will guarantee it is up-to-date.
std::string & JSON::Value::toNetPacked() {
  static std::string emptystring;
  //check if this is legal
  if (myType != OBJECT) {
    INFO_MSG("Ignored attempt to netpack a non-object.");
    return emptystring;
  }
  //if sneaky storage doesn't contain correct data, re-calculate it
  if (strVal.size() == 0 || strVal[0] != 'D' || strVal[1] != 'T') {
    netPrepare();
  }
  return strVal;
}

/// Converts this JSON::Value to valid JSON notation and returns it.
/// Makes absolutely no attempts to pretty-print anything. :-)
std::string JSON::Value::toString() const {
  switch (myType) {
    case INTEGER: {
        std::stringstream st;
        st << intVal;
        return st.str();
        break;
      }
    case DOUBLE: {
        std::stringstream st;
        st << dblVal;
        return st.str();
        break;
      }
    case BOOL: {
        if (intVal != 0){
          return "true";
        }else{
          return "false";
        }
        break;
      }
    case STRING: {
        return JSON::string_escape(strVal);
        break;
      }
    case ARRAY: {
        std::string tmp = "[";
        if (arrVal.size() > 0) {
          jsonForEachConst(*this, i){
            tmp += i->toString();
            if (i.num()+1 != arrVal.size()) {
              tmp += ",";
            }
          }
        }
        tmp += "]";
        return tmp;
        break;
      }
    case OBJECT: {
        std::string tmp2 = "{";
        if (objVal.size() > 0) {
          jsonForEachConst(*this, i){
            tmp2 += JSON::string_escape(i.key()) + ":";
            tmp2 += i->toString();
            if (i.num()+1 != objVal.size()) {
              tmp2 += ",";
            }
          }
        }
        tmp2 += "}";
        return tmp2;
        break;
      }
    case EMPTY:
    default:
      return "null";
  }
  return "null"; //should never get here...
}

/// Converts this JSON::Value to valid JSON notation and returns it.
/// Makes an attempt at pretty-printing.
std::string JSON::Value::toPrettyString(int indentation) const {
  switch (myType) {
    case INTEGER: {
        std::stringstream st;
        st << intVal;
        return st.str();
        break;
      }
    case DOUBLE: {
        std::stringstream st;
        st << dblVal;
        return st.str();
        break;
      }
    case STRING: {
        for (unsigned int i = 0; i < 201 && i < strVal.size(); ++i) {
          if (strVal[i] < 32 || strVal[i] > 126 || strVal.size() > 200) {
            return "\"" + JSON::Value((long long int)strVal.size()).asString() + " bytes of data\"";
          }
        }
        return JSON::string_escape(strVal);
        break;
      }
    case ARRAY: {
        if (arrVal.size() > 0) {
          std::string tmp = "[\n" + std::string(indentation + 2, ' ');
          jsonForEachConst(*this, i){
            tmp += i->toPrettyString(indentation + 2);
            if (i.num() + 1 != arrVal.size()) {
              tmp += ", ";
            }
          }
          tmp += "\n" + std::string(indentation, ' ') + "]";
          return tmp;
        } else {
          return "[]";
        }
        break;
      }
    case OBJECT: {
        if (objVal.size() > 0) {
          bool shortMode = false;
          if (size() <= 3 && isMember("len")) {
            shortMode = true;
          }
          std::string tmp2 = "{" + std::string((shortMode ? "" : "\n"));
          jsonForEachConst(*this, i){
            tmp2 += (shortMode ? std::string("") : std::string(indentation + 2, ' ')) + JSON::string_escape(i.key()) + ":";
            tmp2 += i->toPrettyString(indentation + 2);
            if (i.num() + 1 != objVal.size()) {
              tmp2 += "," + std::string((shortMode ? " " : "\n"));
            }
          }
          tmp2 += (shortMode ? std::string("") : "\n" + std::string(indentation, ' ')) + "}";
          return tmp2;
        } else {
          return "{}";
        }
        break;
      }
    case EMPTY:
    default:
      return "null";
  }
  return "null"; //should never get here...
}

/// Appends the given value to the end of this JSON::Value array.
/// Turns this value into an array if it is not already one.
void JSON::Value::append(const JSON::Value & rhs) {
  if (myType != ARRAY) {
    null();
    myType = ARRAY;
  }
  arrVal.push_back(new JSON::Value(rhs));
}

/// Prepends the given value to the beginning of this JSON::Value array.
/// Turns this value into an array if it is not already one.
void JSON::Value::prepend(const JSON::Value & rhs) {
  if (myType != ARRAY) {
    null();
    myType = ARRAY;
  }
  arrVal.push_front(new JSON::Value(rhs));
}

/// For array and object JSON::Value objects, reduces them
/// so they contain at most size elements, throwing away
/// the first elements and keeping the last ones.
/// Does nothing for other JSON::Value types, nor does it
/// do anything if the size is already lower or equal to the
/// given size.
void JSON::Value::shrink(unsigned int size) {
  while (arrVal.size() > size) {
    delete arrVal.front();
    arrVal.pop_front();
  }
  while (objVal.size() > size) {
    delete objVal.begin()->second;
    objVal.erase(objVal.begin());
  }
}

/// For object JSON::Value objects, removes the member with
/// the given name, if it exists. Has no effect otherwise.
void JSON::Value::removeMember(const std::string & name) {
  if (objVal.count(name)){
    delete objVal[name];
    objVal.erase(name);
  }
}

void JSON::Value::removeMember(const std::deque<Value*>::iterator & it){
  delete (*it);
  arrVal.erase(it);
}

void JSON::Value::removeMember(const std::map<std::string, Value*>::iterator & it){
  delete it->second;
  objVal.erase(it);
}

void JSON::Value::removeNullMembers(){
  bool again = true;
  while (again){
    again = false;
    jsonForEach(*this, m){
      if (m.key().size() && m->isNull()){
        removeMember(m.key());
        again = true;
        break;
      }
    }
  }
}

/// For object JSON::Value objects, returns true if the
/// given name is a member. Returns false otherwise.
bool JSON::Value::isMember(const std::string & name) const {
  return objVal.count(name) > 0;
}

/// Returns true if this object is an integer.
bool JSON::Value::isInt() const {
  return (myType == INTEGER);
}

/// Returns true if this object is a double.
bool JSON::Value::isDouble() const {
  return (myType == DOUBLE);
}

/// Returns true if this object is a string.
bool JSON::Value::isString() const {
  return (myType == STRING);
}

/// Returns true if this object is a bool.
bool JSON::Value::isBool() const {
  return (myType == BOOL);
}

/// Returns true if this object is an object.
bool JSON::Value::isObject() const {
  return (myType == OBJECT);
}

/// Returns true if this object is an array.
bool JSON::Value::isArray() const {
  return (myType == ARRAY);
}

/// Returns true if this object is null.
bool JSON::Value::isNull() const {
  return (myType == EMPTY);
}

/// Returns the total of the objects and array size combined.
unsigned int JSON::Value::size() const {
  return objVal.size() + arrVal.size();
}

/// Converts a std::string to a JSON::Value.
JSON::Value JSON::fromString(const char * data, const uint32_t data_len) {
  const std::string str(data, data_len);
  return JSON::fromString(str);
}

/// Converts a std::string to a JSON::Value.
JSON::Value JSON::fromString(const std::string & json) {
  std::istringstream is(json);
  return JSON::Value(is);
}

/// Converts a file to a JSON::Value.
JSON::Value JSON::fromFile(std::string filename) {
  std::ifstream File;
  File.open(filename.c_str());
  JSON::Value ret(File);
  File.close();
  return ret;
}

/// Parses a single DTMI type - used recursively by the JSON::fromDTMI functions.
/// This function updates i every call with the new position in the data.
/// \param data The raw data to parse.
/// \param len The size of the raw data.
/// \param i Current parsing position in the raw data (defaults to 0).
/// \returns A single JSON::Value, parsed from the raw data.
JSON::Value JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigned int & i) {
  JSON::Value ret;
  fromDTMI(data, len, i, ret);
  return ret;
}

/// Parses a single DTMI type - used recursively by the JSON::fromDTMI functions.
/// This function updates i every call with the new position in the data.
/// \param data The raw data to parse.
/// \param len The size of the raw data.
/// \param i Current parsing position in the raw data (defaults to 0).
/// \param ret Will be set to JSON::Value, parsed from the raw data.
void JSON::fromDTMI(const unsigned char * data, unsigned int len, unsigned int & i, JSON::Value & ret) {
  ret.null();
  if (i >= len) {
    return;
  }
  switch (data[i]) {
    case 0x01: { //integer
        if (i + 8 >= len) {
          return;
        }
        unsigned char tmpdbl[8];
        tmpdbl[7] = data[i + 1];
        tmpdbl[6] = data[i + 2];
        tmpdbl[5] = data[i + 3];
        tmpdbl[4] = data[i + 4];
        tmpdbl[3] = data[i + 5];
        tmpdbl[2] = data[i + 6];
        tmpdbl[1] = data[i + 7];
        tmpdbl[0] = data[i + 8];
        i += 9; //skip 8(an uint64_t)+1 forwards
        uint64_t * d = (uint64_t *)tmpdbl;
        ret = (long long int) * d;
        return;
        break;
      }
    case 0x02: { //string
        if (i + 4 >= len) {
          return;
        }
        unsigned int tmpi = data[i + 1] * 256 * 256 * 256 + data[i + 2] * 256 * 256 + data[i + 3] * 256 + data[i + 4]; //set tmpi to UTF-8-long length
        std::string tmpstr = std::string((const char *)data + i + 5, (size_t)tmpi); //set the string data
        if (i + 4 + tmpi >= len) {
          return;
        }
        i += tmpi + 5; //skip length+size+1 forwards
        ret = tmpstr;
        return;
        break;
      }
    case 0xFF: //also object
    case 0xE0: { //object
        ++i;
        while (data[i] + data[i + 1] != 0 && i < len) { //while not encountering 0x0000 (we assume 0x0000EE)
          if (i + 2 >= len) {
            return;
          }
          unsigned int tmpi = data[i] * 256 + data[i + 1]; //set tmpi to the UTF-8 length
          std::string tmpstr = std::string((const char *)data + i + 2, (size_t)tmpi); //set the string data
          i += tmpi + 2; //skip length+size forwards
          ret[tmpstr].null();
          fromDTMI(data, len, i, ret[tmpstr]); //add content, recursively parsed, updating i, setting indice to tmpstr
        }
        i += 3; //skip 0x0000EE
        return;
        break;
      }
    case 0x0A: { //array
        ++i;
        while (data[i] + data[i + 1] != 0 && i < len) { //while not encountering 0x0000 (we assume 0x0000EE)
          JSON::Value tval;
          fromDTMI(data, len, i, tval); //add content, recursively parsed, updating i
          ret.append(tval);
        }
        i += 3; //skip 0x0000EE
        return;
        break;
      }
  }
  DEBUG_MSG(DLVL_FAIL, "Unimplemented DTMI type %hhx, @ %i / %i - returning.", data[i], i, len);
  i += 1;
  return;
} //fromOneDTMI

/// Parses a std::string to a valid JSON::Value.
/// This function will find one DTMI object in the string and return it.
void JSON::fromDTMI(std::string & data, JSON::Value & ret) {
  unsigned int i = 0;
  return fromDTMI((const unsigned char *)data.c_str(), data.size(), i, ret);
} //fromDTMI

/// Parses a std::string to a valid JSON::Value.
/// This function will find one DTMI object in the string and return it.
JSON::Value JSON::fromDTMI(std::string & data) {
  unsigned int i = 0;
  return fromDTMI((const unsigned char *)data.c_str(), data.size(), i);
} //fromDTMI

void JSON::fromDTMI2(std::string & data, JSON::Value & ret) {
  unsigned int i = 0;
  fromDTMI2((const unsigned char *)data.c_str(), data.size(), i, ret);
  return;
}

JSON::Value JSON::fromDTMI2(std::string & data) {
  JSON::Value ret;
  unsigned int i = 0;
  fromDTMI2((const unsigned char *)data.c_str(), data.size(), i, ret);
  return ret;
}

void JSON::fromDTMI2(const unsigned char * data, unsigned int len, unsigned int & i, JSON::Value & ret) {
  if (len < 13) {
    return;
  }
  long long int tmpTrackID = ntohl(((int *)(data + i))[0]);
  long long int tmpTime = ntohl(((int *)(data + i))[1]);
  tmpTime <<= 32;
  tmpTime += ntohl(((int *)(data + i))[2]);
  i += 12;
  fromDTMI(data, len, i, ret);
  ret["time"] = tmpTime;
  ret["trackid"] = tmpTrackID;
  return;
}

JSON::Value JSON::fromDTMI2(const unsigned char * data, unsigned int len, unsigned int & i) {
  JSON::Value ret;
  fromDTMI2(data, len, i, ret);
  return ret;
}