

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  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(_PSYAPI_H_)
#define _PSYAPI_H_

#include "MemoryManager.h"
#include "PsyTime.h"
#include "xml_parser.h"
#include "DataMessage.h"
#include "Subscriptions.h"
#include "PsySpace.h"

#define CRANKAPI_FAILED		1
#define CRANKAPI_INUSE		2
#define CRANKAPI_RUNNING	3
#define CRANKAPI_IDLE		4

#define POST_FAILED			-1
#define POST_NOSPEC			-2
#define POST_OUTOFCONTEXT	-3

#define QUERY_FAILED			1
#define QUERY_TIMEOUT			2
#define QUERY_NAME_UNKNOWN		3
#define QUERY_COMPONENT_UNKNOWN	4
#define QUERY_QUERYFAILED		5
#define QUERY_SUCCESS			6
#define QUERY_NOT_AVAILABLE		7

namespace cmlabs {

#define LOG_COMPONENT		8

typedef std::pair<DataMessage*, DataMessage*> TriggerAndMessage;

class PsyAPI {
	friend class PsySpace;
public:

	static struct PsyType CTRL_SYSTEM_READY;
	static struct PsyType CTRL_PROCESS_INITIALISE;
	static struct PsyType CTRL_PROCESS_GREETING;
	static struct PsyType CTRL_PROCESS_SHUTDOWN;
	static struct PsyType CTRL_CONTEXT_CHANGE;
	static struct PsyType CTRL_SYSTEM_SHUTDOWN;
	static struct PsyType CTRL_SYSTEM_SHUTTINGDOWN;
	static struct PsyType CTRL_TRIGGER;
	static struct PsyType CTRL_QUERY;
	static struct PsyType CTRL_QUERY_REPLY;
	static struct PsyType CTRL_PULLCOMPONENTDATA;
	static struct PsyType CTRL_CREATECUSTOMPAGE;
	static struct PsyType CTRL_ADDSUBSCRIPTION;
	static struct PsyType CTRL_INTERSYSTEM_QUERY;
	static struct PsyType CTRL_INTERSYSTEM_QUERY_REPLY;

	// ***************** Constructors *****************
	// Create and destroy resources

	/*!  Constructor from a PsySpace

		@param space The space in which the PsyAPI shall be created
	*/
	PsyAPI(PsySpace* space);
	/*! Destructor for the PsyAPI

	*/
	~PsyAPI();

	/*! Internal use only

	*/
	static PsyAPI* fromPython(unsigned long long ptr);
	static const char* fromPythonAddressOf(unsigned long long ptr);

	/*! Internal use only

	*/
	bool setAutoDelete(bool autodel);

	// ***************** System & Status *****************
	// All system calls
	// Get or set status info

	/*! Internal use only

	*/
	bool isRunning();

	/*! 
		Check to see if crank should exit, needs to be checked regularly

		@return true if the crank should continue

	*/
	bool shouldContinue();
	/*!
		Get the name of the module written into the memory of name and return size
		@param name the chunk of memory that the name of the module will be written into
		@param maxSize the size of the memory chunk of tha name parameter
		@return true if module with that name exists and the size of the name is smaller than maySize
	*/
	bool getModuleName(char* name, uint32 maxSize);
	/*!
	   Get the base dir that Psyclone is running from
	   @return the base dir as a string
	*/
	std::string getCommandlineBasedir();
	/*! Internal use only

	*/
	bool setCommandlineBasedir(const char* cmdlineBasedir);
	/*! Get the module name

		@return module name as String

	*/
	std::string getModuleName();
	/*! Get the name of another module by id
	@param id the id of the other module
	@return module name as String

	*/
	std::string getOtherModuleName(uint32 id);
	/*! Get the size of the input queue, i.e. how many unprocessed trigger messages waiting to be processed

	@return size of the input queue

	*/
	uint32 getInputQueueSize();
	/*! Get textual representation of the type
	@param type type as PsyType object
	@return type as string

	*/
	std::string typeToText(PsyType type);
	/*! Get textual representation of the context
	@param context context as PsyContext object
	@return context as string

	*/
	std::string contextToText(PsyContext context);
	/*! Internal use only

	*/
	bool getCurrentScriptLanguage(char* language, uint32 maxSize);
	/*! Internal use only

	*/
	bool getCurrentScript(char* script, uint32 maxSize);
	/*! Internal use only

	*/
	bool getCurrentScriptFilename(char* filename, uint32 maxSize);
	/*! Internal use only

	*/
	std::string getCurrentScriptLanguage();
	/*! Internal use only

	*/
	std::string getCurrentScript();
	/*! Internal use only

	*/
	std::string getCurrentScriptFilename();
	/*! Get a list of post names currently active - i.e. the post names that can be used right now
	@return the post names as a list of strings

	*/
	std::set<std::string> getCurrentPostNames();

	/*! Check to see if the post name is currently active - i.e. can this post be used right now
	@return true if the post name is active, otherwise false

	*/
	bool hasCurrentPostName(const char* name);

	// ***************** Subscription *****************
	// Get or delete current subscriptions
	// Create new subscription
	// *** Not implemented yet



	// ***************** Tags *****************
	// Create, destroy or get info about tags
	// *** Not implemented yet




	// ***************** Messaging *****************
	/*!
	This function waits for the next trigger message to arrive and if it did within the timeout (ms)
	the message is returned.
	The message is owned by the system and should never be deleted by the crank.
	If no message arrives within the timeout NULL is returned.

	@param ms the timeout
	@return the message or NULL if none arrives

	*/
	DataMessage* waitForNewMessage(uint32 ms);


	/*! Get the name of the current trigger, just retrieved using waitForNewMessage()
	@return Triggername as String

	*/
	std::string getCurrentTriggerName();

	/*! Get the context of the current trigger, just retrieved using waitForNewMessage()
	@return Context as PsyContext

	*/
	PsyContext getCurrentTriggerContext();


	/*!
	This function waits for the next trigger message to arrive and if it did within the timeout (ms)
	the message is returned and triggerName indicates the name of the trigger from the spec.
	The message is owned by the system and should never be deleted by the crank.
	If no message arrives within the timeout NULL is returned.

	@param ms the timeout
	@param triggerName  the name of the trigger from the spec returned
	@return the message or NULL if none arrives

	*/
	DataMessage* waitForNewMessage(uint32 ms, const char* &triggerName);
	/*!
	Get current message receive time

	@return current message receive time

	*/

	uint64 getCurrentMessageReceiveTime();

	// Post output messages
	/**
	The crank uses this function to post messages. The actual message posted will depend on the spec post entries. 
	If no postName is provided then all active post entries will be used and one copy of the message posted per post entry.
	If no message is provided an empty message will be used instead. If no active posts match zero or a negative integer is returned,
	otherwise the number of messages sent is returned. Negative values indicate 

	POST_FAILED -1   Error occurred while trying to post the message 

	POST_NOSPEC -2   The crank tried to post a message before a trigger arrived 

	POST_OUTOFCONTEXT -3   The crank is no longer active because the context has changed and is no longer active 

	@param postName name of the Post. If none is provided then all active post entries will be used and one copy of the message posted per post entry.
	@param msg message. If none is provided an empty message will be used instead.
	@return number of messages sent

	*/
	int32 postOutputMessage(const char* postName = NULL, DataMessage* msg = NULL);

	// Post output messages
	/**
	The crank uses this function to post messages. The actual message posted will depend on the spec post entries.
	If no postName is provided then all active post entries will be used and one copy of the message posted per post entry.
	If no message is provided an empty message will be used instead. If no active posts match zero or a negative integer is returned,
	otherwise the number of messages sent is returned. Negative values indicate

	POST_FAILED -1   Error occurred while trying to post the message

	POST_NOSPEC -2   The crank tried to post a message before a trigger arrived

	POST_OUTOFCONTEXT -3   The crank is no longer active because the context has changed and is no longer active

	@param msgType msg type of the Post. If none is provided then all active post entries will be used and one copy of the message posted per post entry.
	@param msg message. If none is provided an empty message will be used instead.
	@return number of messages sent

	*/
	int32 postOutputMessage(PsyType msgType, DataMessage* msg = NULL);


	// ***************** Signals *****************
	/**
	This function call triggers the sending of a signal by name. If no message is provided an empty one will be created.

	@param name name of the signal to be sent
	@param msg message to be sent, empty message if NULL
	@return true if successful

	*/
	bool emitSignal(const char* name, DataMessage* msg = NULL);
	/*!
	This function waits for the next signal message to arrive and if it did within the timeout (ms) the message is returned
	and name indicates the name of the signal from the spec.
	The message is owned by the system and should never be deleted by the crank.
	If no message arrives within the timeout NULL is returned. If lastReceivedTime is set to a time value signals sent before this time are skipped,
	if not the next unread signal is returned.

	@param name name of the signal that is waited for
	@param timeout time to be waited for signal to arrive
	@param lastReceivedTime signals sent before this time are skipped
	@return true if successful

	*/
	DataMessage* waitForSignal(const char* name, uint32 timeout, uint64 lastReceivedTime = 0);


	/*!
	This function adds triggers and posts to an existing registration

	@param xml <registration name="modulename"><trigger.../>...<post.../></registration>
	@return true if successful

	*/
	bool addSubscription(const char* xml);


	// ***************** PsyProbe plugins *****************
	/*!
	Add a custom module view tab for the PsyProbe web interface by providing a template file
	- this file will need to use PsyProbe javascript to work - see the PsyProbe documentation for more info.

	@param name name of the custom module view tab
	@param templateURL The path to the template file
	@return true if successful

	*/
	bool addPsyProbeCustomView(const char* name, const char* templateURL);
	/*!
	Remove a custom module view tab for the PsyProbe web interface

	@param name name of the custom view
	@return true if removal was successful


	*/
	bool removePsyProbeCustomView(const char* name) {
		return addPsyProbeCustomView(name, "");
	}

	// ***************** Own Data *****************
	// Load, save or delete own persistent data
	/*!
	The crank can use this function to store chunks of data centrally so it doesn't have to do it. 
	This means that if the crank exits (or crashes) the data will still be available when it is triggered again.

	@param name name of the data chunk
	@oaram data the data to be stored
	@param size memory size of the data
	@return true if successful


	*/

	bool setPrivateData(const char* name, const char* data, uint64 size, const char* mimetype = NULL) {
		return space->manager->componentMemory->setPrivateData(currentCompID, name, data, size, mimetype);
	}
	/*!
	This returns the size of the private data chunk previously saved by the crank.

	@param name name of the data chunk
	@return size of the private data chunk


	*/
	uint64 getPrivateDataSize(const char* name) {
		return space->manager->componentMemory->getPrivateDataSize(currentCompID, name);
	}
	/*!
	Returns a new data chunk copy of a private entry, with the size written into size. 

	@param name name of the data chunk
	@param size memory size of the data returned
	@return  new data chunk copy of a private entry


	*/
	char* getPrivateDataCopy(const char* name, uint64 &size) {
		return space->manager->componentMemory->getPrivateDataCopy(currentCompID, name, size);
	}
	/*!
	Reads a private chunk from the system into existing data space, maximum size is maxSize. 

	@param name name of the data chunk
	@param data pointer to an already allocated memory chunk
	@param maxSize maximum size of the already allocated memory chunk
	@return  true if reading was successful


	*/
	bool getPrivateData(const char* name, char* data, uint64 maxSize) {
		return space->manager->componentMemory->getPrivateData(currentCompID, name, data, maxSize);
	}
	/*!
	Deletes a private data chunk by name.

	@param name the name of the chunk to be deleted
	@return  true if deletion was successful


	*/
	bool deletePrivateData(const char* name) {
		return space->manager->componentMemory->deletePrivateData(currentCompID, name);
	}

	// ***************** Own Parameters *****************
	// Get, set, reset, create or destroy own parameters
	/*!
	Creates a new string parameter

	@param name name of the parameter
	@param val value of the parameter
	@param defaultValue default value when resetting parameter, NULL if val should be used
	@return true if creation was successful


	*/
	bool createParameter(const char* name, const char* val, const char* defaultValue = NULL) {
		return space->manager->componentMemory->createParameter(currentCompID, name, val, defaultValue);
	}
	/*!
	Creates a new string list parameter with room for count entries

	@param name name of the parameter
	@param val value array of the parameter, separed by binary \0
	@param count number of entries in the array
	@param defaultIndex an int value that sets the default index in the list
	@return true if creation was successful


	*/
	bool createParameter(const char* name, const char* val, uint32 count, uint32 defaultIndex) {
		return space->manager->componentMemory->createParameter(currentCompID, name, val, count, defaultIndex);
	}
	/*!
	Creates a new string parameter with a list of values

	@param name name of the parameter
	@param values vector of values of the parameter
	@param defaultValue default value or NULL for the first entry
	@return true if creation was successful


	*/
	bool createParameter(const char* name, std::vector<std::string> values, const char* defaultValue = NULL) {
		return space->manager->componentMemory->createParameter(currentCompID, name, values, defaultValue);
	}
	/*!
	Creates a new integer list parameter with room for count entries 

	@param name name of the parameter
	@param val array of values of the parameter
	@param count number of entries in the array
	@param defaultIndex an int value that sets the default index in the list
	@return true if creation was successful


	*/
	bool createParameter(const char* name, int64* val, uint32 count, uint32 defaultIndex) {
		return space->manager->componentMemory->createParameter(currentCompID, name, val, count, defaultIndex);
	}
	/*!
	Creates a new String parameter with list of integer values (?)

	@param name name of the parameter
	@param values vector with values of the parameter
	@param defaultValue default as int
	@return true if creation was successful


	*/
	bool createParameter(const char* name, std::vector<std::string> values, int64 defaultValue) {
		return space->manager->componentMemory->createParameter(currentCompID, name, values, defaultValue);
	}
	/*!
	Creates a new integer parameter with list of values

	@param name name of the parameter
	@param values vector of values of the parameter
	@param defaultValue default is 0
	@return true if creation was successful


	*/
	bool createParameter(const char* name, std::vector<int64> values, int64 defaultValue = 0) {
		return space->manager->componentMemory->createParameter(currentCompID, name, values, defaultValue);
	}
	/*!
	Creates a new float parameter

	@param name name of the parameter
	@param val array of value of the parameter
	@param defaultIndex an int value that sets the default index in the list
	@return true if creation was successful


	*/
	bool createParameter(const char* name, float64* val, uint32 count, uint32 defaultIndex) {
		return space->manager->componentMemory->createParameter(currentCompID, name, val, count, defaultIndex);
	}
	/*!
	Creates a new string parameter with list of float values (?)

	@param name name of the parameter
	@param values vector of values of the parameter
	@param defaultValue float value as default
	@return true if creation was successful


	*/
	bool createParameter(const char* name, std::vector<std::string> values, float64 defaultValue) {
		return space->manager->componentMemory->createParameter(currentCompID, name, values, defaultValue);
	}
	/*!
	Creates a new float parameter with list of float values (?)

	@param name name of the parameter
	@param values vector of values of the parameter
	@param defaultValue default is 0
	@return true if creation was successful


	*/
	bool createParameter(const char* name, std::vector<float64> values, float64 defaultValue = 0) {
		return space->manager->componentMemory->createParameter(currentCompID, name, values, defaultValue);
	}
	/*!
	Creates a new integer parameter

	@param name name of the parameter
	@param val value of the parameter
	@param min the minimum value
	@param max the maximum value
	@interval interval limit, amount to jump on every tweak
	@return true if creation was successful


	*/
	bool createParameter(const char* name, int64 val, int64 min = 0, int64 max = 0, int64 interval = 0) {
		return space->manager->componentMemory->createParameter(currentCompID, name, val, min, max, interval);
	}
	/*!
	Creates a new float parameter with min, max and interval limits for allowed values

	@param name name of the parameter
	@param val value of the parameter
	@param min minimum value
	@param max maximum value
	@interval interval limit, amount to jump on every tweak
	@return true if creation was successful


	*/
	bool createParameter(const char* name, float64 val, float64 min = 0, float64 max = 0, float64 interval = 0) {
		return space->manager->componentMemory->createParameter(currentCompID, name, val, min, max, interval);
	}
	/*!
	Checks if a named parameter exists

	@param name name of the parameter
	@return  true if it exists, false otherwise


	*/
	bool hasParameter(const char* name) {
		return space->manager->componentMemory->hasParameter(currentCompID, name);
	}
	/*!
	Deletes a named parameter

	@param name name of the parameter
	@return true if deletion was successful


	*/
	bool deleteParameter(const char* name) {
		return space->manager->componentMemory->deleteParameter(currentCompID, name);
	}
	/*!
	Gets the parameter type

	#define PARAM_STRING 1 

	#define PARAM_INTEGER 2 

	#define PARAM_FLOAT 3 

	#define PARAM_STRING_COLL 4 

	#define PARAM_INTEGER_COLL 5 

	#define PARAM_FLOAT_COLL 6 

	#define PARAM_TYPE_COLL 7

	@param name name of the parameter
	@return  1 for String, 2 for int, 3 for float, 4 for String Collection, 5 for int collection, 6 for florat collection, 7 for type collection


	*/
	uint8 getParameterDataType(const char* name) {
		return space->manager->componentMemory->getParameterDataType(currentCompID, name);
	}
	/*!
	Return the amount of memory in bytes used by the parameter

	@param name name of the parameter
	@return  amount of memory in bytes


	*/
	uint32 getParameterValueSize(const char* name) {
		return space->manager->componentMemory->getParameterValueSize(currentCompID, name);
	}
	/*!
	Read string parameter into existing data chunk val, maximum size maxSize. 

	@param name name of the parameter
	@param val value of the parameter
	@param maxSize maximal size of the parameter to be read
	@return  true if reading was successful


	*/
	bool getParameter(const char* name, char* val, uint32 maxSize) {
		return space->manager->componentMemory->getParameter(currentCompID, name, val, maxSize);
	}
	/*!
	Read and return value of parameter by name

	@param name name of the parameter
	@return  value of the paramer


	*/
	std::string getParameterString(const char* name) {
		return space->manager->componentMemory->getParameterString(currentCompID, name);
	}
	/*!
	Read and interpret value of parameter by name as boolean
	True: String 'Yes', Integer and Float non-zero
	False: String not 'Yes', Integer and Float zero

	@param name name of the parameter
	@return  boolean interpretation of value of the paramer


	*/
	bool getParameterAsBool(const char* name) {
		return space->manager->componentMemory->getParameterAsBool(currentCompID, name);
	}
	/*!
	Read and return value of parameter by name

	@param name name of the parameter
	@return  value of the paramer


	*/
	int64 getParameterInt(const char* name) {
		return space->manager->componentMemory->getParameterInt(currentCompID, name);
	}
	/*!
	Read and return value of parameter by name

	@param name name of the parameter
	@return  value of the paramer


	*/
	float64 getParameterFloat(const char* name) {
		return space->manager->componentMemory->getParameterFloat(currentCompID, name);
	}
	/*!
	Read integer parameter value

	@param name name of the parameter
	@param val value of the parameter
	@return  true if reading was successful


	*/
	bool getParameter(const char* name, int64& val) {
		return space->manager->componentMemory->getParameter(currentCompID, name, val);
	}
	/*!
	Read float parameter value

	@param name name of the parameter
	@param val value of the parameter
	@return true if reading was successful


	*/
	bool getParameter(const char* name, float64& val) {
		return space->manager->componentMemory->getParameter(currentCompID, name, val);
	}
	/*!
	Set string parameter value 

	@param name name of the parameter
	@param val value of the parameter
	@return true if successful


	*/
	bool setParameter(const char* name, const char* val) {
		return space->manager->componentMemory->setParameter(currentCompID, name, val);
	}
	/*!
	Set integer parameter value

	@param name name of the parameter
	@param val value of the parameter
	@return  true if successful


	*/
	bool setParameter(const char* name, int64 val) {
		return space->manager->componentMemory->setParameter(currentCompID, name, val);
	}
	/*!
	Set float parameter value 

	@param name name of the parameter
	@param val value of the parameter
	@return true if successful


	*/
	bool setParameter(const char* name, float64 val) {
		return space->manager->componentMemory->setParameter(currentCompID, name, val);
	}
	/*!
	Reset parameter to its default (or initial) value

	@param name name of the parameter
	@return true if successful


	*/
	bool resetParameter(const char* name) {
		return space->manager->componentMemory->resetParameter(currentCompID, name);
	}
	/*!
	Step up or down list or range parameter value.
	If list steps to next or previous value, if range adds or subtracts interval while staying in the min-max range. 

	@param name name of the parameter
	@param tweak number of steps to tweak, positive is upwards, negative is downwards
	@return true if successful


	*/
	bool tweakParameter(const char* name, int32 tweak) {
		return space->manager->componentMemory->tweakParameter(currentCompID, name, tweak);
	}

	// ***************** Other Modules' Parameters *****************
	// Get, set or reset other module's parameters
	// *** Not implemented yet



	// ***************** Queries *****************
	// Query a Data storage devices (Whiteboard, Stream, Catalogue) for data
	// Named queries in PsySpec may be used
	/*!
	Used by a module to retrieve messages from a whiteboard. The retrieve details are provided in the module spec by name. 
	maxcount and maxage can be provided to add to the spec details. 

	@param result a bucket parameter filled by the function. A list of messages.
	@param name name of the messages to be retrieved
	@param maxcount the maximal number of messages to be retrieved
	@param maxage the maximal age of the messages to be retrieved
	@param timeout if no messages are retrieved after this time, NULL is returned (?)
	@return  the messages from the whiteboard


	*/
	uint8 retrieve(std::list<DataMessage*> &result, const char* name, uint32 maxcount = 0, uint32 maxage = 0, uint32 timeout = 5000);
	/*!
	Used by a module to retrieve messages from a whiteboard. The retrieve details are provided in the module spec by name.
	maxcount and maxage can be provided to add to the spec details.

	@param result a bucket parameter filled by the function. A list of messages.
	@param name name of the whiteboard defined in the PsySpec
	@param maxcount the maximal number of messages to be retrieved
	@param maxage the maximal age of the messages to be retrieved
	@param timeout if no messages are retrieved after this time, NULL is returned (?)
	@return  the messages from the whiteboard


	*/
	uint8 retrieveTimeParam(std::list<DataMessage*> &result, const char* name, uint64 startTime, uint64 endTime = 0, uint32 maxcount = 0, uint32 maxage = 0, uint32 timeout = 5000);
	/*!
	Used by a module to retrieve messages from a whiteboard. The retrieve details are provided in the module spec by name. 
	startTime and endTime can be provided to add to the spec details.

	@param result a bucket parameter filled by the function. A list of messages.
	@param name name of the whiteboard defined in the PsySpec
	@param startString this String marks the beginning of the selection of Strings that the functions shall return
	@param endString this String marks the end of the selection of Strings that the functions shall return
	@param maxcount the maximal number of messages to be retrieved
	@param maxage the maximal age of the messages to be retrieved
	@param timeout if no messages are retrieved after this time, NULL is returned (?)
	@return  the messages from the whiteboard


	*/
	uint8 retrieveStringParam(std::list<DataMessage*> &result, const char* name, const char* startString, const char* endString = NULL, uint32 maxcount = 0, uint32 maxage = 0, uint32 timeout = 5000);
	/*!
	Used by a module to retrieve messages from a whiteboard. The retrieve details are provided in the module spec by name. 
	startInteger and endInteger can be provided to add to the spec details.

	@param result a bucket parameter filled by the function. A list of messages.
	@param name name of the whiteboard defined in the PsySpec
	@param startInteger this value marks the beginning of the selection of values that the functions shall return
	@param endInteger this value marks the end of the selection of values that the functions shall return
	@param maxcount the maximal number of messages to be retrieved
	@param maxage the maximal age of the messages to be retrieved
	@param timeout if no messages are retrieved after this time, NULL is returned (?)
	@return  the messages from the whiteboard


	*/
	uint8 retrieveIntegerParam(std::list<DataMessage*> &result, const char* name, int64 startInteger, int64 endInteger = INT64_NOVALUE, uint32 maxcount = 0, uint32 maxage = 0, uint32 timeout = 5000);
	/*!
	Used by a module to retrieve messages from a whiteboard. The retrieve details are provided in the module spec by name.
	maxcount and maxage can be provided to add to the spec details.

	@param result a bucket parameter filled by the function. A list of messages.
	@param name name of the whiteboard defined in the PsySpec
	@param startFloat this value marks the beginning of the selection of values that the functions shall return
	@param endFloat this value marks the end of the selection of values that the functions shall return
	@param maxcount the maximal number of messages to be retrieved
	@param maxage the maximal age of the messages to be retrieved
	@param timeout if no messages are retrieved after this time, NULL is returned (?)
	@return the messages from the whiteboard


	*/
	uint8 retrieveFloatParam(std::list<DataMessage*> &result, const char* name, float64 startFloat, float64 endFloat = FLOAT64_NOVALUE, uint32 maxcount = 0, uint32 maxage = 0, uint32 timeout = 5000);
	/*!
	Used by a module to retrieve messages from a whiteboard. The retrieve details are provided in the module spec by name. 

	@param result a bucket parameter filled by the function. A list of messages.
	@param spec the module spec with retrieve details
	@param timeout if no messages are retrieved after this time, NULL is returned (?)
	@return  the messages from the whiteboard


	*/
	uint8 retrieve(std::list<DataMessage*> &result, RetrieveSpec* spec, uint32 timeout = 5000);

	/*!
	Used by a module to send a query to another module or catalog by name. The query details are provided in the module spec by name. 

	@param result a bucket parameter filled by the function. 
	@param resultsize this value limits the size of the answer to the query
	@param query the actual query sent to the catalog
	@param name name of the query defined in the PsySpec
	@param operation specify the custom operation by name (example could be 'read' or 'write' for the FileCatalog)
	@param data provide optional data to send to as part of the query (example could be the data to write to a file for the FileCatalog)
	@param datasize size of the optional data
	@param timeout if no reply is retrieved after this time, NULL is returned
	@return  the status of the reply from the catalog


	*/
	uint8 queryCatalog(char** result, uint32 &resultsize, const char* name, const char* query, const char* operation = NULL, const char* data = NULL, uint32 datasize = 0, uint32 timeout = 5000);

	/*!
	Used by a module to send a query to another module or catalog by name. The query details are provided in the message parameter and will not require or use any data from the PsySpec.

	@param result the reply message, if one is returned.
	@param name name of the query defined in the PsySpec
	@param msg the msg to be sent to the catalog as the query input
	@param timeout if no reply is retrieved after this time, NULL is returned
	@return  the status of the reply from the catalog


	*/
	uint8 queryCatalog(DataMessage** resultMsg, const char* name, DataMessage* msg, uint32 timeout = 5000);

	/*!
	Used by a module to reply to an incoming query by id. Status can be 

	#define QUERY_FAILED 1 

	#define QUERY_TIMEOUT	2 

	#define QUERY_NAME_UNKNOWN 3 

	#define QUERY_COMPONENT_UNKNOWN 4 

	#define QUERY_QUERYFAILED 5 

	#define QUERY_SUCCESS 6 

	#define QUERY_NOT_AVAILABLE 7 

	Binary reply data of size size can be added and a count can indicate the number of entries in the data chunk.


	@param id id of the incoming query  to reply to
	@param status see description
	@param data optional binary data to reply with
	@param size size of optional binary data
	@param count optional resulting count for operation, if appropriate
	@return  true if reply was successful


	*/
	bool queryReply(uint32 id, uint8 status, char* data, uint32 size, uint32 count);
	/*!
	Used by a module to send a message as a reply to an incoming query

	@param id id of the incoming query to reply to
	@param status see description of queryReply(uint32 id, uint8 status, char* data, uint32 size, uint32 count);
	@param msg 
	@return  true if reply was successful


	*/
	bool queryReply(uint32 id, uint8 status, DataMessage* msg = NULL);

	// ***************** Performance *****************
	// For querying about performance
	// *** Not implemented yet



	// ***************** Monitoring *****************
	// For providing custom data to monitoring tools
	// *** Not implemented yet



	// ***************** Supervisor *****************
	// API for supervisor modules
	// *** Not implemented yet


	// *** Adds the text to the log file and prints to the system console if level is below threshold for logging
	// *** Uses the same formats and parameters like printf(const char *formatstring, ... )
	bool logPrint(uint8 level, const char *formatstring, ... );

private:
	PsySpace* space;
	utils::Mutex apiMutex;
	uint64 startedRunning;
	bool shouldContinueRunning;
	uint32 currentCrankID;
	uint32 currentCompID;
	uint32 msgReceivedCount;
	uint32 msgInputCount;
	uint32 msgSentCount;
	uint32 msgPostedCount;
	uint64 lastCPUTicks;

	std::queue<TriggerAndMessage> inputQueue;
	utils::Semaphore inputQueueSemaphore;

	bool autoDelete;
	DataMessage* currentTriggerMsg;
	DataMessage* currentMsg;
	DataMessage* currentSignalMsg;
	TriggerSpec* currentTriggerSpec;
	char currentTriggerName[MAXKEYNAMELEN+1];
	char commandlineBasedir[MAXCOMMANDLINELEN + 1];

	// Only called by PsySpace
	/*! Internal use only

	*/
	uint8 addInputTrigger(uint32 crankID, uint32 compID, DataMessage* trigger, DataMessage* msg);
	/*! Internal use only

	*/
	bool begin();
	/*! Internal use only

	*/
	bool finish();
	/*! Internal use only

	*/
	bool stop();
};

} // namespace cmlabs

#endif //_PSYAPI_H_

