

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  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.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#if !defined(_DATAMESSAGE_H_)
#define _DATAMESSAGE_H_

#include "Types.h"
#include "ObjectIDs.h"
//#include "Collections.h"
#include "Utils.h"

namespace cmlabs {

struct DataMessageEntryHeader {
	uint32	size;
	uint32	cid;
};

struct DataMessageHeader {
	uint32		size;			// auto
	uint32		cid;			// auto
	uint64		memid;			// auto
	uint64		time;			// auto
	uint64		sendtime;		// api
	uint64		recvtime;		// api
	uint16		origin;			// NodeID, api
	uint16		destination;	// NodeID, api

	uint64		ttl;			// spec
	uint16		priority;		// spec
	uint8		policy;			// spec

	uint32		from;			// user
	uint32		to;				// user

	PsyType		type;			// api/user
	uint32		tag;			// api/user
	uint16		status;			// api/user
	uint64		reference;		// api
	uint64		serial;			// api/user
	PsyContext	contextchange;	// api/user

	uint32 userSize;	// size of user data
	uint32 userCount;	// number of user data entries

	std::string toJSON();
	std::string toXML();
};

class DataMessage {
public:
	/*! DataMessage()
	Creates an empty DataMessage
	*/
	DataMessage();
	/*! DataMessage(PsyType type, uint32 from)
	Creates a DataMessage with type and from fields set
	@param type set the message type
	@param from set the message sender id
	*/
	DataMessage(PsyType type, uint32 from);
	/*! DataMessage(PsyType type, uint32 from, uint32 to, uint64 ttl = 0, uint16 priority = 0)
	Creates a DataMessage with multiple fields set
	@param type set the message type
	@param from set the message sender id
	@param to set the message receiver id
	@param ttl set the time-to-live for the message in microseconds, after which it will have reached its end-of-life (eol)
	@param priority set the message priority
	*/
	DataMessage(PsyType type, uint32 from, uint32 to, uint64 ttl = 0, uint16 priority = 0);
	/*! DataMessage(PsyType type, uint32 from, uint32 to, uint32 tag, uint64 time, uint64 ttl = 0, uint16 priority = 0)
	Creates a DataMessage with multiple fields set
	@param type set the message type
	@param from set the message sender id
	@param to set the message receiver id
	@param tag set the message tag id
	@param ttl set the time-to-live for the message in microseconds, after which it will have reached its end-of-life (eol)
	@param priority set the message priority
	*/
	DataMessage(PsyType type, uint32 from, uint32 to, uint32 tag, uint64 time, uint64 ttl = 0, uint16 priority = 0);
	/*! DataMessage(char* data, bool copy = false)
	Creates a DataMessage as a copy of the binary message data provided
	@param data the binary message data to copy from
	@param copy should the data be copied or can it be taken
	*/
	DataMessage(char* data, bool copy = false);
	/*! DataMessage(const char* data)
	@param data the binary message data to copy from
	Creates a DataMessage as a copy of the binary message data provided, will always copy the data
	*/
	DataMessage(const char* data);
	/*! DataMessage(const DataMessage& msg)
	@param msg the message to copy from
	Creates a DataMessage as a copy of another DataMessage
	*/
	DataMessage(const DataMessage& msg);
	/*! DataMessage(const char* data, uint32 maxDraftSize)
	Creates a DataMessage as a copy of the binary message data provided, will always copy the data
	If the binary size is below maxDraftSize the full message is copied
	If not some larger user entries will be provided as information only, i.e. name and size, but not content
	@param data the binary message data to copy from
	@param maxDraftSize the maximum binary size of the newly created message
	*/
	DataMessage(const char* data, uint32 maxDraftSize);
	/*! DataMessage(const DataMessage& msg, uint32 maxDraftSize)
	Creates a DataMessage as a copy of the message provided
	If the binary size is below maxDraftSize the full message is copied
	If not some larger user entries will be provided as information only, i.e. name and size, but not content
	@param msg the message to copy from
	@param maxDraftSize the maximum binary size of the newly created message
	*/
	DataMessage(const DataMessage& msg, uint32 maxDraftSize);
	/*! ~DataMessage()
	Message destructor
	*/
	~DataMessage();

    /*! swapMessageData(const char* data)
    
        internal function
     
        @param data
     */
	
	const char* swapMessageData(const char* data);
    
    /*! fillInDraftUserDataFrom(const char* data, uint32 maxDraftSize)
     
        internal function
     
        @param data
        @param maxDraftSize
     */
	bool fillInDraftUserDataFrom(const char* data, uint32 maxDraftSize);

	/*! isValid()
	Checks to see if the message memory is valid
	@return true if successful, false otherwise
	*/
	bool isValid() {return data && GetObjID(data) == DATAMESSAGEID; }

	// User
    
    /*! getContentType(const char* key)
        
        returns the type of content with this key as CONSTCHARID, TIMEID, CHARDATAID, INTID, DOUBLEID, etc
     
        @param key
     */
	
	uint32 getContentType(const char* key);
    
    /*! getContentSize(const char* key)
     
        returns the binary size of the content with this key
     
        @param key
     */
    
	uint32 getContentSize(const char* key);

	/*! getAsBool(const char* key)

	returns the interpretation of the entry as a Boolean value
	i.e. if the value is integer/float != 0, string "yes", etc.

	@param key

	*/

	bool getAsBool(const char* key);

    /*! getAsString(const char* key)
     
        returns the user entry as a string regardless of what type it is

        @param key
     
     */
    
	std::string getAsString(const char* key);

	/*! getAsInt(const char* key)

	returns the user entry as an integer regardless of what type it is

	@param key

	*/

	int64 getAsInt(const char* key);

	/*! getAsTime(const char* key)

	returns the user entry as a time regardless of what type it is

	@param key

	*/

	uint64 getAsTime(const char* key);

	/*! getAsFloat(const char* key)

	returns the user entry as a float regardless of what type it is

	@param key

	*/

	float64 getAsFloat(const char* key);

    /*! getTime(const char* key)
     
        returns the user time entry with this key
     
        @param key
     */
    
	uint64 getTime(const char* key);
	
    /*! getString(const char* key)
        
        returns the user string entry with this key
     
        @param key
     */
    
	const char* getString(const char* key);
	
    /*! getString(const char* key, uint32 &size)
     
        returns the user string entry with this key and provides the size
     
        @param key
        @param size
     */
    
	const char* getString(const char* key, uint32 &size);
	
    /*! getInt(const char* key, int64& value)
     
        returns the user integer entry with this key

        @param key
        @param value
     */
    
	bool getInt(const char* key, int64& value);
	
    /*! getDouble(const char* key, double& value)
     
        returns the user float entry with this key
     
        @param key
        @param value
     
     */
    
	bool getDouble(const char* key, double& value);
	
    /*! getFloat(const char* key, float64& value)
        
        returns the user float entry with this key
     
        @param key
        @param value
     
     */
    
	bool getFloat(const char* key, float64& value);
	
    /*! getData(const char* key, uint32& size)
     
        returns the user binary data entry with this key + the size
     
        @param key
        @param size
     */
    
	const char* getData(const char* key, uint32& size);
	
    /*! getDataCopy(const char* key, uint32& size)
     
        returns a copy of the user binary data entry with this key + the size
     
        @param key
        @param size
     
     */
    
	char* getDataCopy(const char* key, uint32& size);
	
    /*! getAttachedMessageCopy(const char* key)
     
        returns a copy of the user message entry with this key
     
        @param key
     
     */
    
	DataMessage* getAttachedMessageCopy(const char* key);

   
    
    
    /*! getTime(const char* key, bool& success)
     
     returns the user time entry with this key / returning the value and success/fail as a parameter
     
     @param key
     @param success
     */
    
	uint64 getTime(const char* key, bool& success);
   
    /*! getString(const char* key)
     
     returns the user string entry with this key / returning the value and success/fail as a parameter
     
     @param key
     @param success
     */
    
    
	const char* getString(const char* key, bool& success);
    
    /*! getString(const char* key, uint32 &size)
     
     returns the user string entry with this key and provides the size / returning the value and success/fail as a parameter
     
     @param key
     @param size
     @param success
     */
    
	const char* getString(const char* key, uint32 &size, bool& success);
    
    /*! getInt(const char* key, int64& value)
     
     returns the user integer entry with this key / returning the value and success/fail as a parameter

     
     @param key
     @param value
     @param success
     */
    
    
	int64 getInt(const char* key, bool& success);
    
    /*! getDouble(const char* key, double& value)
     
     returns the user float entry with this key / returning the value and success/fail as a parameter
     

     
     @param key
     @param value
     @param success
     */
    
	double getDouble(const char* key, bool& success);
    
    /*! getFloat(const char* key, float64& value)
     
     returns the user float entry with this key / returning the value and success/fail as a parameter
     
     @param key
     @param value
     @param success
     
     */
    
	float64 getFloat(const char* key, bool& success);
    
    /*! getData(const char* key, uint32& size)
     
     returns the user binary data entry with this key + the size / returning the value and success/fail as a parameter
     
     @param key
     @param size
     @param success
     */
    
	const char* getData(const char* key, uint32& size, bool& success);
    
    /*! getDataCopy(const char* key, uint32& size)
     
     returns a copy of the user binary data entry with this key + the size / returning the value and success/fail as a parameter

     
     @param key
     @param size
     @param success
     
     */
    
	char* getDataCopy(const char* key, uint32& size, bool& success);
    
    /*! getAttachedMessageCopy(const char* key)
     
     returns a copy of the user message entry with this key / returning the value and success/fail as a parameter

     
     @param key
     @param success
     */
    
	DataMessage* getAttachedMessageCopy(const char* key, bool& success);

    
    /*! getInt(const char* key)
     
     returns the user integer entry with this key / returning the value with no indication of the success/fail except value will be default (0, "", NULL, etc.)
     
     
     @param key
   
     */
    
	int64 getInt(const char* key);
    
    /*! getDouble(const char* key)
     
     returns the user double entry with this key/ returning the value with no indication of the success/fail except value will be default (0, "", NULL, etc.)
     
     
     @param key
     
     
     */
    
	double getDouble(const char* key);
    
   
    /*! getFloat(const char* key)
     
     returns the user float entry with this key/ returning the value with no indication of the success/fail except value will be default (0, "", NULL, etc.)
     
     
     @param key
     
     
     */
    
	float64 getFloat(const char* key);

	// *** setting all of the above, returns success or fail (usually because the message is not valid)
    
    /*! setTime(const char* key, uint64 value)
        
    ???, returns success or fail (usually because the message is not valid)
     
        @param key
        @param value
     
     */
	bool setTime(const char* key, uint64 value);
	
    /*! setString(const char* key, const char* value)
     
     ???, returns success or fail (usually because the message is not valid)
     
     @param key
     @param value
     */
	bool setString(const char* key, const char* value);
	
    /*! setInt(const char* key, int64 value)
     
     ???, returns success or fail (usually because the message is not valid)
     
     @param key
     @param value
     
     */
	bool setInt(const char* key, int64 value);
    
    /*! setDouble(const char* key, double value)
     
     ???, returns success or fail (usually because the message is not valid)
     
     @param key
     @param value
     */
	bool setDouble(const char* key, double value);
	
    /*! setFloat(const char* key, float64 value)
     
     ???, returns success or fail (usually because the message is not valid)
     
     @param key
     @param value
     */
	bool setFloat(const char* key, float64 value);
	
    /*! setData(const char* key, const void* value, uint32 size)
     
     ???, returns success or fail (usually because the message is not valid)
     
     @param key
     @param size
     */
    bool setData(const char* key, const char* value, uint32 size);
	
    /*! setAttachedMessage(const char* key, DataMessage* msg)
     
     ???, returns success or fail (usually because the message is not valid)
     
     @param key
     @param msg
     */
	bool setAttachedMessage(const char* key, DataMessage* msg);


	// Arrays
	// *** Same as above for single values, but now getting and setting entries in arrays
	// myval[0] = val, myval[1] = val, myval[2] = val, etc.

	enum KeyType {NONE, SINGLE, ARRAY, MAP};

	/*! getKeyType(const char* key)

	Return if the key points to a SINGLE, ARRAY or MAP value

	@param key
	*/

	KeyType getKeyType(const char* key);

	/*! isArrayContent(const char* key)

	Check if key variable is an array or not

	@param key
	*/
	bool isArrayContent(const char* key);

	/*! isMapContent(const char* key)

	Check if key variable is a map or not

	@param key
	*/
	bool isMapContent(const char* key);

	/*! isSingleValue(const char* key)

	Check if key variable is not an array nor a map

	@param key
	*/
	bool isSingleValue(const char* key);


	/*!

	Check if key variable exists

	@param key
	*/
	bool hasKey(const char* key);

	/*!

	Check if key variable exists and is a string

	@param key
	*/
	bool hasString(const char* key);

	/*!

	Check if key variable exists and is an integer

	@param key
	*/
	bool hasInteger(const char* key);

	/*!

	Check if key variable exists and is a float

	@param key
	*/
	bool hasFloat(const char* key);

	/*!

	Check if key variable exists and is a time

	@param key
	*/
	bool hasTime(const char* key);

	/*!

	Check if key variable exists and is a data entry

	@param key
	*/
	bool hasData(const char* key);

	/*!

	Check if key variable exists and is a message

	@param key
	*/
	bool hasMessage(const char* key);


    /*! getContentType(int64 i, const char* key)
     
     @param i
     @param key
     */
	uint32 getContentType(int64 i, const char* key);
	
    /*! getContentSize(int64 i, const char* key)
     
     @param i
     @param key
     */
	uint32 getContentSize(int64 i, const char* key);
	 
    /*! getTime(int64 i, const char* key)
     
     
     returns the user time with this key, getting and setting entries in arrays
     
     @param i
     @param key
     */
	uint64 getTime(int64 i, const char* key);
	
    /*! getAsString(int64 i, const char* key)
     
     @param i
     @param key
     */
	std::string getAsString(int64 i, const char* key);
	
	/*! getAsInt(int64 i, const char* key)

	@param i
	@param key
	*/
	int64 getAsInt(int64 i, const char* key);

	/*! getAsTime(int64 i, const char* key)

	@param i
	@param key
	*/
	uint64 getAsTime(int64 i, const char* key);

	/*! getAsFloat(int64 i, const char* key)

	@param i
	@param key
	*/
	float64 getAsFloat(int64 i, const char* key);

	/*! getString(int64 i, const char* key)
     
     @param i
     @param key
     */
	const char* getString(int64 i, const char* key);
	
    /*! getString(int64 i, const char* key, uint32 &size)
     
     @param i
     @param key
     @param size
     */
	const char* getString(int64 i, const char* key, uint32 &size);
	
    /*! getInt(int64 i, const char* key, int64& value)
     
     @param i
     @param key
     @param value
     */
	bool getInt(int64 i, const char* key, int64& value);
	
    /*! getDouble(int64 i, const char* key, double& value)
     
     @param i
     @param key
     @param value
     */
	bool getDouble(int64 i, const char* key, double& value);
    
    /*! getFloat(int64 i, const char* key, float64& value)
     
     @param i
     @param key
     @param value
     */
	bool getFloat(int64 i, const char* key, float64& value);
	
    /*! getInt(int64 i, const char* key, bool& success)
     
     @param i
     @param key
     @param success
     */
	int64 getInt(int64 i, const char* key, bool& success);
    /*! getDouble(int64 i, const char* key, bool& success)
     
     @param i
     @param key
     @param success
     */
	double getDouble(int64 i, const char* key, bool& success);
    /*! getFloat(int64 i, const char* key, bool& success)
     
     @param i
     @param key
     @param success
     */
	float64 getFloat(int64 i, const char* key, bool& success);
    /*! getInt(int64 i, const char* key)
     
     @param i
     @param key
     
     */
	int64 getInt(int64 i, const char* key);
    /*! getDouble(int64 i, const char* key)
     
     @param i
     @param key
     */
	double getDouble(int64 i, const char* key);
    /*! getFloat(int64 i, const char* key)
     
     @param i
     @param key
     */
	float64 getFloat(int64 i, const char* key);
    
    /*! getData(int64 i, const char* key, uint32& size)
     
     @param i
     @param key
     @param size
     */
	const char* getData(int64 i, const char* key, uint32& size);
    
    /*! getDataCopy(int64 i, const char* key, uint32& size)
     
     @param i
     @param key
     @param size
     */
	char* getDataCopy(int64 i, const char* key, uint32& size);
    
    /*! getAttachedMessageCopy(int64 i, const char* key)
     
     @param i
     @param key
    
     */
	DataMessage* getAttachedMessageCopy(int64 i, const char* key);

    /*! setTime(int64 i, const char* key, uint64 value)
     
     @param i
     @param key
     @param value
     */
	
	bool setTime(int64 i, const char* key, uint64 value);
    
    /*! setString(int64 i, const char* key, const char* value)
     
     @param i
     @param key
     @param value
     */
	bool setString(int64 i, const char* key, const char* value);
    
    /*! setInt(int64 i, const char* key, int64 value)
     
     @param i
     @param key
     @param value
     */
	bool setInt(int64 i, const char* key, int64 value);
    
    /*! setDouble(int64 i, const char* key, double value)
     
     @param i
     @param key
     @param value
     */
	bool setDouble(int64 i, const char* key, double value);
    
    /*! setFloat(int64 i, const char* key, float64 value)
     
     @param i
     @param key
     @param value
     */
	bool setFloat(int64 i, const char* key, float64 value);
/*! setData(int64 i, const char* key, const char* value, uint32 size)
     
     @param i
     @param key
     @param value
     @param size
     */
	bool setData(int64 i, const char* key, const char* value, uint32 size);
	//    bool setData(int64 i, const char* key, const void* value, uint32 size);
    
    /*! setAttachedMessage(int64 i, const char* key, DataMessage* msg)
     
     @param i
     @param key
     @param msg
     */
	bool setAttachedMessage(int64 i, const char* key, DataMessage* msg);

	// *** Same as above but reading whole arrays in one go
	std::map<int64, uint64> getTimeArray(const char* key);
    /*! getAsStringArray(const char* key)
     
      @param key
     */
	std::map<int64, std::string> getAsStringArray(const char* key);
	/*! getAsIntArray(const char* key)

	@param key
	*/
	std::map<int64, int64> getAsIntArray(const char* key);
	/*! getAsFloatArray(const char* key)

	@param key
	*/
	std::map<int64, float64> getAsFloatArray(const char* key);
	/*! getStringArray(const char* key)
     
      @param key
     */
	std::map<int64, std::string> getStringArray(const char* key);
    /*! getIntArray(const char* key)
     
      @param key
     
     */
	std::map<int64, int64> getIntArray(const char* key);
    /*!  getDoubleArray(const char* key)
     
      @param key
     */
	std::map<int64, double> getDoubleArray(const char* key);
    /*! getFloatArray(const char* key)
     
      @param key
     */
	std::map<int64, float64> getFloatArray(const char* key);
    /*! getAttachedMessageArray(const char* key)
     
      @param key
     */
	std::map<int64, DataMessage*> getAttachedMessageArray(const char* key);

	
    /*!
     */
	// *** Same as above but setting whole arrays in one go
    /*! setTimeArray(const char* key, std::map<int64, uint64>& map)
     
     @param key
     @param
     @param
     */
	bool setTimeArray(const char* key, std::map<int64, uint64>& map);
    
    /*! setStringArray(const char* key, std::map<int64, std::string>& map)
     
     @param key
     @param
     @param
     */
	bool setStringArray(const char* key, std::map<int64, std::string>& map);
    
    /*! setIntArray(const char* key, std::map<int64, int64>& map)
     
     @param key
     @param
     @param
     */
	bool setIntArray(const char* key, std::map<int64, int64>& map);
    
    /*! setDoubleArray(const char* key, std::map<int64, double>& map)
     
     @param key
     @param
     @param
     */
	bool setDoubleArray(const char* key, std::map<int64, double>& map);
    
    /*! setFloatArray(const char* key, std::map<int64, float64>& map)
     
     @param key
     @param
     @param
     */
	bool setFloatArray(const char* key, std::map<int64, float64>& map);
    
    /*! setAttachedMessageArray(const char* key, std::map<int64, DataMessage*>& map)
     
     @param key
     @param
     @param
     */
	bool setAttachedMessageArray(const char* key, std::map<int64, DataMessage*>& map);

	// Maps
    /*!
     */
    
	// *** Same as for arrays, but now with maps
	// myval["up"] = val, myval["down"] = val, myval["left"] = val, etc.
    
    /*!
     
     returns the type of content with this key as CONSTCHARID, TIMEID, CHARDATAID, INTID, DOUBLEID, etc
     @param idx textual index for the maps
     @param key
     @return contentType as int
     
     */
	uint32 getContentType(const char* idx, const char* key);
    
    /*!
     
     returns the binary size of the content with this key
     @param idx textual index for the maps
     @param key
     @return  binary size of the content
     */
	uint32 getContentSize(const char* idx, const char* key);
    /*!
     
     returns the user time entry with this key
     @param idx textual index for the maps
     @param key
     @return user time
     */
    
	uint64 getTime(const char* idx, const char* key);
    /*!
     
     returns the user entry as a string regardless of what type it is
     @param idx textual index for the maps
     @param key
     @return  user entry as a string
     
     */
	std::string getAsString(const char* idx, const char* key);
	/*!

	returns the user entry as an integer regardless of what type it is
	@param idx textual index for the maps
	@param key
	@return  user entry as a string

	*/
	int64 getAsInt(const char* idx, const char* key);
	/*!

	returns the user entry as a time regardless of what type it is
	@param idx textual index for the maps
	@param key
	@return  user entry as a string

	*/
	uint64 getAsTime(const char* idx, const char* key);
	/*!

	returns the user entry as a float regardless of what type it is
	@param idx textual index for the maps
	@param key
	@return  user entry as a string

	*/
	float64 getAsFloat(const char* idx, const char* key);
	/*!
     
     returns the user string entry with this key
     @param idx textual index for the maps
     @param key
     @return user string entry
     */
	const char* getString(const char* idx, const char* key);
    /*!
     
     returns the user string entry with this key
     @param idx textual index for the maps
     @param key
     @param size the size of the memory chunk for the String
     @return user string entry
     */
	const char* getString(const char* idx, const char* key, uint32 &size);
    /*!
     
     returns the user integer entry with this key
     @param idx textual index for the maps
     @param key
     @param value
     @return true if successfull
     */
    
	bool getInt(const char* idx, const char* key, int64& value);
    /*!
     
     returns the user float entry with this key
     @param idx textual index for the maps
     @param key
     @param value
     @return true if successfull
     
     */
	bool getDouble(const char* idx, const char* key, double& value);
    /*!
     
     returns the user float entry with this key
     @param idx textual index for the maps
     @param key
     @param value
     @return true if successfull
     
     */
	bool getFloat(const char* idx, const char* key, float64& value);
    /*!
     returns the user integer entry with this key
     @param idx textual index for the maps
     @param key
     @param success
     @return  user integer entry
     */
	int64 getInt(const char* idx, const char* key, bool& success);
    /*!
     
     returns the user double entry with this key
     @param idx textual index for the maps
     @param key
     @param success
     @return user double entry
     */
	double getDouble(const char* idx, const char* key, bool& success);
    /*!
     
     returns the user float entry with this key
     @param idx textual index for the maps
     @param key
     @param success
     @return
     */
	float64 getFloat(const char* idx, const char* key, bool& success);
    /*!
     
     returns the user integer entry with this key
     @param idx textual index for the maps
     @param key
     @return user integer entry
     */
	int64 getInt(const char* idx, const char* key);
    /*!
     
     returns the user double entry with this key
     @param idx textual index for the maps
     @param key
     @return user double entry
     
     */
	double getDouble(const char* idx, const char* key);
    /*!
     returns the user float entry with this key
     @param idx textual index for the maps
     @param key
     @return user float entry
     
     */
	float64 getFloat(const char* idx, const char* key);
    /*!
     
     returns the user binary data entry with this key + the size
     @param idx textual index for the maps
     @param key
     @param size
     @return user binary data
     */
	const char* getData(const char* idx, const char* key, uint32& size);
    
    /*!
     
     returns a copy of the user binary data entry with this key + the size
     @param idx textual index for the maps
     @param key
     @param size
     @return copy of the user binary data
     */
	char* getDataCopy(const char* idx, const char* key, uint32& size);
    /*!
     
     returns a copy of the user message entry with this key
     @param idx textual index for the maps
     @param key
     @return copy of the user message entry
     */
	DataMessage* getAttachedMessageCopy(const char* idx, const char* key);
    /*!
     
     sets the user time entry with this key to the value provided
     @param idx textual index for the maps
     @param key
     @param value the value of the time entry
     @return true if successful
     */
	bool setTime(const char* idx, const char* key, uint64 value);
    /*!
     
     sets the user string entry with this key to the value provided
     @param idx textual index for the maps
     @param key
     @param value the new value of the string entry
     @return true if successful
     */
	bool setString(const char* idx, const char* key, const char* value);
    /*!
     
     sets the user integer entry with this key to the value provided
     @param idx textual index for the maps
     @param key
     @param value the new value of the integer entry
     @return true if successful
     */
	bool setInt(const char* idx, const char* key, int64 value);
    /*!
     
     sets the user double entry with this key to the value provided
     @param idx textual index for the maps
     @param key
     @param value the new value of the double entry
     @return true if successful
     
     */
	bool setDouble(const char* idx, const char* key, double value);
    /*!
     
     sets the user float entry with this key to the value provided
     @param idx textual index for the maps
     @param key
     @param value the new value of the float entry
     @return true if successful
     
     */
	bool setFloat(const char* idx, const char* key, float64 value);
    /*!
     
     sets the user binary data entry with this key + the size
     @param idx textual index for the maps
     @param key
     @param value the new value for the data entry
     @param size
     @return true if successful
     */
    bool setData(const char* idx, const char* key, const char* value, uint32 size);
    /*!
     
     sets  the user message entry with this key to the provided message
     @param idx textual index for the maps
     @param key
     @param msg the new message
     @return true if successful
     */
	bool setAttachedMessage(const char* idx, const char* key, DataMessage* msg);

    /*!
     
     returns the user time entry with this key
     @param key
     @return user time
     */
	std::map<std::string, uint64> getTimeMap(const char* key);
    /*!
     
     returns the user entry as a string regardless of what type it is
     @param key
     @return  user entry as a string
     
     */
	std::map<std::string, std::string> getAsStringMap(const char* key);
	/*!

	returns the user entry as an integer map regardless of what type it is
	@param key
	@return  user entry as a string

	*/
	std::map<std::string, int64> getAsIntMap(const char* key);
	/*!

	returns the user entry as a float map regardless of what type it is
	@param key
	@return  user entry as a string

	*/
	std::map<std::string, float64> getAsFloatMap(const char* key);
	/*!
     
     returns the user string entry with this key
     @param key
     @return user string entry
     */
	std::map<std::string, std::string> getStringMap(const char* key);
    /*!
     
     returns the user integer entry with this key
     @param key
     @return user integer entry
     */
	std::map<std::string, int64> getIntMap(const char* key);
    /*!
     
     returns the user double entry with this key
     @param key
     @return user double entry
     
     */
	std::map<std::string, double> getDoubleMap(const char* key);
    /*!
     returns the user float entry with this key
     @param key
     @return user float entry
     
     */
	std::map<std::string, float64> getFloatMap(const char* key);
    /*!
     
     returns a copy of the user message entry with this key
     @param key
     @return copy of the user message entry
     */
	std::map<std::string, DataMessage*> getAttachedMessageMap(const char* key);
    /*!
     
     sets the user time entry with this key
     @param key
     @param map 
     @return true if successful
     */
	bool setTimeMap(const char* key, std::map<std::string, uint64>& map);
    /*!
     
     sets the user string entry with this key 
     @param key
     @param map
     @return true if successful
     */
	bool setStringMap(const char* key, std::map<std::string, std::string>& map);
    /*!
     
     sets the user integer entry with this key 
     @param key
     @param map
     @return true if successful
     */
	bool setIntMap(const char* key, std::map<std::string, int64>& map);
    /*!
     
     sets the user double entry with this key to the value provided
     @param key
     @return true if successful
     
     */
	bool setDoubleMap(const char* key, std::map<std::string, double>& map);
    /*!
     
     sets the user float entry with this key to the value provided
     @param key
     @return true if successful
     
     */
	bool setFloatMap(const char* key, std::map<std::string, float64>& map);
    /*!
     
     sets  the user message entry with this key to the provided message
     @param key
     @param map
     @return true if successful
     */
	bool setAttachedMessageMap(const char* key, std::map<std::string, DataMessage*>& map);

    /*! toJSON()
     
        Returns the JSON representation of the full message including all user entries, arrays and maps - and including the JSON representation of any attached messages
     
     */
    
	
	std::string toJSON();
	
    /*! toXML()
     
        Returns the XML representation of the full message including all user entries, arrays and maps - and including the XML representation of any attached messages
     */
    
	std::string toXML();
	
    /*! getUserEntriesAsString()
     
     Returns the textual representation of the full message including all user entries, arrays and maps - and including the textual representation of any attached messages

     */
    
   
	std::string getUserEntriesAsString();


	// API - inline

	/* getRawData()
		Retrieve the raw data from the message
		@return NULL if the message is not valid
		@return data else
	 */
	char* getRawData() {
		if (data->cid != DATAMESSAGEID) return NULL;
		return (char*)data;
	}

	/* getOrigin()
		Get and return origin of message
		@return NULL if the message is not valid
		@return origin else
	 */

	uint16 getOrigin() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->origin;
	}

	/* getDestination()
		Get and return destination of message
		@return NULL if the message is not valid
		@return destination else
	 */
	uint16 getDestination() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->destination;
	}

	/*! setOrigin(uint16 addr)
		Set origin to address addr and return new origin
		@param addr define origin
		@return true if successful, false otherwise
	 */
	bool setOrigin(uint16 addr) {
		if (data->cid != DATAMESSAGEID) return false;
		data->origin = addr;
		return true;
	}

	/*! setDestination(uint16 addr)
		Set destination to address addr and return new destination
		@param addr define destination
		@return true if successful, false otherwise
	 */
	bool setDestination(uint16 addr) {
		if (data->cid != DATAMESSAGEID) return false;
		data->destination = addr;
		return true;
	}

	/*! getSize()
		Get message size
		Many types of data of any size can be put into a message as user entries; the data will be kept in a single block of memory for efficiency
		@return 0 if the message is not valid
		@return size else
	 */
	uint32 getSize() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->size;
	}

	/*! setMultiple(uint32 from, uint32 to, uint32 tag, uint64 ttl, uint8 policy, uint64 sendtime)
		Set multiple information for a message at the same time
		@param from the sender id
		@param to the receiver id
		@param tag the message's tag id
		@param ttl the message's time-to-live in microseconds
		@param policy the policy id
		@param sendtime the timestamp of the sending of the message
		@return true if successful, false otherwise
	 */
	bool setMultiple(uint32 from, uint32 to, uint32 tag, uint64 ttl, uint8 policy, uint64 sendtime) {
		if (data->cid != DATAMESSAGEID) return false;
		data->from = from;
		data->to = to;
		data->tag = tag;
		data->ttl = ttl;
		data->policy = policy;
		data->sendtime = sendtime;
		return true;
	}

	/*! getTag()
		Retrieve and return message tag id
		Tags can be used to segment data temporally, i.e. a module may only be interested in camera data referencing a specific object or event.
		@return 0 if the message is not valid
		@return tag returns message tag
	 */
	uint32 getTag() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->tag;
	}

	/*! setTag(uint32 tag)

		Sets message tag to tag
		Tags can be used to segment data temporally, i.e. a module may only be interested in camera data referencing a specific object or event.

		@param tag defines message tag

		@return true if successful, false otherwise

	 */
	bool setTag(uint32 tag) {
		if (data->cid != DATAMESSAGEID) return false;
		data->tag = tag;
		return true;
	}

	/*! getReference()
		Get and return message reference id
		@return reference
	 */
	uint64 getReference() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->reference;
	}

	/*! setReference(uint64 ref)
		Set message reference
		@param ref reference
		@return true if successful, false otherwise
	 */
	bool setReference(uint64 ref) {
		if (data->cid != DATAMESSAGEID) return false;
		data->reference = ref;
		return true;
	}

	/*! getMemID()
		Get and return memory ID
		@return memid memory ID
	 */
	uint64 getMemID() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->memid;
	}

	/*! setMemID(uint64 id)
		Set memory ID to id
		@param id memory id
		@return true if successful, false otherwise

	 */
	bool setMemID(uint64 id) {
		if (data->cid != DATAMESSAGEID) return false;
		data->memid = id;
		return true;
	}

	/*! getFrom()
		Get the sender id
		@return from
	 */
	uint32 getFrom() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->from;
	}

	/*! setFrom(uint32 from)

		Set the sender id

		@param from

		@return false if message is not valid


	 */

	bool setFrom(uint32 from) {
		if (data->cid != DATAMESSAGEID) return false;
		data->from = from;
		return true;
	}

	/*! getTo()

		Set the receiver id

		@return to

	 */

	uint32 getTo() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->to;
	}

	/*! setTo(uint32 to)

		Get the receiver id

		@param to

		@return

	 */

	bool setTo(uint32 to) {
		if (data->cid != DATAMESSAGEID) return false;
		data->to = to;
		return true;
	}

	/*! getType()

		Get message type

		@return NOTYPE if message is not valid or if type is not set
		@return type else
	 */

	PsyType getType() {
		PsyType t = NOTYPE;
		if (data->cid != DATAMESSAGEID) return t;
		return data->type;
	}

	/*! setType(PsyType &type)

		Set message type to type

		@param type the message type
		@return false message is not valid
		@return true if success

	 */

	bool setType(PsyType &type) {
		if (data->cid != DATAMESSAGEID) return false;
		data->type = type;
		return true;
	}

	/*! getContextChange()

		Get and return context change entry

		@return NOCONTEXT is message is not valid or if context change is not set

		@return contextchange else

	 */

	PsyContext getContextChange() {
		PsyContext c = NOCONTEXT;
		if (data->cid != DATAMESSAGEID) return c;
		return data->contextchange;
	}

	/*! setContextChange(PsyContext& context)


		Set and return context change entry

		@param context to change to

		@return false if message is not valid

		@return true else

	 */

	bool setContextChange(PsyContext& context) {
		if (data->cid != DATAMESSAGEID) return false;
		data->contextchange = context;
		return true;
	}

	/*! getTTL()

		Gets message's "time to live"
		"TTL is a mechanism that limits the lifespan or lifetime of data in a computer or network"

		Messages in Psyclone 2.0 live for a finite amount of time inside the shared memory,
		If ttl = 0 the message will only be delivered to whoever has subscribed to it and after this seize to exist.

		@return 0 if the message is not valid or the ttl is not set

		@return ttl else

	 */

	uint64 getTTL() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->ttl;
	}

	/*! getEOL()

		Get End of life of message

		@return 0 if message is not valid or the ttl is not set

		@return time that the message will expire

	 */

	uint64 getEOL() {
		if (data->cid != DATAMESSAGEID) return 0;
		if (!data->ttl)
			return 0;
		return data->time + data->ttl;
	}

	/*! setTTL(uint64 ttl)

		Sets time to live for a message in microseconds
		Messages in Psyclone 2.0 live for a finite amount of time inside the shared memory,
		If ttl = 0 the message will only be delivered to whoever has subscribed to it and after this seize to exist.


		@param ttl time-to-live in microseconds

		@return false if message is not valid
		@return true else


	 */

	bool setTTL(uint64 ttl) {
		if (data->cid != DATAMESSAGEID) return false;
		data->ttl = ttl;
		return true;
	}

	/*! setEOL(uint64 eol)

		Calculates and sets the equivalent ttl for the message
		
		@param eol the time at which the message is no longer supposed to exist

		@return false if the message is not valid
		@return true


	 */

	bool setEOL(uint64 eol) {
		if (data->cid != DATAMESSAGEID) return false;
		int64 ttl = eol - data->time;
		if (ttl > 0) {
			data->ttl = (uint64)ttl;
			return true;
		}
		else
			return false;
	}

	/*! getPriority()

		Get message priority
		Messages have a prority that determines their relative order of scheduling, both in the whiteboards and in the modules.

		@return 0 if the message is not valid
		@return priority else

	 */

	uint16 getPriority() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->priority;
	}

	/*! setPriority(uint16 priority)

		Set message priority to priority
		Messages have a prority that determines their relative order of scheduling



		@param priority

		@return false if the message is not valid
		@return true else

	 */

	bool setPriority(uint16 priority) {
		if (data->cid != DATAMESSAGEID) return false;
		data->priority = priority;
		return true;
	}

	/*! getPolicy()

		Gets the policy id of the message

		@return 0 if the message is not valid or if no policy is set
		@return policy id else


	 */

	uint8 getPolicy() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->policy;
	}

	/*! setPolicy(uint8 policy)

		Sets the policy id of the message

		@param policy

		@return false if the message is not valid
		@return true else

	 */

	bool setPolicy(uint8 policy) {
		if (data->cid != DATAMESSAGEID) return false;
		data->policy = policy;
		return true;
	}

	/*! getSendTime()

		Get time message was sent

		@return 0 if the message is not valid or the time was not set
		@return sendtime else

	 */

	uint64 getSendTime() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->sendtime;
	}

	/*! setSendTime(uint64 time)

		Set message sendtime to time

		@param time Sendtime

		@return false if the message is not valid
		@return true else

	 */

	bool setSendTime(uint64 time) {
		if (data->cid != DATAMESSAGEID) return false;
		data->sendtime = time;
		return true;
	}

	/*! getRecvTime()

		Get and return time message was received

		@return 0 if the message is not valid or the time was not set
		@return recvtime else

	 */

	uint64 getRecvTime() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->recvtime;
	}

	/*! setRecvTime(uint64 time)

		Set new receiving time time

		@param time receiving time

		@return false if the message is not valid
		@return true else

	 */

	bool setRecvTime(uint64 time) {
		if (data->cid != DATAMESSAGEID) return false;
		data->recvtime = time;
		return true;
	}

	/*! getCreatedTime()

		Get and return time message was created

		@return false if the message is not valid
		@return time else


	 */

	uint64 getCreatedTime() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->time;
	}

	/*! setCreatedTime(uint64 t)

		Set time message was created to t

		@param t time message was created

		@return 0 if the message is not valid
		@return time=t else

	 */

	bool setCreatedTime(uint64 t) {
		if (data->cid != DATAMESSAGEID) return 0;
		data->time = t;
		return true;
	}

	/*! getStatus()

		Get current message status

		@return 0 if the message is not valid
		@return status else

	 */

	uint16 getStatus() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->status;
	}

	/*! setStatus(uint16 status)

		Set message status

		@param status message status

		@return false if the message is not valid
		@return true else

	 */

	bool setStatus(uint16 status) {
		if (data->cid != DATAMESSAGEID) return false;
		data->status = status;
		return true;
	}

	/*! getSerial()

		Get message serial number

		@return 0 if the message is not valid
		@return serial else
	 */

	uint64 getSerial() {
		if (data->cid != DATAMESSAGEID) return 0;
		return data->serial;
	}

	/*! setSerial(uint64 serial)

		Set message serial number

		@param serial

		@return false if the message is not valid
		@return true else

	 */

	bool setSerial(uint64 serial) {
		if (data->cid != DATAMESSAGEID) return false;
		data->serial = serial;
		return true;
	}

	DataMessageHeader* data;

protected:
	bool setRawData(const char* key, const char* value, uint32 size, uint32 datatype);

	/*! findKey(const char* key)
		Internal function
		@param key

		@return NULL if the message is not valid
		@return src if
		@return NULL else

	*/
	char* findKey(const char* key) {
		if (data->cid != DATAMESSAGEID) return NULL;
		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 src;
			}
			src += ((DataMessageEntryHeader*)src)->size;
		}
		return NULL;
	}

	/*! findEntry(const char* key)

		Internal function

		@param key keyword

		@return NULL if src == NULL
		@return src + sizeof(DataMessageEntryHeader) + strlen(key) + 1 else

	 */

	char* findEntry(const char* key) {
		char* src = findKey(key);
		if (src == NULL) return NULL;
		return src + sizeof(DataMessageEntryHeader) + strlen(key) + 1;
	}

	/*! removeEntry(const char* key)

		Internal function

		@param key keyword

		@return true if src == NULL
		@return true if successfull

	 */

	bool removeEntry(const char* key) {
		char* src = findKey(key);
		if (src == NULL) return true;
		((DataMessageEntryHeader*)src)->cid = UNUSEDID;
		data->userCount--;
		data->userSize += ((DataMessageEntryHeader*)src)->size;
		return true;
	}

	/*! findSpace(uint32 space)

		Internal function

		@param space

		@return NULL if the message is not valid
		@return src
		@return NULL

	 */

	char* findSpace(uint32 space) {
		if (data->cid != DATAMESSAGEID) return NULL;
		char* src = (char*)data + sizeof(DataMessageHeader);
		char* srcEnd = (char*)data + data->size;
		while (src < srcEnd) {
			if ( (((DataMessageEntryHeader*)src)->cid == UNUSEDID) &&
				(((DataMessageEntryHeader*)src)->size >= space) ) {
					return src;
			}
			src += ((DataMessageEntryHeader*)src)->size;
		}
		return NULL;
	}

};

} // namespace cmlabs

#endif //_DATAMESSAGE_H_

