

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  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 "DataMapsMemory.h"

namespace cmlabs {

DataMapsMemory::DataMapsMemory(MasterMemory* master) {
	mutex = NULL;
	this->master = master;
	header = NULL;
	memorySize = 0;
	port = 0;
	serial = 0;
	typeMapHeader = NULL;
	contextMapHeader = NULL;
	tagMapHeader = NULL;
	crankMapHeader = NULL;
//	componentMapHeader = NULL;
	requestMapHeader = NULL;
}

DataMapsMemory::~DataMapsMemory() {
	if (mutex)
		mutex->enter(5000, __FUNCTION__);

	typeMapHeader = NULL;
	contextMapHeader = NULL;
	tagMapHeader = NULL;
	crankMapHeader = NULL;
//	componentMapHeader = NULL;
	requestMapHeader = NULL;

	if (memorySize)
		utils::CloseSharedMemorySegment((char*) header, memorySize);
	header = NULL;
	if (mutex)
		mutex->leave();
	delete(mutex);
	mutex = NULL;
}

bool DataMapsMemory::getMemoryUsage(uint64& alloc, uint64& usage) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL

	alloc = memorySize;
	usage =
		typeMapHeader->count * sizeof(TypeMapEntry) +
		contextMapHeader->count * sizeof(ContextMapEntry) +
		tagMapHeader->count * sizeof(TagMapEntry) +
		crankMapHeader->count * sizeof(CrankMapEntry) +
		requestMapHeader->count * sizeof(RequestMapEntry);

	mutex->leave();
	return true;
}


bool DataMapsMemory::create(uint32 typesMaxCount, uint32 contextsMaxCount, uint32 tagsMaxCount, uint32 cranksMaxCount, uint32 requestsMaxCount) {
	serial = master->incrementDataMapsShmemSerial();
	return resize(master->port, serial, typesMaxCount, contextsMaxCount, tagsMaxCount, cranksMaxCount, requestsMaxCount);
}

bool DataMapsMemory::open() {
	serial = master->getDataMapsShmemSerial();
	uint64 size = master->getDataMapsShmemSize();
	this->port = master->port;

	bool createdMutex = false;
	if (!mutex) {
		// LogPrint(0,LOG_MEMORY,0," --------- Opening new DataMapsMemory section serial %u --------", serial);
		mutex = new utils::Mutex(utils::StringFormat("PsycloneDataMapsMemoryMutex_%u", port).c_str());
		createdMutex = true;
		if (!mutex->enter(5000, __FUNCTION__))
			return false;
	}
	else
		LogPrint(0,LOG_MEMORY,0," --------- Reopening DataMapsMemory section serial %u --------", serial);
	
	DataMapsMemoryStruct* newHeader = (DataMapsMemoryStruct*) utils::OpenSharedMemorySegment(utils::StringFormat("PsycloneDataMapsMemory_%u_%u", port, serial).c_str(), size);
	if (!newHeader) {
		if (createdMutex)
			mutex->leave();
		return false;
	}
	if (newHeader->cid != DATAMAPSMEMORYID) {
		utils::CloseSharedMemorySegment((char*)newHeader, size);
		if (createdMutex)
			mutex->leave();
		return false;
	}

	typeMapHeader = (GenericMapHeader*)(((char*)newHeader) + sizeof(DataMapsMemoryStruct));
	contextMapHeader = (GenericMapHeader*)(((char*)typeMapHeader) + typeMapHeader->size);
	tagMapHeader = (GenericMapHeader*)(((char*)contextMapHeader) + contextMapHeader->size);
	crankMapHeader = (GenericMapHeader*)(((char*)tagMapHeader) + tagMapHeader->size);
	requestMapHeader = (GenericMapHeader*)(((char*)crankMapHeader) + crankMapHeader->size);

	memorySize = size;
	if (header) 
		utils::CloseSharedMemorySegment((char*)header, header->size);
	header = newHeader;
	if (createdMutex)
		mutex->leave();
	// else leave mutex locked as we are calling from within the object
	return true;
}


bool DataMapsMemory::maintenance() {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL

	double factor = 2.0;

	uint32 newTypeCount = header->typesMaxCount;
	uint32 newContextCount = header->contextsMaxCount;
	uint32 newTagCount = header->tagsMaxCount;
	uint32 newCrankCount = header->cranksMaxCount;
//	uint32 newComponentCount = 0;
	uint32 newRequestCount = header->requestsMaxCount;

	bool shouldResize = false;
	if (header->typesMaxCount - typeMapHeader->count < (header->typesMaxCount * 0.1)) {
		newTypeCount = (uint32)(header->typesMaxCount * factor);
		shouldResize = true;
	}
	if (header->contextsMaxCount - contextMapHeader->count < (header->contextsMaxCount * 0.1)) {
		newContextCount = (uint32)(header->contextsMaxCount * factor);
		shouldResize = true;
	}
	if (header->tagsMaxCount - tagMapHeader->count < (header->tagsMaxCount * 0.1)) {
		newTagCount = (uint32)(header->tagsMaxCount * factor);
		shouldResize = true;
	}
	if (header->cranksMaxCount - crankMapHeader->count < (header->cranksMaxCount * 0.1)) {
		newCrankCount = (uint32)(header->cranksMaxCount * factor);
		shouldResize = true;
	}
//	if (header->componentsMaxCount - componentMapHeader->count < (header->componentsMaxCount * 0.1))
//		newComponentCount = (uint32)(header->componentsMaxCount * factor);
	if (header->requestsMaxCount - requestMapHeader->count < (header->requestsMaxCount * 0.1)) {
		newRequestCount = (uint32)(header->requestsMaxCount * factor);
		shouldResize = true;
	}
	
	if (shouldResize)
		resize(master->port, serial = master->incrementDataMapsShmemSerial(), newTypeCount, newContextCount, newTagCount, newCrankCount, newRequestCount);

	mutex->leave();
	return true;
}


bool DataMapsMemory::resize(uint16 port, uint32 serial, uint32 typesMaxCount, uint32 contextsMaxCount, uint32 tagsMaxCount, uint32 cranksMaxCount, uint32 requestsMaxCount) {
	// Create and lock new mutex
	if (!mutex)
		mutex = new utils::Mutex(utils::StringFormat("PsycloneDataMapsMemoryMutex_%u", port).c_str(), true);
	if (!mutex->enter(5000, __FUNCTION__)) {
		LogPrint(0,LOG_MEMORY,0,"DataMaps Memory Mutex could not be created and locked...");
		return false;
	}

	uint32 typesBitFieldSize = utils::Calc32BitFieldSize(typesMaxCount);
	uint32 typesSize = sizeof(GenericMapHeader) + typesBitFieldSize + typesMaxCount*sizeof(TypeMapEntry);
	uint32 contextsBitFieldSize = utils::Calc32BitFieldSize(contextsMaxCount);
	uint32 contextsSize = sizeof(GenericMapHeader) + contextsBitFieldSize + contextsMaxCount*sizeof(ContextMapEntry);
	uint32 tagsBitFieldSize = utils::Calc32BitFieldSize(tagsMaxCount);
	uint32 tagsSize = sizeof(GenericMapHeader) + tagsBitFieldSize + tagsMaxCount*sizeof(TagMapEntry);
	uint32 cranksBitFieldSize = utils::Calc32BitFieldSize(cranksMaxCount);
	uint32 cranksSize = sizeof(GenericMapHeader) + cranksBitFieldSize + cranksMaxCount*sizeof(CrankMapEntry);
//	uint32 componentsBitFieldSize = utils::Calc32BitFieldSize(componentsMaxCount);
//	uint32 componentsSize = sizeof(GenericMapHeader) + componentsBitFieldSize + componentsMaxCount*sizeof(ComponentMapEntry);
	uint32 requestsBitFieldSize = utils::Calc32BitFieldSize(requestsMaxCount);
	uint32 requestsSize = sizeof(GenericMapHeader) + requestsBitFieldSize + requestsMaxCount*sizeof(RequestMapEntry);

	uint32 newMemorySize = typesSize + contextsSize + tagsSize + cranksSize + requestsSize + sizeof(DataMapsMemoryStruct);

	if (newMemorySize > 100000000) {
		LogPrint(0,LOG_MEMORY,0,"Memory Error: DataMaps Memory requested size %s denied...", utils::BytifySize(newMemorySize).c_str());
		mutex->leave();
		return false;
	}
	else if (newMemorySize > 50000000) {
		LogPrint(0,LOG_MEMORY,2,"Memory Warning: DataMaps Memory now %s...", utils::BytifySize(newMemorySize).c_str());
	}

	//DataMapsMemoryStruct* newHeader = (DataMapsMemoryStruct*) utils::OpenSharedMemorySegment(utils::StringFormat("PsycloneDataMapsMemory_%u_%u", port, serial).c_str(), memorySize);
	//if (newHeader) {
	//	//utils::CloseSharedMemorySegment((char*)newHeader, newMemorySize);
	//	LogPrint(0,LOG_MEMORY,0,"DataMapsMemory removing stale shared memory (%u/%u)...", port, serial);
	//}

	DataMapsMemoryStruct* newHeader = (DataMapsMemoryStruct*) utils::CreateSharedMemorySegment(utils::StringFormat("PsycloneDataMapsMemory_%u_%u", port, serial).c_str(), newMemorySize, true);
	if (!newHeader) {
		mutex->leave();
		LogPrint(0,LOG_MEMORY,0,"DataMaps Memory could not be created...");
		return false;
	}

	memset(newHeader, 0, (size_t)memorySize);
	newHeader->size = memorySize;
	newHeader->cid = DATAMAPSMEMORYID;
	newHeader->createdTime = GetTimeNow();
	newHeader->typesMaxCount = typesMaxCount;
	newHeader->typesBitFieldSize = typesBitFieldSize;
	newHeader->typesSize = typesSize;
	newHeader->contextsMaxCount = contextsMaxCount;
	newHeader->contextsBitFieldSize = contextsBitFieldSize;
	newHeader->contextsSize = contextsSize;
	newHeader->tagsMaxCount = tagsMaxCount;
	newHeader->tagsBitFieldSize = tagsBitFieldSize;
	newHeader->tagsSize = tagsSize;
	newHeader->cranksMaxCount = cranksMaxCount;
	newHeader->cranksBitFieldSize = cranksBitFieldSize;
	newHeader->cranksSize = cranksSize;
//	newHeader->componentsMaxCount = componentsMaxCount;
//	newHeader->componentsBitFieldSize = componentsBitFieldSize;
//	newHeader->componentsSize = componentsSize;
	newHeader->requestsMaxCount = requestsMaxCount;
	newHeader->requestsBitFieldSize = requestsBitFieldSize;
	newHeader->requestsSize = requestsSize;

	this->port = port;

	GenericMapHeader* oldSubHeader = typeMapHeader;
	typeMapHeader = (GenericMapHeader*)(((char*)newHeader) + sizeof(DataMapsMemoryStruct));
	typeMapHeader->bitFieldSize = typesBitFieldSize;
	typeMapHeader->size = typesSize;
	typeMapHeader->maxID = typesMaxCount;
	memset(((char*)typeMapHeader)+sizeof(GenericMapHeader), 255, typesBitFieldSize);
	// Position 0 is not allowed, used to indicate error or unused	
	utils::SetBit(0, BITOCCUPIED, ((char*)typeMapHeader + sizeof(GenericMapHeader)), typeMapHeader->bitFieldSize);

	if (header) {
		// Copy bitfield
		memcpy((char*)typeMapHeader + sizeof(GenericMapHeader),
			(char*)oldSubHeader + sizeof(GenericMapHeader),
			oldSubHeader->bitFieldSize);
		// Copy data
		memcpy((char*)typeMapHeader + sizeof(GenericMapHeader) + typesBitFieldSize,
			(char*)oldSubHeader + sizeof(GenericMapHeader) + oldSubHeader->bitFieldSize,
			(size_t)(oldSubHeader->size - sizeof(GenericMapHeader) - oldSubHeader->bitFieldSize));
	}

	oldSubHeader = contextMapHeader;
	contextMapHeader = (GenericMapHeader*)(((char*)typeMapHeader) + typesSize);
	contextMapHeader->bitFieldSize = contextsBitFieldSize;
	contextMapHeader->size = contextsSize;
	contextMapHeader->maxID = contextsMaxCount;
	memset(((char*)contextMapHeader)+sizeof(GenericMapHeader), 255, contextsBitFieldSize);
	// Position 0 is not allowed, used to indicate error or unused	
	utils::SetBit(0, BITOCCUPIED, ((char*)contextMapHeader + sizeof(GenericMapHeader)), contextMapHeader->bitFieldSize);
	if (header) {
		// Copy bitfield
		memcpy((char*)contextMapHeader + sizeof(GenericMapHeader),
			(char*)oldSubHeader + sizeof(GenericMapHeader),
			oldSubHeader->bitFieldSize);
		// Copy data
		memcpy((char*)contextMapHeader + sizeof(GenericMapHeader) + contextsBitFieldSize,
			(char*)oldSubHeader + sizeof(GenericMapHeader) + oldSubHeader->bitFieldSize,
			(size_t)(oldSubHeader->size - sizeof(GenericMapHeader) - oldSubHeader->bitFieldSize));
	}

	oldSubHeader = tagMapHeader;
	tagMapHeader = (GenericMapHeader*)(((char*)contextMapHeader) + contextsSize);
	tagMapHeader->bitFieldSize = tagsBitFieldSize;
	tagMapHeader->size = tagsSize;
	tagMapHeader->maxID = tagsMaxCount;
	memset(((char*)tagMapHeader)+sizeof(GenericMapHeader), 255, tagsBitFieldSize);
	// Position 0 is not allowed, used to indicate error or unused	
	utils::SetBit(0, BITOCCUPIED, ((char*)tagMapHeader + sizeof(GenericMapHeader)), tagMapHeader->bitFieldSize);
	if (header) {
		// Copy bitfield
		memcpy((char*)tagMapHeader + sizeof(GenericMapHeader),
			(char*)oldSubHeader + sizeof(GenericMapHeader),
			oldSubHeader->bitFieldSize);
		// Copy data
		memcpy((char*)tagMapHeader + sizeof(GenericMapHeader) + tagsBitFieldSize,
			(char*)oldSubHeader + sizeof(GenericMapHeader) + oldSubHeader->bitFieldSize,
			(size_t)(oldSubHeader->size - sizeof(GenericMapHeader) - oldSubHeader->bitFieldSize));
	}

	oldSubHeader = crankMapHeader;
	crankMapHeader = (GenericMapHeader*)(((char*)tagMapHeader) + tagsSize);
	crankMapHeader->bitFieldSize = cranksBitFieldSize;
	crankMapHeader->size = cranksSize;
	crankMapHeader->maxID = cranksMaxCount;
	memset(((char*)crankMapHeader)+sizeof(GenericMapHeader), 255, cranksBitFieldSize);
	// Position 0 is not allowed, used to indicate error or unused	
	utils::SetBit(0, BITOCCUPIED, ((char*)crankMapHeader + sizeof(GenericMapHeader)), crankMapHeader->bitFieldSize);
	if (header) {
		// Copy bitfield
		memcpy((char*)crankMapHeader + sizeof(GenericMapHeader),
			(char*)oldSubHeader + sizeof(GenericMapHeader),
			oldSubHeader->bitFieldSize);
		// Copy data
		memcpy((char*)crankMapHeader + sizeof(GenericMapHeader) + cranksBitFieldSize,
			(char*)oldSubHeader + sizeof(GenericMapHeader) + oldSubHeader->bitFieldSize,
			(size_t)(oldSubHeader->size - sizeof(GenericMapHeader) - oldSubHeader->bitFieldSize));
	}
	
	//oldSubHeader = componentMapHeader;
	//componentMapHeader = (GenericMapHeader*)(((char*)crankMapHeader) + cranksSize);
	//componentMapHeader->bitFieldSize = componentsBitFieldSize;
	//componentMapHeader->size = componentsSize;
	//if (header) {
	//	// Copy bitfield
	//	memcpy((char*)componentMapHeader + sizeof(GenericMapHeader),
	//		(char*)oldSubHeader + sizeof(GenericMapHeader),
	//		oldSubHeader->bitFieldSize);
	//	// Copy data
	//	memcpy((char*)componentMapHeader + sizeof(GenericMapHeader) + componentsBitFieldSize,
	//		(char*)oldSubHeader + sizeof(GenericMapHeader) + oldSubHeader->bitFieldSize,
	//		oldSubHeader->size - sizeof(GenericMapHeader) - oldSubHeader->bitFieldSize);
	//}

	oldSubHeader = requestMapHeader;
	requestMapHeader = (GenericMapHeader*)(((char*)crankMapHeader) + cranksSize);
	requestMapHeader->bitFieldSize = requestsBitFieldSize;
	requestMapHeader->size = requestsSize;
	requestMapHeader->maxID = requestsMaxCount;
	memset(((char*)requestMapHeader)+sizeof(GenericMapHeader), 255, requestsBitFieldSize);
	// Position 0 is not allowed, used to indicate error or unused	
	utils::SetBit(0, BITOCCUPIED, ((char*)requestMapHeader + sizeof(GenericMapHeader)), requestMapHeader->bitFieldSize);
	if (header) {
		// Copy bitfield
		memcpy((char*)requestMapHeader + sizeof(GenericMapHeader),
			(char*)oldSubHeader + sizeof(GenericMapHeader),
			oldSubHeader->bitFieldSize);
		// Copy data
		memcpy((char*)requestMapHeader + sizeof(GenericMapHeader) + requestsBitFieldSize,
			(char*)oldSubHeader + sizeof(GenericMapHeader) + oldSubHeader->bitFieldSize,
			(size_t)(oldSubHeader->size - sizeof(GenericMapHeader) - oldSubHeader->bitFieldSize));
	}

	if (header) 
		utils::CloseSharedMemorySegment((char*)header, header->size);
	header = newHeader;
	memorySize = newMemorySize;

	//utils::Sleep(10);
	master->setDataMapsShmemSize(memorySize);
	mutex->leave();
	return true;
}





 
bool DataMapsMemory::confirmTypeLevelID(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<TypeMapEntry, uint16>::ConfirmEntry((char*)typeMapHeader, id);
	mutex->leave();
	return result;
}

bool DataMapsMemory::cancelTypeLevelID(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<TypeMapEntry, uint16>::CancelEntry((char*)typeMapHeader, id);
	mutex->leave();
	return result;
}

bool DataMapsMemory::writeTypeLevelsToMsg(DataMessage* msg) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<TypeMapEntry, uint16>::WriteAllEntriesToMsg((char*)typeMapHeader, msg);
	mutex->leave();
	return result;
}

bool DataMapsMemory::syncTypeLevels(DataMessage* msg) {
	int64 n = 0;
	uint16 id;
	const char* name;
	uint64 time;
	uint16 exID;
	while ( (id = (uint16)msg->getInt(n, "ID")) && (name = msg->getString(n, "Name")) && (time = msg->getTime(n, "CreatedTime"))) {
		if (!createNewTypeLevel(id, name, time, exID))
			return false;
		confirmTypeLevelID(id);
		n++;
	}
	return true;
}

bool DataMapsMemory::writeContextLevelsToMsg(DataMessage* msg) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<TypeMapEntry, uint16>::WriteAllEntriesToMsg((char*)contextMapHeader, msg);
	mutex->leave();
	return result;
}

bool DataMapsMemory::syncContextLevels(DataMessage* msg) {
	int64 n = 0;
	uint16 id;
	const char* name;
	uint64 time;
	uint16 exID;
	while ((id = (uint16)msg->getInt(n, "ID")) && (name = msg->getString(n, "Name")) && (time = msg->getTime(n, "CreatedTime"))) {
		if (!createNewContextLevel(id, name, time, exID))
			return false;
		confirmContextLevelID(id);
		n++;
	}
	return true;
}

bool DataMapsMemory::writeTagsToMsg(DataMessage* msg) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<TypeMapEntry, uint16>::WriteAllEntriesToMsg((char*)tagMapHeader, msg);
	mutex->leave();
	return result;
}

bool DataMapsMemory::syncTags(DataMessage* msg) {
	int64 n = 0;
	uint16 id;
	const char* name;
	uint64 time;
	uint32 exID;
	while ((id = (uint16)msg->getInt(n, "ID")) && (name = msg->getString(n, "Name")) && (time = msg->getTime(n, "CreatedTime"))) {
		if (!createNewTag(id, name, time, exID))
			return false;
		confirmTagID(id);
		n++;
	}
	return true;
}

bool DataMapsMemory::writeCranksToMsg(DataMessage* msg) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<TypeMapEntry, uint16>::WriteAllEntriesToMsg((char*)crankMapHeader, msg);
	mutex->leave();
	return result;
}

bool DataMapsMemory::syncCranks(DataMessage* msg) {
	int64 n = 0;
	uint16 id;
	const char* name, *function, *libraryFilename, *language, *script;
	uint64 time;
	uint16 exID;
	while ((id = (uint16)msg->getInt(n, "ID")) && (name = msg->getString(n, "Name")) && (time = msg->getTime(n, "CreatedTime"))) {
		function = msg->getString(n, "Function");
		libraryFilename = msg->getString(n, "LibraryFilename");
		language = msg->getString(n, "Language");
		script = msg->getString(n, "Script");
		if (!createNewCrank(id, (uint16) msg->getInt(n, "CompID"), name, function ? function : "",
			libraryFilename ? libraryFilename : "", language ? language : "", script ? script : "", time, exID))
			return false;
		confirmCrankID(id);
		n++;
	}
	return true;
}


bool DataMapsMemory::createNewTypeLevel(uint16 id, const char* name, uint64 time, uint16& existingID) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL

	existingID = GenericMemoryMap<TypeMapEntry, uint16>::GetEntryID((char*)typeMapHeader, name, true);
	if (existingID && (existingID != id)) {
		mutex->leave();
		return false;
	}

	if (id > header->typesMaxCount) {
		// printf("createNewTypeLevel ID %u > typesMax %u\n", id, header->typesMaxCount);
		if (!resize(port, serial = master->incrementDataMapsShmemSerial(), id + 1024, header->contextsMaxCount, header->tagsMaxCount, header->cranksMaxCount, header->requestsMaxCount)) {
			mutex->leave();
			printf("createNewTypeLevel resize failed\n");
			return false;
		}
		// printf("createNewTypeLevel typesMax %u after resize\n", header->typesMaxCount);
	}
		
	TypeMapEntry* entry = GenericMemoryMap<TypeMapEntry, uint16>::CreateEntry((char*)typeMapHeader, id, name);
	if (!entry) {
		entry = GenericMemoryMap<TypeMapEntry, uint16>::GetEntry((char*)typeMapHeader, id);
		if (!entry) {
			printf("createNewTypeLevel '%s' %u failed\n", name, id); fflush(stdout);
		}
		else {
			printf("createNewTypeLevel '%s' %u failed - existing entry: '%s'\n", name, id, entry->name); fflush(stdout);
		}
		mutex->leave();
		return false;
	}
	//printf("createNewTypeLevel '%s' %u success\n", name, id); fflush(stdout);
	if (time)
		entry->time = time;
	mutex->leave();
	return true;
}


bool DataMapsMemory::getTypeLevelName(uint16 id, char* name, uint32 maxSize) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	if (GenericMemoryMap<TypeMapEntry, uint16>::GetEntryName((char*)typeMapHeader, id, name, maxSize)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::getTypeLevelID(const char* name, uint16 &id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	id = GenericMemoryMap<TypeMapEntry, uint16>::GetEntryID((char*)typeMapHeader, name);
	if (id) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


uint8 DataMapsMemory::lookupTypeLevelID(const char* name, uint16 &id) { // status = 0: not there, 1: in-sync, 2: ready
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint8 status = GenericMemoryMap<TypeMapEntry, uint16>::LookupEntryID((char*)typeMapHeader, name, id);
	mutex->leave();
	return status;
}


bool DataMapsMemory::deleteTypeLevel(const char* name) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint16 id = GenericMemoryMap<TypeMapEntry, uint16>::GetEntryID((char*)typeMapHeader, name);
	if (id && GenericMemoryMap<TypeMapEntry, uint16>::DeleteEntry((char*)typeMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::deleteTypeLevel(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	if (GenericMemoryMap<TypeMapEntry, uint16>::DeleteEntry((char*)typeMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


uint64 DataMapsMemory::getTypeLevelCreateTime(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint64 t = GenericMemoryMap<TypeMapEntry, uint16>::GetEntryTime((char*)typeMapHeader, id);
	mutex->leave();
	return t;
}

std::string DataMapsMemory::printAllTypes() {
	std::string str;
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return str;
	CHECKDATAMAPSMEMORYSERIAL
	str = GenericMemoryMap<TypeMapEntry, uint16>::PrintAllEntries((char*)typeMapHeader);
	mutex->leave();
	return str;
}



///////////////////////////////////////////////////////////
//                   ContextMap                          //
///////////////////////////////////////////////////////////

 
bool DataMapsMemory::confirmContextLevelID(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<ContextMapEntry, uint16>::ConfirmEntry((char*)contextMapHeader, id);
	mutex->leave();
	return result;
}

bool DataMapsMemory::cancelContextLevelID(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<ContextMapEntry, uint16>::CancelEntry((char*)contextMapHeader, id);
	mutex->leave();
	return result;
}

bool DataMapsMemory::createNewContextLevel(uint16 id, const char* name, uint64 time, uint16& existingID) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL

	existingID = GenericMemoryMap<ContextMapEntry, uint16>::GetEntryID((char*)contextMapHeader, name, true);
	if (existingID && (existingID != id)) {
		mutex->leave();
		return false;
	}

	if (id > header->contextsMaxCount) {
		if (!resize(port, serial = master->incrementDataMapsShmemSerial(), header->typesMaxCount, id + 1024, header->tagsMaxCount, header->cranksMaxCount, header->requestsMaxCount)) {
			mutex->leave();
			return false;
		}
	}
		
	ContextMapEntry* entry = GenericMemoryMap<ContextMapEntry, uint16>::CreateEntry((char*)contextMapHeader, id, name);
	if (!entry) {
		mutex->leave();
		return false;
	}
	if (time)
		entry->time = time;
	mutex->leave();
	return true;
}


bool DataMapsMemory::getContextLevelName(uint16 id, char* name, uint32 maxSize) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	if (GenericMemoryMap<ContextMapEntry, uint16>::GetEntryName((char*)contextMapHeader, id, name, maxSize)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::getContextLevelID(const char* name, uint16 &id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	id = GenericMemoryMap<ContextMapEntry, uint16>::GetEntryID((char*)contextMapHeader, name);
	if (id) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}

uint8 DataMapsMemory::lookupContextLevelID(const char* name, uint16 &id) { // status = 0: not there, 1: in-sync, 2: ready
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint8 status = GenericMemoryMap<ContextMapEntry, uint16>::LookupEntryID((char*)contextMapHeader, name, id);
	mutex->leave();
	return status;
}

bool DataMapsMemory::deleteContextLevel(const char* name) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint16 id = GenericMemoryMap<ContextMapEntry, uint16>::GetEntryID((char*)contextMapHeader, name);
	if (id && GenericMemoryMap<ContextMapEntry, uint16>::DeleteEntry((char*)contextMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::deleteContextLevel(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	if (GenericMemoryMap<ContextMapEntry, uint16>::DeleteEntry((char*)contextMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


uint64 DataMapsMemory::getContextLevelCreateTime(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint64 t = GenericMemoryMap<ContextMapEntry, uint16>::GetEntryTime((char*)contextMapHeader, id);
	mutex->leave();
	return t;
}

std::string DataMapsMemory::printAllContexts() {
	std::string str;
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return str;
	CHECKDATAMAPSMEMORYSERIAL
	str = GenericMemoryMap<TypeMapEntry, uint16>::PrintAllEntries((char*)contextMapHeader);
	mutex->leave();
	return str;
}



///////////////////////////////////////////////////////////
//                     TagMap                          //
///////////////////////////////////////////////////////////

 
bool DataMapsMemory::confirmTagID(uint32 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<TagMapEntry, uint16>::ConfirmEntry((char*)tagMapHeader, id);
	mutex->leave();
	return result;
}

bool DataMapsMemory::cancelTagID(uint32 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<TagMapEntry, uint16>::CancelEntry((char*)tagMapHeader, id);
	mutex->leave();
	return result;
}

bool DataMapsMemory::createNewTag(uint32 id, const char* name, uint64 time, uint32& existingID) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL

	existingID = GenericMemoryMap<TagMapEntry, uint16>::GetEntryID((char*)tagMapHeader, name, true);
	if (existingID && (existingID != id)) {
		mutex->leave();
		return false;
	}

	if (id > header->tagsMaxCount) {
		if (!resize(port, serial = master->incrementDataMapsShmemSerial(), header->typesMaxCount, header->contextsMaxCount, id + 1024, header->cranksMaxCount, header->requestsMaxCount)) {
			mutex->leave();
			return false;
		}
	}
		
	TagMapEntry* entry = GenericMemoryMap<TagMapEntry, uint16>::CreateEntry((char*)tagMapHeader, id, name);
	if (!entry) {
		mutex->leave();
		return false;
	}
	if (time)
		entry->time = time;
	mutex->leave();
	return true;
}


bool DataMapsMemory::getTagName(uint32 id, char* name, uint32 maxSize) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	if (GenericMemoryMap<TagMapEntry, uint16>::GetEntryName((char*)tagMapHeader, id, name, maxSize)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::getTagID(const char* name, uint32 &id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	id = GenericMemoryMap<TagMapEntry, uint16>::GetEntryID((char*)tagMapHeader, name);
	if (id) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


uint8 DataMapsMemory::lookupTagID(const char* name, uint32 &id) { // status = 0: not there, 1: in-sync, 2: ready
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint8 status = GenericMemoryMap<TagMapEntry, uint32>::LookupEntryID((char*)tagMapHeader, name, id);
	mutex->leave();
	return status;
}


bool DataMapsMemory::deleteTag(const char* name) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint32 id = GenericMemoryMap<TagMapEntry, uint16>::GetEntryID((char*)tagMapHeader, name);
	if (id && GenericMemoryMap<TagMapEntry, uint16>::DeleteEntry((char*)tagMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::deleteTag(uint32 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	if (GenericMemoryMap<TagMapEntry, uint16>::DeleteEntry((char*)tagMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


uint64 DataMapsMemory::getTagCreateTime(uint32 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint64 t = GenericMemoryMap<TagMapEntry, uint16>::GetEntryTime((char*)tagMapHeader, id);
	mutex->leave();
	return t;
}






///////////////////////////////////////////////////////////
//                     CrankMap                          //
///////////////////////////////////////////////////////////


bool DataMapsMemory::confirmCrankID(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<CrankMapEntry, uint16>::ConfirmEntry((char*)crankMapHeader, id);
	mutex->leave();
	return result;
}

bool DataMapsMemory::cancelCrankID(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	bool result = GenericMemoryMap<CrankMapEntry, uint16>::CancelEntry((char*)crankMapHeader, id);
	mutex->leave();
	return result;
}

bool DataMapsMemory::createNewCrank(uint16 id, uint32 compID, const char* name, const char* function, const char* libraryFilename, const char* language, const char* script, uint64 time, uint16& existingID) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	
	existingID = GenericMemoryMap<CrankMapEntry, uint16>::GetEntryID((char*)crankMapHeader, name, true);
	if (existingID && (existingID != id)) {
		mutex->leave();
		return false;
	}

	if (id > header->cranksMaxCount) {
		if (!resize(port, serial = master->incrementDataMapsShmemSerial(), header->typesMaxCount, header->contextsMaxCount, header->tagsMaxCount, id + 1024, header->requestsMaxCount)) {
			mutex->leave();
			return false;
		}
	}
		
	CrankMapEntry* entry = GenericMemoryMap<CrankMapEntry, uint16>::CreateEntry((char*)crankMapHeader, id, name);
	if (!entry) {
		mutex->leave();
		return false;
	}
	entry->compID = compID;
	if (time)
		entry->time = time;
	utils::strcpyavail(entry->language, language, MAXKEYNAMELEN, false);
	utils::strcpyavail(entry->function, function, MAXKEYNAMELEN, false);
	utils::strcpyavail(entry->libraryFilename, libraryFilename, MAXKEYNAMELEN, false);
	utils::strcpyavail(entry->script, script, MAXSCRIPTLEN, false);
	mutex->leave();
	return true;
}

bool DataMapsMemory::getCrankFunction(uint16 id, char* function, uint32 maxSize) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
		CrankMapEntry* entry = GenericMemoryMap<CrankMapEntry, uint16>::GetEntry((char*)crankMapHeader, id);
	if (entry) {
		utils::strcpyavail(function, entry->function, maxSize, false);
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}

bool DataMapsMemory::getCrankLanguage(uint16 id, char* language, uint32 maxSize) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
		CrankMapEntry* entry = GenericMemoryMap<CrankMapEntry, uint16>::GetEntry((char*)crankMapHeader, id);
	if (entry) {
		utils::strcpyavail(language, entry->language, maxSize, false);
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}

//static
bool DataMapsMemory::getCrankLibraryFilename(uint16 id, char* libraryFilename, uint32 maxSize) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	CrankMapEntry* entry = GenericMemoryMap<CrankMapEntry, uint16>::GetEntry((char*)crankMapHeader, id);
	if (entry) {
		utils::strcpyavail(libraryFilename, entry->libraryFilename, maxSize, false);
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::getCrankScript(uint16 id, char* script, uint32 maxSize) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	CrankMapEntry* entry = GenericMemoryMap<CrankMapEntry, uint16>::GetEntry((char*)crankMapHeader, id);
	if (entry) {
		utils::strcpyavail(script, entry->script, maxSize, false);
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::getCrankName(uint16 id, char* name, uint32 maxSize) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	if (GenericMemoryMap<CrankMapEntry, uint16>::GetEntryName((char*)crankMapHeader, id, name, maxSize)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::getCrankID(const char* name, uint16 &id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	id = GenericMemoryMap<CrankMapEntry, uint16>::GetEntryID((char*)crankMapHeader, name);
	if (id) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}

uint8 DataMapsMemory::lookupCrankID(const char* name, uint16 &id) { // status = 0: not there, 1: in-sync, 2: ready
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint8 status = GenericMemoryMap<CrankMapEntry, uint16>::LookupEntryID((char*)crankMapHeader, name, id);
	mutex->leave();
	return status;
}

uint32 DataMapsMemory::getCrankCompID(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return 0;
	CHECKDATAMAPSMEMORYSERIAL
	CrankMapEntry* entry = GenericMemoryMap<CrankMapEntry, uint16>::GetEntry((char*)crankMapHeader, id);
	if (entry) {
		uint32 compID = entry->compID;
		mutex->leave();
		return compID;
	}
	else {
		mutex->leave();
		return 0;
	}
}

bool DataMapsMemory::deleteCrank(const char* name) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint16 id = GenericMemoryMap<CrankMapEntry, uint16>::GetEntryID((char*)crankMapHeader, name);
	if (id && GenericMemoryMap<CrankMapEntry, uint16>::DeleteEntry((char*)crankMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


bool DataMapsMemory::deleteCrank(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	if (GenericMemoryMap<CrankMapEntry, uint16>::DeleteEntry((char*)crankMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}


uint64 DataMapsMemory::getCrankCreateTime(uint16 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint64 t = GenericMemoryMap<CrankMapEntry, uint16>::GetEntryTime((char*)crankMapHeader, id);
	mutex->leave();
	return t;
}






///////////////////////////////////////////////////////////
//                     RequestMap                        //
///////////////////////////////////////////////////////////

bool DataMapsMemory::createNewRequest(uint32 from, uint32 to, uint32 remoteID, uint32 &id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL

	RequestMapEntry* entry = GenericMemoryMap<RequestMapEntry, uint32>::CreateFirstFreeEntry((char*)requestMapHeader, id, NULL);
	if (!entry) {
		if (!maintenance()) {
			mutex->leave();
			return false;
		}
		CHECKDATAMAPSMEMORYSERIAL
		if (!(entry = GenericMemoryMap<RequestMapEntry, uint32>::CreateFirstFreeEntry((char*)requestMapHeader, id, NULL))) {
			mutex->leave();
			return false;
		}
	}
	entry->status = REQ_CREATED;
	entry->time = GetTimeNow();
	entry->from = from;
	entry->to = to;
	entry->remoteID = remoteID;
	entry->lastUpdate = 0;
	entry->status = 2; // No need to sync between nodes, so just confirm the entry id as valid
	snprintf(entry->name, MAXKEYNAMELEN, "ReqPsycloneProcessMemoryRequest_%u_%u", port, id);
	LogPrint(0,LOG_MEMORY,5,"Creating request (%p) id %u...", entry, id);
	mutex->leave();
	return true;
}

bool DataMapsMemory::getRequestInfo(uint32 id, uint32& from, uint32& to, uint32& remoteID) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	RequestMapEntry* entry = GenericMemoryMap<RequestMapEntry, uint32>::GetEntry((char*)requestMapHeader, id);
	if (entry) {
		from = entry->from;
		to = entry->to;
		remoteID = entry->remoteID;
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}

bool DataMapsMemory::getRequestStatus(uint32 id, uint8& status, uint64& time, uint64& msgID, uint64& msgEOL) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	RequestMapEntry* entry = GenericMemoryMap<RequestMapEntry, uint32>::GetEntry((char*)requestMapHeader, id);
	if (entry) {
		status = entry->status;
		time = entry->lastUpdate;
		msgID = entry->dataMessageID;
		msgEOL = entry->dataMessageEOL;
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}

bool DataMapsMemory::setRequestStatus(uint32 id, uint8 status) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	RequestMapEntry* entry = GenericMemoryMap<RequestMapEntry, uint32>::GetEntry((char*)requestMapHeader, id);
	if (entry) {
		entry->status = status;
		entry->lastUpdate = GetTimeNow();
		mutex->leave();
		utils::SignalSemaphore(entry->name);
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}

bool DataMapsMemory::setRequestStatus(uint32 id, uint8 status, uint64 msgID, uint64 msgEOL) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	RequestMapEntry* entry = GenericMemoryMap<RequestMapEntry, uint32>::GetEntry((char*)requestMapHeader, id);
	if (entry) {
		entry->status = status;
		entry->lastUpdate = GetTimeNow();
		entry->dataMessageID = msgID;
		entry->dataMessageEOL = msgEOL;
		LogPrint(0,LOG_MEMORY,5,"setRequestStatus (%p) id %u status %u (last update %s)", entry, id, status, PrintTimeString(entry->lastUpdate).c_str());
		mutex->leave();
		utils::SignalSemaphore(entry->name);
		return true;
	}
	else {
		LogPrint(0,LOG_MEMORY,0,"setRequestStatus id %u failed", id);
		mutex->leave();
		return false;
	}
}

bool DataMapsMemory::waitForRequestReply(uint32 id, uint32 timeout, uint8& status, uint64& time, uint64& msgID, uint64& msgEOL) {
	uint64 start = GetTimeNow();
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	RequestMapEntry* entry = GenericMemoryMap<RequestMapEntry, uint32>::GetEntry((char*)requestMapHeader, id);
	if (!entry) {
		mutex->leave();
		return false;
	}

	LogPrint(0,LOG_MEMORY,5,"Start waitForRequestReply (%p) id %u status %u (last update %s)", entry, id, entry->status, PrintTimeString(time).c_str());

	int32 timeleft;
	while ( (entry->status < REQ_REPLY_READY) && ( (timeleft = timeout - GetTimeAgeMS(start)) > 0) ) {
		// get semaphore
		mutex->leave();
		// wait for timeleft for semaphore
		utils::WaitForSemaphore(entry->name, timeleft);
		if (!mutex->enter(5000, __FUNCTION__)) {
		//	printf("MUTEX!");
			return false;
		}
		CHECKDATAMAPSMEMORYSERIAL
		if (!(entry = GenericMemoryMap<RequestMapEntry, uint32>::GetEntry((char*)requestMapHeader, id))) {
		//	printf("ENTRY!");
			mutex->leave();
			return false;
		}
	}

	// Here we will have the mutex
	status = entry->status;
	time = entry->lastUpdate;
	msgID = entry->dataMessageID;
	msgEOL = entry->dataMessageEOL;

	mutex->leave();
	if (!(status >= REQ_REPLY_READY))
		LogPrint(0,LOG_MEMORY,0,"waitForRequestReply (%p) id %u timed out, status %u (last update %s)", entry, id, status, PrintTimeString(time).c_str());
	return (status >= REQ_REPLY_READY);
}

bool DataMapsMemory::deleteRequest(uint32 id) {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	LogPrint(0,LOG_MEMORY,5,"Deleting request id %u...", id);
	if (id && GenericMemoryMap<RequestMapEntry, uint32>::DeleteEntry((char*)requestMapHeader, id)) {
		mutex->leave();
		return true;
	}
	else {
		mutex->leave();
		return false;
	}
}

uint32 DataMapsMemory::getRequestCount() {
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return false;
	CHECKDATAMAPSMEMORYSERIAL
	uint32 count = GenericMemoryMap<RequestMapEntry, uint32>::GetCount((char*)requestMapHeader);
	mutex->leave();
	return count;
}


std::string DataMapsMemory::printFriendlyHTML() {
	std::string str;
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return str;
	CHECKDATAMAPSMEMORYSERIAL
	str = "<B>Types</B><BR><table border=1>";
	str += GenericMemoryMap<TypeMapEntry, uint16>::PrintAllEntriesHTML((char*)typeMapHeader);
	str += "</table><B>Contexts</B><BR><table border=1>";
	str += GenericMemoryMap<ContextMapEntry, uint16>::PrintAllEntriesHTML((char*)contextMapHeader);
	str += "</table><B>Tags</B><BR><table border=1>";
	str += GenericMemoryMap<TagMapEntry, uint16>::PrintAllEntriesHTML((char*)tagMapHeader);
	str += "</table><B>Crank</B><BR><table border=1>";
	str += GenericMemoryMap<CrankMapEntry, uint16>::PrintAllEntriesHTML((char*)crankMapHeader);
	str += "</table><B>Requests</B><BR><table border=1>";
	str += GenericMemoryMap<RequestMapEntry, uint16>::PrintAllEntriesHTML((char*)requestMapHeader);
	mutex->leave();
	return str;
}

std::string DataMapsMemory::toXML() {
	std::string xml;
	if (!mutex || !mutex->enter(5000, __FUNCTION__))
		return xml;
	CHECKDATAMAPSMEMORYSERIAL
	xml += GenericMemoryMap<TypeMapEntry, uint16>::ToXML((char*)typeMapHeader);
	xml += GenericMemoryMap<ContextMapEntry, uint16>::ToXML((char*)contextMapHeader);
	xml += GenericMemoryMap<TagMapEntry, uint16>::ToXML((char*)tagMapHeader);
	xml += GenericMemoryMap<CrankMapEntry, uint16>::ToXML((char*)crankMapHeader);
	// xml += GenericMemoryMap<RequestMapEntry, uint16>::ToXML((char*)requestMapHeader);
	mutex->leave();
	return utils::StringFormat("<ids>\n%s</ids>\n", xml.c_str());
}


} // namespace cmlabs













