#include "EventIdRangeMatcher.h"
#include "EventMatchTree.h"
#include "ReporterRangeMatcher.h"
#include "SeverityRangeMatcher.h"

EventMatchTree::EventMatchTree(StorageManagerIF* storageBackend,
		bool invertedMatch) :
		MatchTree<EventMessage*>(end(), 1), factory(storageBackend), invertedMatch(
				invertedMatch) {
}

EventMatchTree::~EventMatchTree() {
}

bool EventMatchTree::match(EventMessage* number) {
	if (invertedMatch) {
		return !MatchTree<EventMessage*>::match(number);
	} else {
		return MatchTree<EventMessage*>::match(number);
	}
}

ReturnValue_t EventMatchTree::addMatch(EventId_t idFrom, EventId_t idTo,
		bool idInverted, object_id_t reporterFrom, object_id_t reporterTo,
		bool reporterInverted) {
	if (idFrom == 0) {
		//Assuming all events shall be forwarded.
		idTo = 0;
		idInverted = true;
	}
	if (idTo == 0) {
		idTo = idFrom;
	}
	iterator lastTest;
	ReturnValue_t result = findOrInsertRangeMatcher<EventId_t,
			EventIdRangeMatcher>(begin(), idFrom, idTo, idInverted, &lastTest);
	if (result != HasReturnvaluesIF::RETURN_OK) {
		return result;
	}
	if (reporterFrom == 0) {
		//No need to add another AND branch
		return RETURN_OK;
	}
	if (reporterTo == 0) {
		reporterTo = reporterFrom;
	}
	return findOrInsertRangeMatcher<object_id_t, ReporterRangeMatcher>(
			lastTest.left(), reporterFrom, reporterTo, reporterInverted,
			&lastTest);
}

ReturnValue_t EventMatchTree::removeMatch(EventId_t idFrom, EventId_t idTo,
		bool idInverted, object_id_t reporterFrom, object_id_t reporterTo,
		bool reporterInverted) {

	iterator foundElement;

	if (idFrom == 0) {
		//Assuming a "forward all events" request.
		idTo = 0;
		idInverted = true;
	}
	if (idTo == 0) {
		idTo = idFrom;
	}
	foundElement = findRangeMatcher<EventId_t, EventIdRangeMatcher>(begin(),
			idFrom, idTo, idInverted);
	if (foundElement == end()) {
		return NO_MATCH; //Can't tell if too detailed or just not found.
	}
	if (reporterFrom == 0) {
		if (foundElement.left() == end()) {
			return removeElementAndReconnectChildren(foundElement);
		} else {
			return TOO_GENERAL_REQUEST;
		}
	}
	if (reporterTo == 0) {
		reporterTo = reporterFrom;
	}
	foundElement = findRangeMatcher<object_id_t, ReporterRangeMatcher>(
			foundElement.left(), reporterFrom, reporterTo, reporterInverted);
	if (foundElement == end()) {
		return NO_MATCH;
	} else {
		return removeElementAndReconnectChildren(foundElement);
	}
}

template<typename VALUE_T, typename INSERTION_T>
inline ReturnValue_t EventMatchTree::findOrInsertRangeMatcher(iterator start,
		VALUE_T idFrom, VALUE_T idTo, bool inverted, iterator* lastTest) {
	bool attachToBranch = AND;
	iterator iter = start;
	while (iter != end()) {
		INSERTION_T* matcher = static_cast<INSERTION_T*>(*iter);
		attachToBranch = OR;
		*lastTest = iter;
		if ((matcher->rangeMatcher.lowerBound == idFrom)
				&& (matcher->rangeMatcher.upperBound == idTo)
				&& (matcher->rangeMatcher.inverted == inverted)) {
			return RETURN_OK;
		} else {
			iter = iter.right();
		}
	}
	//Only reached if nothing was found.
	SerializeableMatcherIF<EventMessage*>* newContent = factory.generate<
			INSERTION_T>(idFrom, idTo, inverted);
	if (newContent == NULL) {
		return FULL;
	}
	Node* newNode = factory.generate<Node>(newContent);
	if (newNode == NULL) {
		//Need to make sure partially generated content is deleted, otherwise, that's a leak.
		factory.destroy<INSERTION_T>(static_cast<INSERTION_T*>(newContent));
		return FULL;
	}
	*lastTest = insert(attachToBranch, *lastTest, newNode);
	if (*lastTest == end()) {
		//This actaully never fails, so creating a dedicated returncode seems an overshoot.
		return RETURN_FAILED;
	}
	return RETURN_OK;
}

template<typename VALUE_T, typename INSERTION_T>
EventMatchTree::iterator EventMatchTree::findRangeMatcher(iterator start,
		VALUE_T idFrom, VALUE_T idTo, bool inverted) {
	iterator iter = start;
	while (iter != end()) {
		INSERTION_T* matcher = static_cast<INSERTION_T*>(*iter);
		if ((matcher->rangeMatcher.lowerBound == idFrom)
				&& (matcher->rangeMatcher.upperBound == idTo)
				&& (matcher->rangeMatcher.inverted == inverted)) {
			break;
		} else {
			iter = iter.right(); //next OR element
		}
	}
	return iter;
}

ReturnValue_t EventMatchTree::cleanUpElement(iterator position) {
	factory.destroy(position.element->value);
	//If deletion fails, delete element anyway, nothing we can do.
	//SHOULDO: Throw event, or write debug output.
	return factory.destroy(position.element);
}