

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of PSYCLONE 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/
//_/_/
//_/_/  PSYCLONE 2.0 is released under the GNU Lesser General Public License 
//_/_/  (LGPL) version 3.0, and is subject to the following
//_/_/  
//_/_/  - 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. 
//_/_/    
//_/_/  A commercial license for PSYCLONE 2.0 is also available to 
//_/_/  any interested party from the copyright holder.
//_/_/  
//_/_/  You can redistribute this copy of PSYCLONE 2.0 and/or modify it under 
//_/_/  the terms of the GNU General Public License as published by the Free 
//_/_/  Software Foundation, either version 3 of the License, or (at your 
//_/_/  option) any later version.
//_/_/  
//_/_/  You should have received a copy of the GNU General Public License
//_/_/  and the GNU Lesser General Public License along with PSYCLONE 2.0.  
//_/_/  If not, see <http://www.gnu.org/licenses/>.
//_/_/  
//_/_/  PSYCLONE 2.0 is distributed in the hope that it will be useful,
//_/_/  but WITHOUT ANY WARRANTY; without even the implied warranty of
//_/_/  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//_/_/  GNU General Public License for more details.
//_/_/
//_/_/  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(_TASKMANAGERCATALOG_H_)
#define _TASKMANAGERCATALOG_H_

#include "PsyAPI.h"
#include "jsmn.h"

namespace	cmlabs {

extern "C" {
	DllExport int8 TaskManagerCatalog(PsyAPI* api);
}

static std::string TaskEventTypeNames[] = {
	"none",
	"fail", "success", "complete"
	"stop", "timeout", "start",
	"next", "previous", "restart", "startnow" };

enum TaskEventType {
	EVENT_NONE = 0,
	EVENT_FAIL = 1, EVENT_SUCCESS = 2, EVENT_COMPLETE = 3,
	EVENT_STOP = 4, EVENT_TIMEOUT = 5, EVENT_START = 6,
	EVENT_NEXT = 7, EVENT_PREVIOUS = 8, EVENT_RESTART = 9,
	EVENT_STARTNOW = 10
};
#define EVENT_COUNT 11


class TaskEntry;
struct TaskQueueTrigger {
	uint64 time;
	uint32 delay;
	std::string msgType;
	TaskEventType triggerType;
	TaskEntry* task;
	bool setAsTimer(uint64 t, uint32 delayMS, TaskEventType type, TaskEntry* aTask) {
		msgType = ""; time = t; delay = delayMS; triggerType = type; task = aTask; return true;
	}
	bool setAsMsgTrigger(std::string aMsgType, TaskEventType type, TaskEntry* aTask) {
		msgType = aMsgType; time = delay = 0; triggerType = type; task = aTask; return true;
	}
	bool equals(const TaskQueueTrigger& other) {
		// Note: if timed trigger don't bother comparing time, just match
		//       and if not timed trigger, just match msgType
		return ((task == other.task) && (triggerType == other.triggerType) && (msgType == other.msgType));
	}
};

class TaskEntry {
public:
	TaskEntry(PsyAPI* api) { this->api = api; reset(); }
	~TaskEntry() { cleanup(); }
	bool reset() {
		id = 0;
		name.clear();
		description.clear();
		timeoutMS = 0;
		delayStartMS = 0;
		delayBetweenMS = 0;
		currentTask = -1;
		parentTask = nextTask = previousTask = NULL;
		return true;
	}
	bool cleanup() {
		std::vector<TaskEntry*>::iterator i = subTasks.begin(), e = subTasks.end();
		while (i != e) {
			delete(*i);
			i++;
		}
		return reset();
	}
	bool isActive() { return currentTask >= 0; }
	bool isActiveSelf() { return currentTask == 0; }
	bool isActiveSubtask() { return currentTask > 0; }

	//TaskEventType timerEvent(PsyAPI* api, std::map<uint64, TaskEntry*> &timeQueue, std::map<PsyType, TaskQueueTrigger> &triggerList);
	//TaskEventType triggerEvent(TaskEventType triggerType, PsyAPI* api, std::map<uint64, TaskEntry*> &timeQueue, std::map<PsyType, TaskQueueTrigger> &triggerList);

	bool handleTrigger(TaskEventType trigger, std::list<std::string> &posts,
		std::list<TaskQueueTrigger> &newTriggers, std::list<TaskEntry*> &oldTasks);

	//bool handleStart(std::list<std::string> &posts, TaskQueueTrigger &trigger);
	//bool handleTimeout(std::list<std::string> &posts, TaskQueueTrigger &trigger);
	//bool handleSuccess(std::list<std::string> &posts, TaskQueueTrigger &trigger);
	//bool handleFail(std::list<std::string> &posts, TaskQueueTrigger &trigger);
	//bool handleStop(std::list<std::string> &posts, TaskQueueTrigger &trigger);
	//bool handleRestart(std::list<std::string> &posts, TaskQueueTrigger &trigger);

	//bool handleNext(std::list<std::string> &posts, TaskQueueTrigger &trigger);
	//bool handlePrevious(std::list<std::string> &posts, TaskQueueTrigger &trigger);

	bool log(std::string text);
	bool fromJSON(const char* json, jsmntok_t* tokens, int tokenCount, int parent,
		std::list<std::string> &allTriggers, std::list<std::string> &allPosts);
	std::string toJSON();
	std::string toJSONStatus();

	PsyAPI *api;
	uint64 id;
	std::string name;
	std::string description;
	uint32 timeoutMS;
	uint32 delayStartMS;
	uint32 delayBetweenMS;

	std::list<std::string> msgTriggers[EVENT_COUNT];
	std::list<std::string> msgPosts[EVENT_COUNT];

	TaskEntry* parentTask;
	TaskEntry* nextTask;
	TaskEntry* previousTask;
	std::vector<TaskEntry*> subTasks;

	int32 currentTask; // -1 if not active, 0 if self active, N > 0 if subtask N is active
};

bool addToTimerQueue(uint64 t, TaskQueueTrigger trigger, std::map<uint64, TaskQueueTrigger> &timeQueue);
bool removeTaskFromQueues(TaskEntry* oldTask, std::list<TaskQueueTrigger> &triggerQueue, std::map<uint64, TaskQueueTrigger> &timeQueue);


} // namespace cmlabs

#endif // _TASKMANAGERCATALOG_H_
