

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.0.0.170915_Beta4 (15 September 2017)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2017
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#include "DataMessage.h"
#include "PsyTime.h"

namespace cmlabs {

std::string DataMessageHeader::toJSON() {
	if (cid != DATAMESSAGEID) return 0;
	return utils::StringFormat("{ \"size\": %u, \"memid\": \"%llu\", \"time\": \"%llu\", \"time__desc\": \"%s\", \"sendtime\": \"%llu\", \"sendtime__desc\": \"%s\", \"recvtime\": \"%llu\", \"recvtime__desc\": \"%s\", \"origin\": %u, \"destination\": %u, \"ttl\": \"%llu\", \"eol__desc\": \"%s\", \"priority\": %u, \"policy\": %u, \"from\": %u, \"to\": %u, \"type\": \"%s\", \"tag\": \"%u\", \"status\": %u, \"reference\": \"%llu\", \"serial\": \"%llu\", \"contextchange\": \"%s\", \"userdatacount\": %u, \"userdatasize\": %u }",
		size, memid,
		time, time ? PrintTimeString(time).c_str() : "",
		sendtime, sendtime ? PrintTimeString(sendtime).c_str() : "",
		recvtime, recvtime ? PrintTimeString(recvtime).c_str() : "",
		origin, destination, ttl, ttl ? PrintTimeString(time + ttl).c_str() : "",
		priority, policy, from, to, type.toString().c_str(), tag, status, reference, serial,
		contextchange.isValid() ? contextchange.toString().c_str() : "",
		userCount, userSize);
}

std::string DataMessageHeader::toXML() {
	if (cid != DATAMESSAGEID) return 0;

	return utils::StringFormat("<datamessage size=\"%u\" memid=\"%llu\" time=\"%llu\" timetext=\"%s\" sendtime=\"%llu\" sendtimetext=\"%s\" recvtime=\"%llu\" recvtimetext=\"%s\" origin=\"%u\" destination=\"%u\" ttl=\"%llu\" eoltext=\"%s\" priority=\"%u\" policy=\"%u\" from=\"%u\" to=\"%u\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" serial=\"%llu\" contextchange=\"%s\" userdatacount=\"%u\" userdatasize=\"%u\" />\n",
		size, memid,
		time, time ? PrintTimeString(time).c_str() : "",
		sendtime, sendtime ? PrintTimeString(sendtime).c_str() : "",
		recvtime, recvtime ? PrintTimeString(recvtime).c_str() : "",
		origin, destination, ttl, ttl ? PrintTimeString(time + ttl).c_str() : "", priority, policy, from, to, type.toString().c_str(), tag, status, reference, serial, contextchange.isValid() ? contextchange.toString().c_str() : "", userCount, userSize);

	//if (contextchange.isValid())
	//	return utils::StringFormat("<datamessage size=\"%u\" memid=\"%llu\" time=\"%llu\" sendtime=\"%llu\" recvtime=\"%llu\" origin=\"%u\" destination=\"%u\" ttl=\"%llu\" priority=\"%u\" policy=\"%u\" from=\"%u\" to=\"%u\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" contextchange=\"%s\" userdatacount=\"%u\" userdatasize=\"%u\" />\n",
	//	size, memid, time, sendtime, recvtime, origin, destination, ttl, priority, policy, from, to, type.toString().c_str(), tag, status, reference, contextchange.toString().c_str(), userCount, userSize);
	//else
	//	return utils::StringFormat("<datamessage size=\"%u\" memid=\"%llu\" time=\"%llu\" sendtime=\"%llu\" recvtime=\"%llu\" origin=\"%u\" destination=\"%u\" ttl=\"%llu\" priority=\"%u\" policy=\"%u\" from=\"%u\" to=\"%u\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" contextchange=\"\" userdatacount=\"%u\" userdatasize=\"%u\" />\n",
	//		size, memid, time, sendtime, recvtime, origin, destination, ttl, priority, policy, from, to, type.toString().c_str(), tag, status, reference, userCount, userSize);
}


std::string DataMessage::getUserEntriesAsString() {
	if (data->cid != DATAMESSAGEID) return 0;

	if (!data->userCount)
		return "";

	std::map< std::string, std::list<std::string> > userMaps;
	std::map< std::string, std::list<int64> > userArrays;

	DataMessage* msg;
	bool ok;
	const char* key;
	const char* mapStart, *mapEnd;
	std::string userData;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			key = src + sizeof(DataMessageEntryHeader);
			src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
			if ((mapStart = strstr(key, "_-|")) && (mapEnd = strstr(key, "|-_"))) {
				userArrays[std::string(key, mapStart - key)].push_back(utils::Ascii2Int64(std::string(mapStart + 3, mapEnd - mapStart - 3).c_str()));
				src += ((DataMessageEntryHeader*)src)->size;
				continue;
			}
			else if ((mapStart = strstr(key, "_-[")) && (mapEnd = strstr(key, "]-_"))) {
				userMaps[std::string(key, mapStart - key)].push_back(std::string(mapStart + 3, mapEnd - mapStart - 3));
				src += ((DataMessageEntryHeader*)src)->size;
				continue;
			}
			switch (((DataMessageEntryHeader*)src)->cid) {
				case CONSTCHARID:
					userData += utils::StringFormat("'%s' : '%s' (string)\n", key, src + sizeof(DataMessageEntryHeader));
					break;
				case TIMEID:
					userData += utils::StringFormat("'%s' : %s (time)\n",
						key,
						*(uint64*)(src + sizeof(DataMessageEntryHeader)) ? PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader))).c_str() : ""
						);
					break;
				case CHARDATAID:
					userData += utils::StringFormat("'%s' : size %u (binary)\n", key, ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader));
					break;
				case CONSTCHARINFOID:
					userData += utils::StringFormat("'%s' : (string of size %lld)\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case CHARDATAINFOID:
					userData += utils::StringFormat("'%s' : (binary of size %lld)\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEINFOID:
					userData += utils::StringFormat("'%s' : (message of size %lld)\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case INTID:
					userData += utils::StringFormat("'%s' : %lld (integer)\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case DOUBLEID:
					userData += utils::StringFormat("'%s' : %f (float)\n", key, *(float64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEID:
					msg = new DataMessage(src + sizeof(DataMessageEntryHeader));
					if (msg) {
						if (userData.length()) userData += ", ";
						userData += utils::StringFormat("'%s' : (message)\n%s\n", key, utils::TextIndent(msg->getUserEntriesAsString().c_str(), " -").c_str());
					}
					delete(msg);
					break;
				case DATAMESSAGEDRAFTID:
					// ignore
				default:
					break;
			}
		}
		// else cannot generate JSON for this entry
		src += ((DataMessageEntryHeader*)src)->size;
	}

	std::string subUserData;

	std::list< int64 >::iterator entryII, entryEE;
	std::map< std::string, std::list<int64 > >::iterator keyII = userArrays.begin(), keyEE = userArrays.end();
	while (keyII != keyEE) {
		subUserData.clear();
		entryII = keyII->second.begin();
		entryEE = keyII->second.end();
		while (entryII != entryEE) {
			switch (getContentType(*entryII, keyII->first.c_str())) {
			case CONSTCHARID:
				subUserData += utils::StringFormat("%lld : '%s' (string)\n", *entryII, getAsString(*entryII, keyII->first.c_str()).c_str());
				break;
			case TIMEID:
				subUserData += utils::StringFormat("%lld : %s (time)\n",
					*entryII,
					getAsString(*entryII, keyII->first.c_str()).c_str()
				);
				break;
			case CHARDATAID:
				subUserData += utils::StringFormat("%lld : size %u (binary)\n", *entryII, getContentSize(*entryII, keyII->first.c_str()));
				break;
			case DATAMESSAGEID:
				msg = getAttachedMessageCopy(*entryII, keyII->first.c_str());
				if (msg) {
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("%lld : (message)\n%s\n", *entryII, utils::TextIndent(msg->getUserEntriesAsString().c_str(), " -").c_str());
				}
				delete(msg);
				break;
			case INTID:
				subUserData += utils::StringFormat("%lld : %lld (integer)\n", *entryII, getInt(*entryII, keyII->first.c_str(), ok));
				break;
			case DOUBLEID:
				subUserData += utils::StringFormat("%lld : %f (float)\n", *entryII, getDouble(*entryII, keyII->first.c_str(), ok));
				break;
			case CONSTCHARINFOID:
				subUserData += utils::StringFormat("%lld : (string of size %lld)\n", *entryII, getInt(*entryII, keyII->first.c_str(), ok));
				break;
			case CHARDATAINFOID:
				subUserData += utils::StringFormat("%lld : (binary of size %lld)\n", *entryII, getInt(*entryII, keyII->first.c_str(), ok));
				break;
			case DATAMESSAGEINFOID:
				subUserData += utils::StringFormat("%lld : (message of size %lld)\n", *entryII, getInt(*entryII, keyII->first.c_str(), ok));
				break;
			default:
				break;
			}
			entryII++;
		}
		userData += utils::StringFormat("'%s' : (array)\n%s", keyII->first.c_str(), utils::TextIndent(subUserData.c_str(), " -").c_str());
		keyII++;
	}

	std::list< std::string >::iterator entryI, entryE;
	std::map< std::string, std::list<std::string > >::iterator keyI = userMaps.begin(), keyE = userMaps.end();
	while (keyI != keyE) {
		subUserData.clear();
		entryI = keyI->second.begin();
		entryE = keyI->second.end();
		while (entryI != entryE) {
			switch (getContentType(entryI->c_str(), keyI->first.c_str())) {
			case CONSTCHARID:
				subUserData += utils::StringFormat("'%s' : '%s' (string)\n", entryI->c_str(), getAsString(entryI->c_str(), keyI->first.c_str()).c_str());
				break;
			case TIMEID:
				subUserData += utils::StringFormat("'%s' : %s (time)\n",
					entryI->c_str(),
					getAsString(entryI->c_str(), keyI->first.c_str()).c_str()
					);
				break;
			case CHARDATAID:
				subUserData += utils::StringFormat("'%s' : size %u (binary)\n", entryI->c_str(), getContentSize(entryI->c_str(), keyI->first.c_str()));
				break;
			case DATAMESSAGEID:
				msg = getAttachedMessageCopy(entryI->c_str(), keyI->first.c_str());
				if (msg) {
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("'%s' : (message)\n%s\n", entryI->c_str(), utils::TextIndent(msg->getUserEntriesAsString().c_str(), " -").c_str());
				}
				delete(msg);
				break;
			case INTID:
				subUserData += utils::StringFormat("'%s' : %lld (integer)\n", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str(), ok));
				break;
			case DOUBLEID:
				subUserData += utils::StringFormat("'%s' : %f (float)\n", entryI->c_str(), getDouble(entryI->c_str(), keyI->first.c_str(), ok));
				break;
			case CONSTCHARINFOID:
				subUserData += utils::StringFormat("'%s' : (string of size %lld)\n", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str(), ok));
				break;
			case CHARDATAINFOID:
				subUserData += utils::StringFormat("'%s' : (binary of size %lld)\n", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str(), ok));
				break;
			case DATAMESSAGEINFOID:
				subUserData += utils::StringFormat("'%s' : (message of size %lld)\n", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str(), ok));
				break;
			default:
				break;
			}
			entryI++;
		}
		userData += utils::StringFormat("'%s' : (map)\n%s", keyI->first.c_str(), utils::TextIndent(subUserData.c_str(), " -").c_str());
		keyI++;
	}

	return userData;
}

std::string DataMessage::toJSON() {
	if (data->cid != DATAMESSAGEID) return "";

	if (!data->userCount)
		return data->toJSON();

	std::map< std::string, std::list<std::string> > userMaps;
	std::map< std::string, std::list<int64> > userArrays;

	uint32 draftSize = 0;
	uint32 draftUserSize = 0;
	uint32 draftUserCount = 0;

	const char* oldData = NULL;
	DataMessage* msg = new DataMessage();
	bool ok;
	const char* key;
	const char* mapStart, *mapEnd;
	std::string userData;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			key = src + sizeof(DataMessageEntryHeader);
			src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
			if ((mapStart = strstr(key, "_-|")) && (mapEnd = strstr(key, "|-_"))) {
				userArrays[std::string(key, mapStart - key)].push_back(utils::Ascii2Int64(std::string(mapStart + 3, mapEnd - mapStart - 3).c_str()));
				src += ((DataMessageEntryHeader*)src)->size;
				continue;
			}
			else if ((mapStart = strstr(key, "_-[")) && (mapEnd = strstr(key, "]-_"))) {
				userMaps[std::string(key, mapStart - key)].push_back(std::string(mapStart + 3, mapEnd - mapStart - 3));
				src += ((DataMessageEntryHeader*)src)->size;
				continue;
			}
			switch (((DataMessageEntryHeader*)src)->cid) {
				case CONSTCHARID:
					if (userData.length()) userData += ", ";
					userData += utils::StringFormat("\"%s\": {\"type\": \"text\", \"value\": \"%s\" }\n", key, src + sizeof(DataMessageEntryHeader));
					break;
				case TIMEID:
					if (userData.length()) userData += ", ";
					userData += utils::StringFormat("\"%s\": {\"type\": \"time\", \"value\": %llu, \"text\": \"%s\" }\n",
						key, *(uint64*)(src + sizeof(DataMessageEntryHeader)),
						*(uint64*)(src + sizeof(DataMessageEntryHeader)) ? PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader))).c_str() : ""
						);
					break;
				case CHARDATAID:
					if (userData.length()) userData += ", ";
					userData += utils::StringFormat("\"%s\": {\"type\": \"binary\", \"size\": %u }\n", key, ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader));
					break;
				case INTID:
					if (userData.length()) userData += ", ";
					userData += utils::StringFormat("\"%s\": {\"type\": \"integer\", \"value\": %lld }\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case DOUBLEID:
					if (userData.length()) userData += ", ";
					userData += utils::StringFormat("\"%s\": {\"type\": \"double\", \"value\": %f }\n", key, *(float64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEID:
					if (((DataMessageHeader*)(src + sizeof(DataMessageEntryHeader)))->cid == DATAMESSAGEID) {
						if (!oldData)
							oldData = msg->swapMessageData(src + sizeof(DataMessageEntryHeader));
						else
							msg->swapMessageData(src + sizeof(DataMessageEntryHeader));
						//msg = new DataMessage(src + sizeof(DataMessageEntryHeader));
						//if (msg) {
						if (userData.length()) userData += ", ";
						userData += utils::StringFormat("\"%s\": {\"type\": \"message\", \"value\": %s }\n", key, msg->toJSON().c_str());
						//}
						//delete(msg);
					}
					break;
				case CONSTCHARINFOID:
					userData += utils::StringFormat("\"%s\": {\"type\": \"textinfo\", \"size\": %u }\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case CHARDATAINFOID:
					userData += utils::StringFormat("\"%s\": {\"type\": \"binary\", \"size\": %u }\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEINFOID:
					userData += utils::StringFormat("\"%s\": {\"type\": \"messageinfo\", \"size\": %u }\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEDRAFTID:
					if (strcmp(key, "OS") == 0)
						draftSize = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
					else if (strcmp(key, "US") == 0)
						draftUserSize = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
					else if (strcmp(key, "UC") == 0)
						draftUserCount = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
				default:
					break;
			}
		}
		// else cannot generate JSON for this entry
		src += ((DataMessageEntryHeader*)src)->size;
	}

	if (oldData)
		msg->swapMessageData(oldData);
	delete(msg);
	
	std::string subUserData;

	std::list< int64 >::iterator entryII, entryEE;
	std::map< std::string, std::list<int64 > >::iterator keyII = userArrays.begin(), keyEE = userArrays.end();
	while (keyII != keyEE) {
		subUserData.clear();
		entryII = keyII->second.begin();
		entryEE = keyII->second.end();
		while (entryII != entryEE) {
			switch (getContentType(*entryII, keyII->first.c_str())) {
			case CONSTCHARID:
				if (subUserData.length()) subUserData += ", ";
				subUserData += utils::StringFormat("%lld: {\"type\": \"text\", \"value\": \"%s\" }\n", *entryII, getAsString(*entryII, keyII->first.c_str()).c_str());
				break;
			case TIMEID:
				if (subUserData.length()) subUserData += ", ";
				subUserData += utils::StringFormat("%lld: {\"type\": \"time\", \"value\": %llu, \"text\": \"%s\" }\n",
					*entryII,
					getTime(*entryII, keyII->first.c_str()),
					getAsString(*entryII, keyII->first.c_str()).c_str()
				);
				break;
			case CHARDATAID:
				if (subUserData.length()) subUserData += ", ";
				subUserData += utils::StringFormat("%lld: {\"type\": \"binary\", \"size\": %u }\n", *entryII, getContentSize(*entryII, keyII->first.c_str()));
				break;
			case DATAMESSAGEID:
				if (subUserData.length()) subUserData += ", ";
				msg = getAttachedMessageCopy(*entryII, keyII->first.c_str());
				if (msg) {
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("%lld: {\"type\": \"message\", \"value\": %s }\n", *entryII, msg->toJSON().c_str());
				}
				delete(msg);
				break;
			case INTID:
				if (subUserData.length()) subUserData += ", ";
				subUserData += utils::StringFormat("%lld: {\"type\": \"integer\", \"value\": %lld }\n", *entryII, getInt(*entryII, keyII->first.c_str(), ok));
				break;
			case DOUBLEID:
				if (subUserData.length()) subUserData += ", ";
				subUserData += utils::StringFormat("%lld: {\"type\": \"double\", \"value\": %f }\n", *entryII, getDouble(*entryII, keyII->first.c_str(), ok));
				break;
			case CONSTCHARINFOID:
				if (subUserData.length()) subUserData += ", ";
				subUserData += utils::StringFormat("%lld: {\"type\": \"textinfo\", \"size\": %lld }", *entryII, getInt(*entryII, keyII->first.c_str(), ok));
				break;
			case CHARDATAINFOID:
				if (subUserData.length()) subUserData += ", ";
				subUserData += utils::StringFormat("%lld: {\"type\": \"binary\", \"size\": %lld }", *entryII, getInt(*entryII, keyII->first.c_str(), ok));
				break;
			case DATAMESSAGEINFOID:
				if (subUserData.length()) subUserData += ", ";
				subUserData += utils::StringFormat("%lld: {\"type\": \"messageinfo\", \"size\": %lld }", *entryII, getInt(*entryII, keyII->first.c_str(), ok));
				break;
			default:
				break;
			}
			entryII++;
		}
		if (userData.length()) userData += ", ";
		userData += utils::StringFormat("\"%s\": {\"type\": \"array\", \"value\":\n{%s} }\n", keyII->first.c_str(), subUserData.c_str());
		keyII++;
	}


	std::list< std::string >::iterator entryI, entryE;
	std::map< std::string, std::list<std::string > >::iterator keyI = userMaps.begin(), keyE = userMaps.end();
	while (keyI != keyE) {
		subUserData.clear();
		entryI = keyI->second.begin();
		entryE = keyI->second.end();
		while (entryI != entryE) {
			switch (getContentType(entryI->c_str(), keyI->first.c_str())) {
				case CONSTCHARID:
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("\"%s\": {\"type\": \"text\", \"value\": \"%s\" }\n", entryI->c_str(), getAsString(entryI->c_str(), keyI->first.c_str()).c_str());
					break;
				case TIMEID:
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("\"%s\": {\"type\": \"time\", \"value\": %llu, \"text\": \"%s\" }\n",
						entryI->c_str(),
						getTime(entryI->c_str(), keyI->first.c_str()),
						getAsString(entryI->c_str(), keyI->first.c_str()).c_str()
						);
					break;
				case CHARDATAID:
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("\"%s\": {\"type\": \"binary\", \"size\": %u }\n", entryI->c_str(), getContentSize(entryI->c_str(), keyI->first.c_str()));
					break;
				case DATAMESSAGEID:
					if (subUserData.length()) subUserData += ", ";
					msg = getAttachedMessageCopy(entryI->c_str(), keyI->first.c_str());
					if (msg) {
						if (subUserData.length()) subUserData += ", ";
						subUserData += utils::StringFormat("\"%s\": {\"type\": \"message\", \"value\": %s }\n", entryI->c_str(), msg->toJSON().c_str());
					}
					delete(msg);
					break;
				case INTID:
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("\"%s\": {\"type\": \"integer\", \"value\": %lld }\n", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str(), ok));
					break;
				case DOUBLEID:
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("\"%s\": {\"type\": \"double\", \"value\": %f }\n", entryI->c_str(), getDouble(entryI->c_str(), keyI->first.c_str(), ok));
					break;
				case CONSTCHARINFOID:
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("\"%s\": {\"type\": \"textinfo\", \"size\": %lld }", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str(), ok));
					break;
				case CHARDATAINFOID:
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("\"%s\": {\"type\": \"binary\", \"size\": %lld }", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str(), ok));
					break;
				case DATAMESSAGEINFOID:
					if (subUserData.length()) subUserData += ", ";
					subUserData += utils::StringFormat("\"%s\": {\"type\": \"messageinfo\", \"size\": %lld }", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str(), ok));
					break;
				default:
					break;
			}
			entryI++;
		}
		if (userData.length()) userData += ", ";
		userData += utils::StringFormat("\"%s\": {\"type\": \"map\", \"value\":\n{%s} }\n", keyI->first.c_str(), subUserData.c_str());
		keyI++;
	}

	if (draftSize) {
		return utils::StringFormat("{ \"draft\":\"yes\", \"size\": %u, \"memid\": \"%llu\", \"time\": \"%llu\", \"time__text\": \"%s\", \"sendtime\": \"%llu\", \"sendtime__text\": \"%s\", \"recvtime\": \"%llu\", \"recvtime__text\": \"%s\", \"origin\": %u, \"destination\": %u, \"ttl\": \"%llu\", \"eol__text\": \"%s\", \"priority\": %u, \"policy\": %u, \"from\": %u, \"to\": %u, \"type\": \"%s\", \"tag\": \"%u\", \"status\": %u, \"reference\": \"%llu\", \"serial\": \"%llu\", \"contextchange\": \"%s\", \"userdatacount\": %u, \"userdatasize\": %u, \"userdata\":\n{\n%s}\n }\n",
			draftSize, data->memid,
			data->time, data->time ? PrintTimeString(data->time).c_str() : "",
			data->sendtime, data->sendtime ? PrintTimeString(data->sendtime).c_str() : "",
			data->recvtime, data->recvtime ? PrintTimeString(data->recvtime).c_str() : "",
			data->origin, data->destination, data->ttl, data->ttl ? PrintTimeString(data->time + data->ttl).c_str() : "",
			data->priority, data->policy, data->from, data->to, data->type.toString().c_str(), data->tag, data->status, data->reference, data->serial,
			data->contextchange.isValid() ? data->contextchange.toString().c_str() : "",
			draftUserCount, draftUserSize, userData.c_str());
	}
	else {
		return utils::StringFormat("{ \"size\": %u, \"memid\": \"%llu\", \"time\": \"%llu\", \"time__text\": \"%s\", \"sendtime\": \"%llu\", \"sendtime__text\": \"%s\", \"recvtime\": \"%llu\", \"recvtime__text\": \"%s\", \"origin\": %u, \"destination\": %u, \"ttl\": \"%llu\", \"eol__text\": \"%s\", \"priority\": %u, \"policy\": %u, \"from\": %u, \"to\": %u, \"type\": \"%s\", \"tag\": \"%u\", \"status\": %u, \"reference\": \"%llu\", \"serial\": \"%llu\", \"contextchange\": \"%s\", \"userdatacount\": %u, \"userdatasize\": %u, \"userdata\":\n{\n%s}\n }\n",
			data->size, data->memid,
			data->time, data->time ? PrintTimeString(data->time).c_str() : "",
			data->sendtime, data->sendtime ? PrintTimeString(data->sendtime).c_str() : "",
			data->recvtime, data->recvtime ? PrintTimeString(data->recvtime).c_str() : "",
			data->origin, data->destination, data->ttl, data->ttl ? PrintTimeString(data->time + data->ttl).c_str() : "",
			data->priority, data->policy, data->from, data->to, data->type.toString().c_str(), data->tag, data->status, data->reference, data->serial,
			data->contextchange.isValid() ? data->contextchange.toString().c_str() : "",
			data->userCount, data->userSize, userData.c_str());
	}
}

std::string DataMessage::toXML() {
	if (data->cid != DATAMESSAGEID) return "";

	if (!data->userCount)
		return data->toXML();

	std::map< std::string, std::list<std::string> > userMaps;
	std::map< std::string, std::list<int64> > userArrays;
	uint32 draftSize = 0;
	uint32 draftUserSize = 0;
	uint32 draftUserCount = 0;

	const char* oldData = NULL;
	DataMessage* msg = new DataMessage();
	const char* key;
	const char* mapStart, *mapEnd;
	std::string userData;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			key = src + sizeof(DataMessageEntryHeader);
			src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
			if ((mapStart = strstr(key, "_-|")) && (mapEnd = strstr(key, "|-_"))) {
				userArrays[std::string(key, mapStart - key)].push_back(utils::Ascii2Int64(std::string(mapStart + 3, mapEnd - mapStart - 3).c_str()));
				src += ((DataMessageEntryHeader*)src)->size;
				continue;
			}
			else if ((mapStart = strstr(key, "_-[")) && (mapEnd = strstr(key, "]-_"))) {
				userMaps[std::string(key, mapStart - key)].push_back(std::string(mapStart + 3, mapEnd - mapStart - 3));
				src += ((DataMessageEntryHeader*)src)->size;
				continue;
			}
			switch (((DataMessageEntryHeader*)src)->cid) {
			case CONSTCHARID:
				userData += utils::StringFormat("<data name=\"%s\" type=\"text\" value=\"%s\" />\n", key, src + sizeof(DataMessageEntryHeader));
				break;
			case TIMEID:
				userData += utils::StringFormat("<data name=\"%s\" type=\"time\" value=\"%llu\" text=\"%s\" />\n",
					key,
					*(uint64*)(src + sizeof(DataMessageEntryHeader)),
					*(uint64*)(src + sizeof(DataMessageEntryHeader)) ?
					PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader))).c_str() : ""
					);
				break;
			case CHARDATAID:
				userData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%u\" />\n", key, ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader));
				break;
			case INTID:
				userData += utils::StringFormat("<data name=\"%s\" type=\"integer\" value=\"%lld\" />\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
				break;
			case DOUBLEID:
				userData += utils::StringFormat("<data name=\"%s\" type=\"float\" value=\"%f\" />\n", key, *(float64*)(src + sizeof(DataMessageEntryHeader)));
				break;
			case DATAMESSAGEID:
				if (((DataMessageHeader*)(src + sizeof(DataMessageEntryHeader)))->cid == DATAMESSAGEID) {
					if (!oldData)
						oldData = msg->swapMessageData(src + sizeof(DataMessageEntryHeader));
					else
						msg->swapMessageData(src + sizeof(DataMessageEntryHeader));
					//msg = new DataMessage(src + sizeof(DataMessageEntryHeader));
					//if (msg)
					userData += utils::StringFormat("<data name=\"%s\" type=\"datamessage\">\n%s</data>", key, msg->toXML().c_str());
					//delete(msg);
				}
				break;
			case CONSTCHARINFOID:
				userData += utils::StringFormat("<data name=\"%s\" type=\"textinfo\" size=\"%u\" />\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
				break;
			case CHARDATAINFOID:
				userData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%u\" />\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
				break;
			case DATAMESSAGEINFOID:
				userData += utils::StringFormat("<data name=\"%s\" type=\"messageinfo\" size=\"%u\" />\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
				break;
			case DATAMESSAGEDRAFTID:
				if (strcmp(key, "OS") == 0)
					draftSize = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
				else if (strcmp(key, "US") == 0)
					draftUserSize = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
				else if (strcmp(key, "UC") == 0)
					draftUserCount = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
			default:
				break;
			}
		}
		// else cannot generate JSON for this entry
		src += ((DataMessageEntryHeader*)src)->size;
	}

	if (oldData)
		msg->swapMessageData(oldData);
	delete(msg);

	std::string subUserData;

	std::list< int64 >::iterator entryII, entryEE;
	std::map< std::string, std::list<int64 > >::iterator keyII = userArrays.begin(), keyEE = userArrays.end();
	while (keyII != keyEE) {
		subUserData.clear();
		entryII = keyII->second.begin();
		entryEE = keyII->second.end();
		while (entryII != entryEE) {
			switch (getContentType(*entryII, keyII->first.c_str())) {
			case CONSTCHARID:
				subUserData += utils::StringFormat("<data name=\"%lld\" type=\"text\" value=\"%s\" />\n", *entryII, getAsString(*entryII, keyII->first.c_str()).c_str());
				break;
			case TIMEID:
				subUserData += utils::StringFormat("<data name=\"%lld\" type=\"time\" value=\"%llu\" text=\"%s\" />\n",
					*entryII,
					getTime(*entryII, keyII->first.c_str()),
					getAsString(*entryII, keyII->first.c_str()).c_str()
				);
				break;
			case CHARDATAID:
				subUserData += utils::StringFormat("<data name=\"%lld\" type=\"binary\" size=\"%u\" />\n", *entryII, getContentSize(*entryII, keyII->first.c_str()));
				//subUserData += utils::StringFormat("<data name=\"%lld\" type=\"binary\" size=\"%s\" />\n", *entryII, getAsString(*entryII, keyII->first.c_str()).c_str());
				break;
			case INTID:
				subUserData += utils::StringFormat("<data name=\"%lld\" type=\"integer\" value=\"%s\" />\n", *entryII, getAsString(*entryII, keyII->first.c_str()).c_str());
				break;
			case DOUBLEID:
				subUserData += utils::StringFormat("<data name=\"%lld\" type=\"float\" value=\"%s\" />\n", *entryII, getAsString(*entryII, keyII->first.c_str()).c_str());
				break;
			case DATAMESSAGEID:
				msg = getAttachedMessageCopy(*entryII, keyII->first.c_str());
				if (msg)
					subUserData += utils::StringFormat("<data name=\"%lld\" type=\"datamessage\">\n%s</data>", *entryII, msg->toXML().c_str());
				delete(msg);
				break;
			case CONSTCHARINFOID:
				subUserData += utils::StringFormat("<data name=\"%lld\" type=\"textinfo\" size=\"%lld\" />\n", *entryII, getInt(*entryII, keyII->first.c_str()));
				break;
			case CHARDATAINFOID:
				subUserData += utils::StringFormat("<data name=\"%lld\" type=\"binary\" size=\"%lld\" />\n", *entryII, getInt(*entryII, keyII->first.c_str()));
				break;
			case DATAMESSAGEINFOID:
				subUserData += utils::StringFormat("<data name=\"%lld\" type=\"messageinfo\" size=\"%lld\" />\n", *entryII, getInt(*entryII, keyII->first.c_str()));
				break;
			default:
				break;
			}
			entryII++;
		}
		userData += utils::StringFormat("<array name=\"%s\">\n%s</array>\n", keyII->first.c_str(), subUserData.c_str());
		keyII++;
	}

	std::list< std::string >::iterator entryI, entryE;
	std::map< std::string, std::list<std::string > >::iterator keyI = userMaps.begin(), keyE = userMaps.end();
	while (keyI != keyE) {
		subUserData.clear();
		entryI = keyI->second.begin();
		entryE = keyI->second.end();
		while (entryI != entryE) {
			switch (getContentType(entryI->c_str(), keyI->first.c_str())) {
				case CONSTCHARID:
					subUserData += utils::StringFormat("<data name=\"%s\" type=\"text\" value=\"%s\" />\n", entryI->c_str(), getAsString(entryI->c_str(), keyI->first.c_str()).c_str());
					break;
				case TIMEID:
					subUserData += utils::StringFormat("<data name=\"%s\" type=\"time\" value=\"%llu\" text=\"%s\" />\n",
						entryI->c_str(),
						getTime(entryI->c_str(), keyI->first.c_str()),
						getAsString(entryI->c_str(), keyI->first.c_str()).c_str()
						);
					break;
				case CHARDATAID:
					subUserData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%u\" />\n", entryI->c_str(), getContentSize(entryI->c_str(), keyI->first.c_str()));
					//subUserData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%s\" />\n", entryI->c_str(), getAsString(entryI->c_str(), keyI->first.c_str()).c_str());
					break;
				case INTID:
					subUserData += utils::StringFormat("<data name=\"%s\" type=\"integer\" value=\"%s\" />\n", entryI->c_str(), getAsString(entryI->c_str(), keyI->first.c_str()).c_str());
					break;
				case DOUBLEID:
					subUserData += utils::StringFormat("<data name=\"%s\" type=\"float\" value=\"%s\" />\n", entryI->c_str(), getAsString(entryI->c_str(), keyI->first.c_str()).c_str());
					break;
				case DATAMESSAGEID:
					msg = getAttachedMessageCopy(entryI->c_str(), keyI->first.c_str());
					if (msg)
						subUserData += utils::StringFormat("<data name=\"%s\" type=\"datamessage\">\n%s</data>", entryI->c_str(), msg->toXML().c_str());
					delete(msg);
					break;
				case CONSTCHARINFOID:
					subUserData += utils::StringFormat("<data name=\"%s\" type=\"textinfo\" size=\"%lld\" />\n", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str()));
					break;
				case CHARDATAINFOID:
					subUserData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%lld\" />\n", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str()));
					break;
				case DATAMESSAGEINFOID:
					subUserData += utils::StringFormat("<data name=\"%s\" type=\"messageinfo\" size=\"%lld\" />\n", entryI->c_str(), getInt(entryI->c_str(), keyI->first.c_str()));
					break;
				default:
					break;
			}
			entryI++;
		}
		userData += utils::StringFormat("<map name=\"%s\">\n%s</map>\n", keyI->first.c_str(), subUserData.c_str());
		keyI++;
	}

	if (draftSize) {
		return utils::StringFormat("<datamessage draft=\"yes\" size=\"%u\" memid=\"%llu\" time=\"%llu\" timetext=\"%s\" sendtime=\"%llu\" sendtimetext=\"%s\" recvtime=\"%llu\" recvtimetext=\"%s\" origin=\"%u\" destination=\"%u\" ttl=\"%llu\" eoltext=\"%s\" priority=\"%u\" policy=\"%u\" from=\"%u\" to=\"%u\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" serial=\"%llu\" contextchange=\"%s\" userdatacount=\"%u\" userdatasize=\"%u\">\n%s</datamessage>\n",
			draftSize, data->memid,
			data->time, data->time ? PrintTimeString(data->time).c_str() : "",
			data->sendtime, data->sendtime ? PrintTimeString(data->sendtime).c_str() : "",
			data->recvtime, data->recvtime ? PrintTimeString(data->recvtime).c_str() : "",
			data->origin, data->destination, data->ttl, data->ttl ? PrintTimeString(data->time + data->ttl).c_str() : "",
			data->priority, data->policy, data->from, data->to, data->type.toString().c_str(), data->tag, data->status, data->reference, data->serial, data->contextchange.isValid() ? data->contextchange.toString().c_str() : "", draftUserCount, draftUserSize, userData.c_str());
	}
	else {
		return utils::StringFormat("<datamessage size=\"%u\" memid=\"%llu\" time=\"%llu\" timetext=\"%s\" sendtime=\"%llu\" sendtimetext=\"%s\" recvtime=\"%llu\" recvtimetext=\"%s\" origin=\"%u\" destination=\"%u\" ttl=\"%llu\" eoltext=\"%s\" priority=\"%u\" policy=\"%u\" from=\"%u\" to=\"%u\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" serial=\"%llu\" contextchange=\"%s\" userdatacount=\"%u\" userdatasize=\"%u\">\n%s</datamessage>\n",
			data->size, data->memid,
			data->time, data->time ? PrintTimeString(data->time).c_str() : "",
			data->sendtime, data->sendtime ? PrintTimeString(data->sendtime).c_str() : "",
			data->recvtime, data->recvtime ? PrintTimeString(data->recvtime).c_str() : "",
			data->origin, data->destination, data->ttl, data->ttl ? PrintTimeString(data->time + data->ttl).c_str() : "",
			data->priority, data->policy, data->from, data->to, data->type.toString().c_str(), data->tag, data->status, data->reference, data->serial, data->contextchange.isValid() ? data->contextchange.toString().c_str() : "", data->userCount, data->userSize, userData.c_str());
	}
}




// ################# Constructors #################

DataMessage::DataMessage() {
	this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
	memset((char*)this->data, 0, sizeof(DataMessageHeader));
	data->size = sizeof(DataMessageHeader);
	data->cid = DATAMESSAGEID;
	data->time = GetTimeNow();
}

DataMessage::DataMessage(PsyType type, uint32 from) {
	this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
	memset((char*)this->data, 0, sizeof(DataMessageHeader));
	data->size = sizeof(DataMessageHeader);
	data->cid = DATAMESSAGEID;
	data->type = type;
	data->time = GetTimeNow();
	data->from = from;
}

DataMessage::DataMessage(PsyType type, uint32 from, uint32 to, uint64 ttl, uint16 priority) {
	this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
	memset((char*)this->data, 0, sizeof(DataMessageHeader));
	data->size = sizeof(DataMessageHeader);
	data->cid = DATAMESSAGEID;
	data->type = type;
	data->time = GetTimeNow();
	data->from = from;
	data->to = to;
	data->ttl = ttl;
	data->priority = priority;
}

DataMessage::DataMessage(PsyType type, uint32 from, uint32 to, uint32 tag, uint64 time, uint64 ttl, uint16 priority) {
	this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
	memset((char*)this->data, 0, sizeof(DataMessageHeader));
	data->size = sizeof(DataMessageHeader);
	data->cid = DATAMESSAGEID;
	data->type = type;
	data->time = GetTimeNow();
	data->from = from;
	data->to = to;
	data->tag = tag;
	data->time = time;
	data->ttl = ttl;
	data->priority = priority;
}

DataMessage::DataMessage(char* data, bool copy) {
	if (GetObjID(data) != DATAMESSAGEID) {
		this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
		memset((char*)this->data, 0, sizeof(DataMessageHeader));
		this->data->size = sizeof(DataMessageHeader);
		this->data->cid = DATAMESSAGEID;
		return;
	}
	if (!copy)
		this->data = (DataMessageHeader*)data;
	else {
		uint32 size = *(uint32*)data;
		this->data = (DataMessageHeader*) malloc(size);
		memcpy(this->data, data, size);
	}
}

DataMessage::DataMessage(const char* data) {
	if (GetObjID(data) != DATAMESSAGEID) {
		this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
		memset((char*)this->data, 0, sizeof(DataMessageHeader));
		this->data->size = sizeof(DataMessageHeader);
		this->data->cid = DATAMESSAGEID;
		return;
	}
	uint32 size = *(uint32*)data;
	this->data = (DataMessageHeader*) malloc(size);
	memcpy(this->data, data, size);
}

DataMessage::DataMessage(const DataMessage& msg) {
	if (GetObjID(msg.data) != DATAMESSAGEID) {
		this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
		memset((char*)this->data, 0, sizeof(DataMessageHeader));
		this->data->size = sizeof(DataMessageHeader);
		this->data->cid = DATAMESSAGEID;
		return;
	}
	this->data = (DataMessageHeader*)malloc(msg.data->size);
	memcpy(this->data, msg.data, msg.data->size);
	//uint32 size = *(uint32*)msg.data;
	//this->data = (DataMessageHeader*)malloc(size);
	//memcpy(this->data, msg.data, size);
}

DataMessage::DataMessage(const char* data, uint32 maxDraftSize) {
	if (GetObjID(data) != DATAMESSAGEID) {
		this->data = (DataMessageHeader*)malloc(sizeof(DataMessageHeader));
		memset((char*)this->data, 0, sizeof(DataMessageHeader));
		this->data->size = sizeof(DataMessageHeader);
		this->data->cid = DATAMESSAGEID;
		return;
	}
	uint32 size = *(uint32*)data;
	if (size <= maxDraftSize) {
		this->data = (DataMessageHeader*)malloc(size);
		memcpy(this->data, data, size);
	}
	else {
		this->data = (DataMessageHeader*)malloc(maxDraftSize);
		memcpy(this->data, data, sizeof(DataMessageHeader));
		fillInDraftUserDataFrom(data, maxDraftSize);
	}
}

DataMessage::DataMessage(const DataMessage& msg, uint32 maxDraftSize) {
	if (GetObjID(msg.data) != DATAMESSAGEID) {
		this->data = (DataMessageHeader*)malloc(sizeof(DataMessageHeader));
		memset((char*)this->data, 0, sizeof(DataMessageHeader));
		this->data->size = sizeof(DataMessageHeader);
		this->data->cid = DATAMESSAGEID;
		return;
	}
	uint32 size = *(uint32*)msg.data;
	if (size <= maxDraftSize) {
		this->data = (DataMessageHeader*)malloc(size);
		memcpy(this->data, msg.data, size);
	}
	else {
		this->data = (DataMessageHeader*)malloc(maxDraftSize);
		memcpy(this->data, msg.data, sizeof(DataMessageHeader));
		fillInDraftUserDataFrom((char*)msg.data, maxDraftSize);
	}
}

bool DataMessage::fillInDraftUserDataFrom(const char* rawdata, uint32 maxDraftSize) {
	DataMessageHeader* data = (DataMessageHeader*)rawdata;
	if (data->cid != DATAMESSAGEID) return false;

	if (!data->userCount)
		return true;

	this->data->size = sizeof(DataMessageHeader);
	uint32 draftInfoSize = (uint32)((2 * sizeof(DataMessageEntryHeader)) + 3 + sizeof(int64));
	if (this->data->size + (3 * draftInfoSize) > maxDraftSize)
		return false;

	this->data->userCount = 0;
	this->data->userSize = 0;

	int64 size;
	uint32 itemSize;

	size = data->size;
	setRawData("OS", (char*)&size, sizeof(int64), DATAMESSAGEDRAFTID);
	size = data->userSize;
	setRawData("US", (char*)&size, sizeof(int64), DATAMESSAGEDRAFTID);
	size = data->userCount;
	setRawData("UC", (char*)&size, sizeof(int64), DATAMESSAGEDRAFTID);

	std::map< std::string, std::list<std::string> > userMaps;

	const char* key;
	std::string userData;

	// First try to add all the small data info (int, float, time and info about binary, messages)
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			key = src + sizeof(DataMessageEntryHeader);
			itemSize = (uint32)(sizeof(DataMessageEntryHeader) + strlen(key) + 1);
			src += itemSize;
			switch (((DataMessageEntryHeader*)src)->cid) {
			case TIMEID:
				itemSize += sizeof(DataMessageEntryHeader) + sizeof(uint64);
				if (this->data->size + itemSize < maxDraftSize) {
					setTime(key, *(uint64*)(src + sizeof(DataMessageEntryHeader)));
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize;
				}
				break;
			case INTID:
				itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
				if (this->data->size + itemSize < maxDraftSize) {
					setInt(key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize;
				}
				break;
			case DOUBLEID:
				itemSize += sizeof(DataMessageEntryHeader) + sizeof(float64);
				if (this->data->size + itemSize < maxDraftSize) {
					setDouble(key, (double)*(float64*)(src + sizeof(DataMessageEntryHeader)));
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize;
				}
				break;
			case CHARDATAID:
				size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
				itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
				if (this->data->size + itemSize < maxDraftSize) {
					setRawData(key, (char*)&size, sizeof(int64), CHARDATAINFOID);
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
				}
				break;
			case DATAMESSAGEID:
				size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
				itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
				if (this->data->size + itemSize < maxDraftSize) {
					setRawData(key, (char*)&size, sizeof(int64), DATAMESSAGEID);
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
				}
				break;

			case CONSTCHARINFOID:
				size = (*(int64*)(src + sizeof(DataMessageEntryHeader)));
				itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
				if (this->data->size + itemSize < maxDraftSize) {
					setRawData(key, (char*)&size, sizeof(int64), CONSTCHARINFOID);
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
				}
				break;
			case CHARDATAINFOID:
				size = (*(int64*)(src + sizeof(DataMessageEntryHeader)));
				itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
				if (this->data->size + itemSize < maxDraftSize) {
					setRawData(key, (char*)&size, sizeof(int64), CHARDATAINFOID);
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
				}
				break;
			case DATAMESSAGEINFOID:
				size = (*(int64*)(src + sizeof(DataMessageEntryHeader)));
				itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
				if (this->data->size + itemSize < maxDraftSize) {
					setRawData(key, (char*)&size, sizeof(int64), DATAMESSAGEINFOID);
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
				}
				break;
			// Ignore these for now
			case CONSTCHARID:
			default:
				break;
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}

	// Now try to see how many strings we have room for
	src = (char*)data + sizeof(DataMessageHeader);
	srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			key = src + sizeof(DataMessageEntryHeader);
			itemSize = (uint32)(sizeof(DataMessageEntryHeader) + strlen(key) + 1);
			src += itemSize;
			switch (((DataMessageEntryHeader*)src)->cid) {
			case CONSTCHARID:
				size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
				itemSize += sizeof(DataMessageEntryHeader);
				if (this->data->size + itemSize + size < maxDraftSize) {
					// add the whole thing
					setString(key, (src + sizeof(DataMessageEntryHeader)));
				}
				else if (this->data->size + itemSize + sizeof(int64) < maxDraftSize) {
					setRawData(key, (char*)&size, sizeof(int64), CONSTCHARINFOID);
				}
				else {
					this->data->userCount++;
					this->data->userSize += itemSize + (uint32)size;
				}
				break;
			case TIMEID:
			case INTID:
			case DOUBLEID:
			case CHARDATAID:
			case DATAMESSAGEID:
			case CONSTCHARINFOID:
			case CHARDATAINFOID:
			case DATAMESSAGEINFOID:
			default:
				break;
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}

	return true;
}


DataMessage::~DataMessage() {
	//printf("Deleting msg: %u.%u.%u (%p)...\n", data->type[0], data->type[1], data->type[2], this);
	free(data);
	data = NULL;
}

const char* DataMessage::swapMessageData(const char* data) {
	const char* oldData = (const char*)this->data;
	this->data = (DataMessageHeader*)data;
	return oldData;
}


// ################# User #################

int64 DataMessage::getAsInt(const char* key) {
	return utils::Ascii2Int64(getAsString(key).c_str());
}

uint64 DataMessage::getAsTime(const char* key) {
	return utils::Ascii2Uint64(getAsString(key).c_str());
}

float64 DataMessage::getAsFloat(const char* key) {
	return utils::Ascii2Float64(getAsString(key).c_str());
}

int64 DataMessage::getAsInt(int64 i, const char* key) {
	return utils::Ascii2Int64(getAsString(i, key).c_str());
}

uint64 DataMessage::getAsTime(int64 i, const char* key) {
	return utils::Ascii2Uint64(getAsString(i, key).c_str());
}

float64 DataMessage::getAsFloat(int64 i, const char* key) {
	return utils::Ascii2Float64(getAsString(i, key).c_str());
}

int64 DataMessage::getAsInt(const char* idx, const char* key) {
	return utils::Ascii2Int64(getAsString(idx, key).c_str());
}

uint64 DataMessage::getAsTime(const char* idx, const char* key) {
	return utils::Ascii2Uint64(getAsString(idx, key).c_str());
}

float64 DataMessage::getAsFloat(const char* idx, const char* key) {
	return utils::Ascii2Float64(getAsString(idx, key).c_str());
}


bool DataMessage::getAsBool(const char* key) {

	char* src = findEntry(key);
	if (src == NULL)
		return false;

	uint32 cid = ((DataMessageEntryHeader*)src)->cid;
	src += sizeof(DataMessageEntryHeader);

	switch (cid) {
	case CONSTCHARID:
		return ( (stricmp(src, "yes") == 0) || (stricmp(src, "true") == 0) || (stricmp(src, "1") == 0));
	case TIMEID:
		return (*(uint64*)src != 0);
	case CHARDATAID:
		return true;
	case INTID:
		return (*(int64*)src != 0);
	case DOUBLEID:
		return (((int64)(*(float64*)src)) != 0);
	case DATAMESSAGEID:
		return true;
	case CONSTCHARINFOID:
		return false;
	case CHARDATAINFOID:
		return false;
	case DATAMESSAGEINFOID:
		return false;
	default:
		return false;
	}
}

std::string DataMessage::getAsString(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) {
		if (stricmp(key, "size") == 0)
			return utils::StringFormat("%u", data->size);
		else if (stricmp(key, "cid") == 0)
			return utils::StringFormat("%llu", data->cid);
		else if (stricmp(key, "memid") == 0)
			return utils::StringFormat("%llu", data->memid);
		else if (stricmp(key, "time") == 0)
			return utils::StringFormat("%llu", data->time);
		else if (stricmp(key, "sendtime") == 0)
			return utils::StringFormat("%llu", data->sendtime);
		else if (stricmp(key, "recvtime") == 0)
			return utils::StringFormat("%llu", data->recvtime);
		else if (stricmp(key, "timetext") == 0)
			return data->time ? PrintTimeString(data->time) : "";
		else if (stricmp(key, "sendtimetext") == 0)
			return data->sendtime ? PrintTimeString(data->sendtime) : "";
		else if (stricmp(key, "recvtimetext") == 0)
			return data->recvtime ? PrintTimeString(data->recvtime) : "";
		else if (stricmp(key, "origin") == 0)
			return utils::StringFormat("%u", data->origin);
		else if (stricmp(key, "destination") == 0)
			return utils::StringFormat("%u", data->destination);
		else if (stricmp(key, "ttl") == 0)
			return utils::StringFormat("%llu", data->ttl);
		else if (stricmp(key, "eol") == 0)
			return data->ttl ? utils::StringFormat("%llu", data->time + data->ttl) : "0";
		else if (stricmp(key, "eoltext") == 0)
			return data->ttl ? PrintTimeString(data->time + data->ttl) : "";
		else if (stricmp(key, "priority") == 0)
			return utils::StringFormat("%u", data->priority);
		else if (stricmp(key, "policy") == 0)
			return utils::StringFormat("%u", data->policy);
		else if (stricmp(key, "from") == 0)
			return utils::StringFormat("%u", data->from);
		else if (stricmp(key, "to") == 0)
			return utils::StringFormat("%u", data->to);
		else if (stricmp(key, "type") == 0)
			return data->type.toString();
		else if (stricmp(key, "tag") == 0)
			return utils::StringFormat("%u", data->tag);
		else if (stricmp(key, "status") == 0)
			return utils::StringFormat("%u", data->status);
		else if (stricmp(key, "reference") == 0)
			return utils::StringFormat("%llu", data->reference);
		else if (stricmp(key, "serial") == 0)
			return utils::StringFormat("%llu", data->serial);
		else if (stricmp(key, "contextchange") == 0)
			return data->contextchange.isValid() ? data->contextchange.toString() : "";
		else if (stricmp(key, "userSize") == 0)
			return utils::StringFormat("%u", data->userSize);
		else if (stricmp(key, "userCount") == 0)
			return utils::StringFormat("%u", data->userCount);
		else
			return "";
	}

	switch (((DataMessageEntryHeader*)src)->cid) {
		case CONSTCHARID:
			return src + sizeof(DataMessageEntryHeader);
		case TIMEID:
			return PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader)));
		case CHARDATAID:
			return utils::StringFormat("BinaryData [%ub]", ((DataMessageEntryHeader*)src)->size);
		case INTID:
			return utils::StringFormat("%lld", *(int64*)(src + sizeof(DataMessageEntryHeader)));
		case DOUBLEID:
			return utils::StringFormat("%f", *(float64*)(src + sizeof(DataMessageEntryHeader)));
		case DATAMESSAGEID:
			return utils::StringFormat("DataMessage [%ub]", ((DataMessageEntryHeader*)src)->size);
		case CONSTCHARINFOID:
			return utils::StringFormat("(%lld)", *(int64*)(src + sizeof(DataMessageEntryHeader)));
		case CHARDATAINFOID:
			return utils::StringFormat("(%lld)", *(int64*)(src + sizeof(DataMessageEntryHeader)));
		case DATAMESSAGEINFOID:
			return utils::StringFormat("(%lld)", *(int64*)(src + sizeof(DataMessageEntryHeader)));
		default:
			return "";
	}
}

const char* DataMessage::getString(const char* key) {
	bool success = false;
	return getString(key, success);
}

const char* DataMessage::getString(const char* key, uint32 &size) {
	bool success = false;
	return getString(key, size, success);
}

uint64 DataMessage::getTime(const char* key) {
	bool success = false;
	return getTime(key, success);
}

bool DataMessage::getInt(const char* key, int64& value) {
	bool success = false;
	value = getInt(key, success);
	return success;
}

bool DataMessage::getDouble(const char* key, double& value) {
	bool success = false;
	value = getDouble(key, success);
	return success;
}

bool DataMessage::getFloat(const char* key, float64& value) {
	bool success = false;
	value = getFloat(key, success);
	return success;
}

const char* DataMessage::getData(const char* key, uint32& size) {
	bool success = false;
	return getData(key, size, success);
}

char* DataMessage::getDataCopy(const char* key, uint32& size) {
	bool success = false;
	return getDataCopy(key, size, success);
}

DataMessage* DataMessage::getAttachedMessageCopy(const char* key) {
	bool success = false;
	return getAttachedMessageCopy(key, success);
}





// ################# User with success flag #################

const char* DataMessage::getString(const char* key, bool& success) {
	success = false;
	char* src = findEntry(key);
	if (src == NULL)
		return NULL;

	if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
		success = true;
		return src+sizeof(DataMessageEntryHeader);
	}

	return NULL;
}

const char* DataMessage::getString(const char* key, uint32 &size, bool& success) {
	size = 0;
	success = false;
	char* src = findEntry(key);
	if (src == NULL)
		return NULL;

	if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
		success = true;
		size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader) - 1;
		return src+sizeof(DataMessageEntryHeader);
	}

	return NULL;
}

uint32 DataMessage::getContentType(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) return 0;
	return ((DataMessageEntryHeader*)src)->cid;
}

uint32 DataMessage::getContentSize(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) return 0;
	return ((DataMessageEntryHeader*)src)->size;
}


uint64 DataMessage::getTime(const char* key, bool& success) {
	success = false;
	char* src = findEntry(key);
	if (src == NULL) return 0;

	if (((DataMessageEntryHeader*)src)->cid == TIMEID) {
		success = true;
		return *(uint64*)(src+sizeof(DataMessageEntryHeader));
	}

	return 0;
}

int64 DataMessage::getInt(const char* key, bool& success) {
	success = false;
	char* src = findEntry(key);
	if (src == NULL) return 0;

	if (((DataMessageEntryHeader*)src)->cid == INTID) {
		success = true;
		return *(int64*)(src+sizeof(DataMessageEntryHeader));
	}
	return 0;
}

int64 DataMessage::getInt(const char* key) {
	bool success = false;
	return getInt(key, success);
}

double DataMessage::getDouble(const char* key, bool& success) {
	success = false;
	char* src = findEntry(key);
	if (src == NULL) return false;

	if (((DataMessageEntryHeader*)src)->cid == DOUBLEID) {
		success = true;
		return *(float64*)(src + sizeof(DataMessageEntryHeader));
	}
	return false;
}

float64 DataMessage::getFloat(const char* key, bool& success) {
	success = false;
	char* src = findEntry(key);
	if (src == NULL) return false;

	if (((DataMessageEntryHeader*)src)->cid == DOUBLEID) {
		success = true;
		return *(float64*)(src + sizeof(DataMessageEntryHeader));
	}
	return false;
}

double DataMessage::getDouble(const char* key) {
	bool success = false;
	return getDouble(key, success);
}

double DataMessage::getFloat(const char* key) {
	bool success = false;
	return getFloat(key, success);
}

const char* DataMessage::getData(const char* key, uint32& size, bool& success) {
	success = false;
	char* src = findEntry(key);
	if (src == NULL) return NULL;

	if (((DataMessageEntryHeader*)src)->cid == CHARDATAID) {
		success = true;
		size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
		return src+sizeof(DataMessageEntryHeader);
	}

	return NULL;
}

char* DataMessage::getDataCopy(const char* key, uint32& size, bool& success) {
	success = false;
	char* src = findEntry(key);
	if (src == NULL) return NULL;

	if (((DataMessageEntryHeader*)src)->cid == CHARDATAID) {
		success = true;
		size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
		char* data = new char[size];
		memcpy(data, src+sizeof(DataMessageEntryHeader), size);
		return data;
	}

	return NULL;
}

DataMessage* DataMessage::getAttachedMessageCopy(const char* key, bool& success) {
	success = false;
	char* src = findEntry(key);
	if (src == NULL) return NULL;

	if (((DataMessageEntryHeader*)src)->cid == DATAMESSAGEID) {
		success = true;
		return new DataMessage(src+sizeof(DataMessageEntryHeader), true);
	}
	return NULL;
}













bool DataMessage::setString(const char* key, const char* value) {
	if (!key || !value)
		return false;
	return setRawData(key, value, (uint32)strlen(value)+1, CONSTCHARID);
}

bool DataMessage::setTime(const char* key, uint64 value) {
	return setRawData(key, (char*)&value, sizeof(uint64), TIMEID);
}

bool DataMessage::setInt(const char* key, int64 value) {
	return setRawData(key, (char*)&value, sizeof(int64), INTID);
}

bool DataMessage::setDouble(const char* key, double value) {
	float64 val = value;
	return setRawData(key, (char*)&val, sizeof(float64), DOUBLEID);
}

bool DataMessage::setFloat(const char* key, float64 value) {
	return setRawData(key, (char*)&value, sizeof(float64), DOUBLEID);
}

bool DataMessage::setData(const char* key, const char* value, uint32 size) {
	return setRawData(key, value, size, CHARDATAID);
}

bool DataMessage::setAttachedMessage(const char* key, DataMessage* msg) {
	if (!msg->isValid())
		return false;
	return setRawData(key, (char*)msg->data, msg->data->size, DATAMESSAGEID);
}

bool DataMessage::setRawData(const char* key, const char* value, uint32 size, uint32 datatype) {
	char* src = findEntry(key);
	
	uint32 spaceReq = sizeof(DataMessageEntryHeader) + size;
	uint32 fullSpaceReq = 2 * sizeof(DataMessageEntryHeader) + (uint32)strlen(key) + 1 + size;

	if (src != NULL) { // overwrite?
		if (((DataMessageEntryHeader*)src)->size >= spaceReq) {
			((DataMessageEntryHeader*)src)->cid = datatype;
			memcpy(src+sizeof(DataMessageEntryHeader), value, size);
			//data->userCount++;
			//data->userSize += fullSpaceReq;
			return true;
		}
		else {
			removeEntry(key);
			// and act as if not found, ie. continue
		}
	}
	
	src = findSpace(spaceReq);
	if (src == NULL) {
		// Space not found, create a new one
	//	if (!ownsData) return false;

		uint32 oldSize = ((DataMessageHeader*)data)->size;
		data = (DataMessageHeader*)realloc(data, oldSize + fullSpaceReq);
		data->size = oldSize + fullSpaceReq;

		src = (char*)data + oldSize;
		((DataMessageEntryHeader*)src)->size = fullSpaceReq;
	}

	((DataMessageEntryHeader*)src)->cid = CONSTCHARID;
	utils::strcpyavail(src+sizeof(DataMessageEntryHeader), key, (uint32)strlen(key)+1, true);

	src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
	((DataMessageEntryHeader*)src)->cid = datatype;
	((DataMessageEntryHeader*)src)->size = sizeof(DataMessageEntryHeader) + size;
	memcpy(src+sizeof(DataMessageEntryHeader), value, size);
	data->userCount++;
	data->userSize += fullSpaceReq;

	return true;
}







// Arrays

bool DataMessage::isArrayContent(const char* key) {
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return false;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false) &&
				utils::TextEndsWith(src + sizeof(DataMessageEntryHeader), "|-_", false))
				return true;
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return false;
}

bool DataMessage::isMapContent(const char* key) {
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return false;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false) && 
				utils::TextEndsWith(src + sizeof(DataMessageEntryHeader), "]-_", false) )
				return true;
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return false;
}

DataMessage::KeyType DataMessage::getKeyType(const char* key) {
	uint32 size;
	char* arrayKeyStart = utils::StringFormat(size, "%s_-|", key);
	char* mapKeyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return NONE;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (stricmp(key, src + sizeof(DataMessageEntryHeader)) == 0)
				return SINGLE;
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), arrayKeyStart, false) &&
				utils::TextEndsWith(src + sizeof(DataMessageEntryHeader), "|-_", false))
				return ARRAY;
			else if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), mapKeyStart, false) &&
				utils::TextEndsWith(src + sizeof(DataMessageEntryHeader), "]-_", false))
				return MAP;
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] arrayKeyStart;
	delete[] mapKeyStart;
	return NONE;
}




bool DataMessage::hasKey(const char* key) {
	return (findEntry(key) != NULL);
}

bool DataMessage::hasString(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) return 0;
	return (((DataMessageEntryHeader*)src)->cid == CONSTCHARID);
}

bool DataMessage::hasInteger(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) return 0;
	return (((DataMessageEntryHeader*)src)->cid == INTID);
}

bool DataMessage::hasFloat(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) return 0;
	return (((DataMessageEntryHeader*)src)->cid == DOUBLEID);
}

bool DataMessage::hasTime(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) return 0;
	return (((DataMessageEntryHeader*)src)->cid == TIMEID);
}

bool DataMessage::hasData(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) return 0;
	return (((DataMessageEntryHeader*)src)->cid == CHARDATAID);
}

bool DataMessage::hasMessage(const char* key) {
	char* src = findEntry(key);
	if (src == NULL) return 0;
	return (((DataMessageEntryHeader*)src)->cid == DATAMESSAGEID);
}


bool DataMessage::isSingleValue(const char* key) {
	return (findEntry(key) != NULL);
}

uint32 DataMessage::getContentType(int64 i, const char* key) {
	return getContentType(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
}

uint32 DataMessage::getContentSize(int64 i, const char* key) {
	return getContentSize(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
}

uint64 DataMessage::getTime(int64 i, const char* key) {
	return getTime(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
}

std::string DataMessage::getAsString(int64 i, const char* key) {
	return getAsString(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
}

const char* DataMessage::getString(int64 i, const char* key) {
	return getString(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
}

const char* DataMessage::getString(int64 i, const char* key, uint32 &size) {
	return getString(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
}

bool DataMessage::getInt(int64 i, const char* key, int64& value) {
	return getInt(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
}

bool DataMessage::getDouble(int64 i, const char* key, double& value) {
	return getDouble(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
}

bool DataMessage::getFloat(int64 i, const char* key, float64& value) {
	return getFloat(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
}

int64 DataMessage::getInt(int64 i, const char* key, bool& success) {
	return getInt(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), success);
}

double DataMessage::getDouble(int64 i, const char* key, bool& success) {
	return getDouble(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), success);
}

float64 DataMessage::getFloat(int64 i, const char* key, bool& success) {
	return getFloat(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), success);
}

int64 DataMessage::getInt(int64 i, const char* key) {
	bool success;
	return getInt(i, key, success);
}

double DataMessage::getDouble(int64 i, const char* key) {
	bool success;
	return getDouble(i, key, success);
}

float64 DataMessage::getFloat(int64 i, const char* key) {
	bool success;
	return getFloat(i, key, success);
}

int64 DataMessage::getInt(const char* idx, const char* key) {
	bool success;
	return getInt(idx, key, success);
}

double DataMessage::getDouble(const char* idx, const char* key) {
	bool success;
	return getDouble(idx, key, success);
}

float64 DataMessage::getFloat(const char* idx, const char* key) {
	bool success;
	return getFloat(idx, key, success);
}


const char* DataMessage::getData(int64 i, const char* key, uint32& size) {
	return getData(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), size);
}

char* DataMessage::getDataCopy(int64 i, const char* key, uint32& size) {
	return getDataCopy(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), size);
}

DataMessage* DataMessage::getAttachedMessageCopy(int64 i, const char* key) {
	return getAttachedMessageCopy(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
}


bool DataMessage::setTime(int64 i, const char* key, uint64 value) {
	return setTime(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
}

bool DataMessage::setString(int64 i, const char* key, const char* value) {
	return setString(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
}

bool DataMessage::setInt(int64 i, const char* key, int64 value) {
	return setInt(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
}

bool DataMessage::setDouble(int64 i, const char* key, double value) {
	return setDouble(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
}

bool DataMessage::setFloat(int64 i, const char* key, float64 value) {
	return setFloat(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
}

bool DataMessage::setData(int64 i, const char* key, const char* value, uint32 size) {
	return setData(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value, size);
}

bool DataMessage::setAttachedMessage(int64 i, const char* key, DataMessage* msg) {
	return setAttachedMessage(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), msg);
}


// Maps
uint32 DataMessage::getContentType(const char* idx, const char* key) {
	return getContentType(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
}

uint32 DataMessage::getContentSize(const char* idx, const char* key) {
	return getContentSize(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
}

uint64 DataMessage::getTime(const char* idx, const char* key) {
	return getTime(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
}

std::string DataMessage::getAsString(const char* idx, const char* key) {
	return getAsString(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
}

const char* DataMessage::getString(const char* idx, const char* key) {
	return getString(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
}

const char* DataMessage::getString(const char* idx, const char* key, uint32 &size) {
	return getString(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
}

bool DataMessage::getInt(const char* idx, const char* key, int64& value) {
	return getInt(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
}

bool DataMessage::getDouble(const char* idx, const char* key, double& value) {
	return getDouble(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
}

bool DataMessage::getFloat(const char* idx, const char* key, float64& value) {
	return getFloat(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
}

int64 DataMessage::getInt(const char* idx, const char* key, bool& success) {
	return getInt(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), success);
}

double DataMessage::getDouble(const char* idx, const char* key, bool& success) {
	return getDouble(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), success);
}

float64 DataMessage::getFloat(const char* idx, const char* key, bool& success) {
	return getFloat(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), success);
}

const char* DataMessage::getData(const char* idx, const char* key, uint32& size) {
	return getData(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), size);
}

char* DataMessage::getDataCopy(const char* idx, const char* key, uint32& size) {
	return getDataCopy(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), size);
}

DataMessage* DataMessage::getAttachedMessageCopy(const char* idx, const char* key) {
	return getAttachedMessageCopy(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
}


bool DataMessage::setTime(const char* idx, const char* key, uint64 value) {
	return setTime(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
}

bool DataMessage::setString(const char* idx, const char* key, const char* value) {
	return setString(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
}

bool DataMessage::setInt(const char* idx, const char* key, int64 value) {
	return setInt(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
}

bool DataMessage::setDouble(const char* idx, const char* key, double value) {
	return setDouble(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
}

bool DataMessage::setFloat(const char* idx, const char* key, float64 value) {
	return setFloat(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
}

bool DataMessage::setData(const char* idx, const char* key, const char* value, uint32 size) {
	return setData(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value, size);
}

bool DataMessage::setAttachedMessage(const char* idx, const char* key, DataMessage* msg) {
	return setAttachedMessage(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), msg);
}








std::map<int64, uint64> DataMessage::getTimeArray(const char* key) {
	std::map<int64, uint64> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == TIMEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
					i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
					map[i] = *(uint64*)(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<int64, int64> DataMessage::getAsIntArray(const char* key) {
	std::map<int64, int64> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
				entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;

				//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
				i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
				switch (((DataMessageEntryHeader*)entry)->cid) {
				case TIMEID:
					map[i] = (int64)(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case CONSTCHARID:
					map[i] = utils::Ascii2Int64(entry + sizeof(DataMessageEntryHeader));
					break;
				case CHARDATAID:
					map[i] = (int64)((DataMessageEntryHeader*)entry)->size;
					break;
				case INTID:
					map[i] = *(int64*)(entry + sizeof(DataMessageEntryHeader));
					break;
				case DOUBLEID:
					map[i] = (int64)(*(float64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEID:
					map[i] = (int64)((DataMessageEntryHeader*)entry)->size;
					break;
				default:
					break;
				}
			}

		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<int64, float64> DataMessage::getAsFloatArray(const char* key) {
	std::map<int64, float64> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
				entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;

				//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
				i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
				switch (((DataMessageEntryHeader*)entry)->cid) {
				case TIMEID:
					map[i] = (float64)(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case CONSTCHARID:
					map[i] = utils::Ascii2Float64(entry + sizeof(DataMessageEntryHeader));
					break;
				case CHARDATAID:
					map[i] = (float64)((DataMessageEntryHeader*)entry)->size;
					break;
				case INTID:
					map[i] = (float64)(*(int64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case DOUBLEID:
					map[i] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
					break;
				case DATAMESSAGEID:
					map[i] = (float64)((DataMessageEntryHeader*)entry)->size;
					break;
				default:
					break;
				}
			}

		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<int64, std::string> DataMessage::getAsStringArray(const char* key) {
	std::map<int64, std::string> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
				entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;

				//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
				i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
				switch (((DataMessageEntryHeader*)entry)->cid) {
				case TIMEID:
					map[i] = PrintTimeString(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case CONSTCHARID:
					map[i] = entry + sizeof(DataMessageEntryHeader);
					break;
				case CHARDATAID:
					map[i] = utils::StringFormat("BinaryData [%ub]", ((DataMessageEntryHeader*)entry)->size);
					break;
				case INTID:
					map[i] = utils::StringFormat("%lld", *(int64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case DOUBLEID:
					map[i] = utils::StringFormat("%f", *(float64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEID:
					map[i] = utils::StringFormat("DataMessage [%ub]", ((DataMessageEntryHeader*)entry)->size);
					break;
				default:
					break;
				}
			}

		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<int64, std::string> DataMessage::getStringArray(const char* key) {
	std::map<int64, std::string> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == CONSTCHARID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
					i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
					map[i] = entry + sizeof(DataMessageEntryHeader);
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<int64, int64> DataMessage::getIntArray(const char* key) {
	std::map<int64, int64> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == INTID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == TIMEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
					i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
					map[i] = *(int64*)(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<int64, double> DataMessage::getDoubleArray(const char* key) {
	std::map<int64, double> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == DOUBLEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
					i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
					map[i] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<int64, float64> DataMessage::getFloatArray(const char* key) {
	std::map<int64, float64> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == DOUBLEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
					i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
					map[i] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<int64, DataMessage*> DataMessage::getAttachedMessageArray(const char* key) {
	std::map<int64, DataMessage*> map;
	int64 i;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-|", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == INTID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == DATAMESSAGEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					//i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
					i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
					map[i] = new DataMessage(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

bool DataMessage::setTimeArray(const char* key, std::map<int64, uint64>& map) {
	std::map<int64, uint64>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setTime(i->first, key, i->second))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setStringArray(const char* key, std::map<int64, std::string>& map) {
	std::map<int64, std::string>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setString(i->first, key, i->second.c_str()))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setIntArray(const char* key, std::map<int64, int64>& map) {
	std::map<int64, int64>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setInt(i->first, key, i->second))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setDoubleArray(const char* key, std::map<int64, double>& map) {
	std::map<int64, double>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setDouble(i->first, key, i->second))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setFloatArray(const char* key, std::map<int64, float64>& map) {
	std::map<int64, float64>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setFloat(i->first, key, i->second))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setAttachedMessageArray(const char* key, std::map<int64, DataMessage*>& map) {
	std::map<int64, DataMessage*>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setAttachedMessage(i->first, key, i->second))
			return false;
		i++;
	}
	return true;
}





std::map<std::string, uint64> DataMessage::getTimeMap(const char* key) {
	std::map<std::string, uint64> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == TIMEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
					map[str] = *(uint64*)(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<std::string, int64> DataMessage::getAsIntMap(const char* key) {
	std::map<std::string, int64> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
				entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
				str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str();
				switch (((DataMessageEntryHeader*)entry)->cid) {
				case TIMEID:
					map[str] = (int64)(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case CONSTCHARID:
					map[str] = utils::Ascii2Int64(entry + sizeof(DataMessageEntryHeader));
					break;
				case CHARDATAID:
					map[str] = (int64)((DataMessageEntryHeader*)entry)->size;
					break;
				case INTID:
					map[str] = *(int64*)(entry + sizeof(DataMessageEntryHeader));
					break;
				case DOUBLEID:
					map[str] = (int64)(*(float64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEID:
					map[str] = (int64)((DataMessageEntryHeader*)entry)->size;
					break;
				default:
					break;
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<std::string, float64> DataMessage::getAsFloatMap(const char* key) {
	std::map<std::string, float64> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
				entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
				str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str();
				switch (((DataMessageEntryHeader*)entry)->cid) {
				case TIMEID:
					map[str] = (float64)(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case CONSTCHARID:
					map[str] = utils::Ascii2Float64(entry + sizeof(DataMessageEntryHeader));
					break;
				case CHARDATAID:
					map[str] = (float64)((DataMessageEntryHeader*)entry)->size;
					break;
				case INTID:
					map[str] = (float64)(*(int64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case DOUBLEID:
					map[str] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
					break;
				case DATAMESSAGEID:
					map[str] = (float64)((DataMessageEntryHeader*)entry)->size;
					break;
				default:
					break;
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<std::string, std::string> DataMessage::getAsStringMap(const char* key) {
	std::map<std::string, std::string> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
				entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
				str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str();
				switch (((DataMessageEntryHeader*)entry)->cid) {
				case TIMEID:
					map[str] = PrintTimeString(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case CONSTCHARID:
					map[str] = entry + sizeof(DataMessageEntryHeader);
					break;
				case CHARDATAID:
					map[str] = utils::StringFormat("BinaryData [%ub]", ((DataMessageEntryHeader*)entry)->size);
					break;
				case INTID:
					map[str] = utils::StringFormat("%lld", *(int64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case DOUBLEID:
					map[str] = utils::StringFormat("%f", *(float64*)(entry + sizeof(DataMessageEntryHeader)));
					break;
				case DATAMESSAGEID:
					map[str] = utils::StringFormat("DataMessage [%ub]", ((DataMessageEntryHeader*)entry)->size);
					break;
				default:
					break;
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<std::string, std::string> DataMessage::getStringMap(const char* key) {
	std::map<std::string, std::string> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == CONSTCHARID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
					map[str] = entry + sizeof(DataMessageEntryHeader);
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<std::string, int64> DataMessage::getIntMap(const char* key) {
	std::map<std::string, int64> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == INTID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
					map[str] = *(int64*)(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<std::string, double> DataMessage::getDoubleMap(const char* key) {
	std::map<std::string, double> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == DOUBLEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
					map[str] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<std::string, float64> DataMessage::getFloatMap(const char* key) {
	std::map<std::string, float64> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == DOUBLEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
					map[str] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

std::map<std::string, DataMessage*> DataMessage::getAttachedMessageMap(const char* key) {
	std::map<std::string, DataMessage*> map;
	std::string str;
	uint32 size;
	char* keyStart = utils::StringFormat(size, "%s_-[", key);
	if (data->cid != DATAMESSAGEID) return map;
	char* entry;
	char* src = (char*)data + sizeof(DataMessageHeader);
	char* srcEnd = (char*)data + data->size;
	while (src < srcEnd) {
		if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
			entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
			if (((DataMessageEntryHeader*)entry)->cid == DATAMESSAGEID) {
				if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
					str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
					map[str] = new DataMessage(entry + sizeof(DataMessageEntryHeader));
				}
			}
		}
		src += ((DataMessageEntryHeader*)src)->size;
	}
	delete[] keyStart;
	return map;
}

bool DataMessage::setTimeMap(const char* key, std::map<std::string, uint64>& map) {
	std::map<std::string, uint64>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setTime(i->first.c_str(), key, i->second))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setStringMap(const char* key, std::map<std::string, std::string>& map) {
	std::map<std::string, std::string>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setString(i->first.c_str(), key, i->second.c_str()))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setIntMap(const char* key, std::map<std::string, int64>& map) {
	std::map<std::string, int64>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setInt(i->first.c_str(), key, i->second))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setDoubleMap(const char* key, std::map<std::string, double>& map) {
	std::map<std::string, double>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setDouble(i->first.c_str(), key, i->second))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setFloatMap(const char* key, std::map<std::string, float64>& map) {
	std::map<std::string, float64>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setFloat(i->first.c_str(), key, i->second))
			return false;
		i++;
	}
	return true;
}

bool DataMessage::setAttachedMessageMap(const char* key, std::map<std::string, DataMessage*>& map) {
	std::map<std::string, DataMessage*>::iterator i = map.begin(), e = map.end();
	while (i != e) {
		if (!setAttachedMessage(i->first.c_str(), key, i->second))
			return false;
		i++;
	}
	return true;
}




} // namespace cmlabs
