

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

namespace cmlabs {

template <typename T>
std::list<GenericObservation<T>*> GenericObservation<T>::ReadAllFromMessage(DataMessage* msg) {
	uint32 n = 1;
	std::list<GenericObservation<T>*> list;
	GenericObservation<T>* obs;
	uint32 size;
	const char* data;
	while ((data = msg->getData(n, "OBS", size)) && size && (size == sizeof(ObsHeader) + sizeof(T))) {
		obs = new GenericObservation<T>();
		if (obs->readFromData(data, size))
			list.push_back(obs);
		else
			delete obs;
		n++;
	}
	return list;
}

template <typename T>
bool GenericObservation<T>::WriteAllToMessage(DataMessage* msg, std::list<GenericObservation<T>*>& list) {
	// #################
	return false;
}

template <typename T>
GenericObservation<T>::GenericObservation() {
	memset(&header, 0, sizeof(ObsHeader));
	header.cid = OBSERVATIONID;
	header.size = sizeof(ObsHeader);
	header.timestamp = GetTimeNow();
	header.type = data.getType();
	data.init();
}

template <typename T>
GenericObservation<T>::GenericObservation(const char* cdata, uint32 size, uint64 id) {
	if (!readFromData(cdata, size, id)) {
		memset(&header, 0, sizeof(ObsHeader));
		header.cid = OBSERVATIONID;
		header.size = sizeof(ObsHeader);
		header.timestamp = GetTimeNow();
		header.type = data.getType();
		data.init();
	}
}


template <typename T>
GenericObservation<T>::~GenericObservation() {}

//template <typename T>
//bool GenericObservation<T>::init() {}

template <typename T>
bool GenericObservation<T>::writeToMessage(DataMessage* msg, uint64 id) {
	if (!msg || (!header.id && !id)) return false;
	uint32 s;
	if (!id)
		id = header.id;
	if (msg->getData(id, "OBS", s))
		return false;
	// calculate size needed
	header.size = sizeof(ObsHeader) + sizeof(T);
	// create temp memory buffer
	char* buffer = new char[header.size];
	memcpy(buffer, &header, sizeof(ObsHeader));
	memcpy(buffer + sizeof(ObsHeader), &data, sizeof(T));
	bool res = msg->setData(id, "OBS", buffer, header.size);
	delete[] buffer;
	return res;
}

template <typename T>
bool GenericObservation<T>::readFromData(const char* cdata, uint32 size, uint64 id) {
	if (!cdata || (size != (sizeof(ObsHeader) + sizeof(T))))
		return false;
	if (((ObsHeader*)cdata)->type != header.type)
		return false;
	memcpy(&header, cdata, sizeof(ObsHeader));
	memcpy(&data, cdata + sizeof(ObsHeader), sizeof(T));
	return true;
}

template <typename T>
bool GenericObservation<T>::readFromMessage(DataMessage* msg, uint64 id) {
	if (!msg || !id) return false;
	uint32 s;
	const char* cdata = msg->getData(id, "OBS", s);
	return readFromData(cdata, s, id);
}

//template <typename T>
//bool GenericObservation<T>::buildFromQuery(std::string& query) {
//	return data.buildFromQuery(query.c_str());
//}

template <typename T>
bool GenericObservation<T>::isBetween(GenericObservation<T>* a, GenericObservation<T>* b) {
	return data.isBetween(a->data, b->data);
}

template <typename T>
bool GenericObservation<T>::extractDataFromMessage(DataMessage* msg, std::map<std::string, std::string>& mappings) {
	if (!data.extractDataFromMessage(msg, mappings))
		return false;
	// Extract header data
	header.creatorID = (uint64)msg->getInt("SystemID");
	header.objectID = (uint64)msg->getInt("ObjectID");
	header.confidence = msg->getFloat("Confidence");
	header.consensus = msg->getFloat("Consensus");
	header.timestamp = msg->getCreatedTime();
	return true;
}

template <typename T>
std::string GenericObservation<T>::print() {
	return data.print();
}

template <typename T>
std::string GenericObservation<T>::toJSON() {
	std::string json = data.toJSON();
	if (json.length())
		return utils::StringFormat("{ \"datatype\": \"%s\", \"id\": %llu, \"timestamp\": %llu, \"timetext\": \"%s\", \"objectid\": %llu, \"systemid\": %llu, \"topicid\": %llu, \"confidence\": %.3f, \"consensus\": %.3f, %s}\n",
			data.getTypeName().c_str(), header.id, header.timestamp, PrintTimeString(header.timestamp).c_str(), header.objectID, header.creatorID, header.topicID, header.confidence, header.consensus, json.c_str());
	else
		return utils::StringFormat("{ \"datatype\": \"%s\", \"id\": %llu, \"timestamp\": %llu, \"timetext\": \"%s\", \"objectid\": %llu, \"systemid\": %llu, \"topicid\": %llu, \"confidence\": %.3f, \"consensus\": %.3f, \"datatype\": \"unknown\"}\n",
			data.getTypeName().c_str(), header.id, header.timestamp, PrintTimeString(header.timestamp).c_str(), header.objectID, header.creatorID, header.topicID, header.confidence, header.consensus);
}

} // namespace cmlabs
