#include "Swiften/Server/ServerStanzaRouter.h"
#include "Swiften/Server/ServerSession.h"

#include <cassert>
#include <algorithm>

namespace Swift {

namespace {
	struct PriorityLessThan {
		bool operator()(const ServerSession* s1, const ServerSession* s2) const {
			return s1->getPriority() < s2->getPriority();
		}
	};

	struct HasJID {
		HasJID(const JID& jid) : jid(jid) {}
		bool operator()(const ServerSession* session) const {
			return session->getJID().equals(jid, JID::WithResource);
		}
		JID jid;
	};
}

ServerStanzaRouter::ServerStanzaRouter() {
}

bool ServerStanzaRouter::routeStanza(boost::shared_ptr<Stanza> stanza) {
	JID to = stanza->getTo();
	assert(to.isValid());

	// For a full JID, first try to route to a session with the full JID
	if (!to.isBare()) {
		std::vector<ServerSession*>::const_iterator i = std::find_if(clientSessions_.begin(), clientSessions_.end(), HasJID(to));
		if (i != clientSessions_.end()) {
			(*i)->sendStanza(stanza);
			return true;
		}
	}

	// Look for candidate sessions
	to = to.toBare();
	std::vector<ServerSession*> candidateSessions;
	for (std::vector<ServerSession*>::const_iterator i = clientSessions_.begin(); i != clientSessions_.end(); ++i) {
		if ((*i)->getJID().equals(to, JID::WithoutResource) && (*i)->getPriority() >= 0) {
			candidateSessions.push_back(*i);
		}
	}
	if (candidateSessions.empty()) {
		return false;
	}

	// Find the session with the highest priority
	std::vector<ServerSession*>::const_iterator i = std::max_element(clientSessions_.begin(), clientSessions_.end(), PriorityLessThan());
	(*i)->sendStanza(stanza);
	return true;
}

void ServerStanzaRouter::addClientSession(ServerSession* clientSession) {
	clientSessions_.push_back(clientSession);
}

void ServerStanzaRouter::removeClientSession(ServerSession* clientSession) {
	clientSessions_.erase(std::remove(clientSessions_.begin(), clientSessions_.end(), clientSession), clientSessions_.end());
}

}