// [License]
// The Ariba-Underlay Copyright
//
// Copyright (c) 2008-2009, Institute of Telematics, Universität Karlsruhe (TH)
//
// Institute of Telematics
// Universität Karlsruhe (TH)
// Zirkel 2, 76128 Karlsruhe
// Germany
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY THE INSTITUTE OF TELEMATICS ``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 INSTITUTE OF TELEMATICS 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.
//
// The views and conclusions contained in the software and documentation
// are those of the authors and should not be interpreted as representing
// official policies, either expressed or implied, of the Institute of
// Telematics.
// [License]


#include "Node.h"

#include "ariba/overlay/BaseOverlay.h"
#include "ariba/utility/types/OverlayParameterSet.h"
#include "ariba/interface/AribaContext.h"
#include "ariba/interface/ServiceInterface.h"
#include "ariba/interface/UnderlayAbstraction.h"

using ariba::interface::UnderlayAbstraction;

namespace ariba {

class ServiceInterfaceWrapper: public interface::ServiceInterface {
private:
	NodeListener* nodeListener;
	CommunicationListener* commListener;
public:
	ServiceInterfaceWrapper(NodeListener* listener) :
		nodeListener(listener), commListener(NULL) {

	}
	ServiceInterfaceWrapper(CommunicationListener* listener) :
		nodeListener(NULL), commListener(listener) {
	}

protected:
	void onOverlayCreate(const SpoVNetID& id) {

	}
	void onOverlayDestroy(const SpoVNetID& id) {

	}

	bool isJoinAllowed(const NodeID& nodeid, const SpoVNetID& spovnetid) {
		return true;
	}

	void onNodeJoin(const NodeID& nodeid, const SpoVNetID& spovnetid) {
		// not handled
	}

	void onNodeLeave(const NodeID& id, const SpoVNetID& spovnetid) {
		// not handled
	}

	void onJoinSuccess(const SpoVNetID& spovnetid) {
		if (nodeListener != NULL) nodeListener->onJoinCompleted(spovnetid);
	}

	void onJoinFail(const SpoVNetID& spovnetid) {
		if (nodeListener != NULL) nodeListener->onJoinFailed(spovnetid);
	}

	void onLinkUp(const LinkID& link, const NodeID& local, const NodeID& remote) {
		if (commListener != NULL) commListener->onLinkUp(link, remote);
	}

	void onLinkDown(const LinkID& link, const NodeID& local,
			const NodeID& remote) {
		if (commListener != NULL) commListener->onLinkDown(link, remote);
	}

	void onLinkChanged(const LinkID& link, const NodeID& local,
			const NodeID& remote) {
		if (commListener != NULL) commListener->onLinkChanged(link, remote);
	}

	void onLinkFail(const LinkID& id, const NodeID& local, const NodeID& remote) {
		if (commListener != NULL) commListener->onLinkFail(id, remote);
	}

	void onLinkQoSChanged(const LinkID& id, const NodeID& local,
			const NodeID& remote, const QoSParameterSet& qos) {
		if (commListener != NULL) commListener->onLinkQoSChanged(id, remote,
				LinkProperties::DEFAULT);
	}

	bool receiveMessage(const Message* message, const LinkID& link,
			const NodeID& node) {
		if (commListener != NULL) commListener->onMessage(
				const_cast<Message*> (message), node, link);
	}
};

const ServiceID Node::anonymousService = 0xFF00;

Node::Node(AribaModule& ariba_mod, const Name& name) :
	ariba_mod(ariba_mod), name(name) {
	this->context = NULL;
}

Node::~Node() {
}

void Node::join(const Name& vnetname) {
	spovnetId = vnetname.toSpoVNetId();
	nodeId = name.toNodeId();
	this->context = ariba_mod.underlay_abs->joinSpoVNet(spovnetId,
			*ariba_mod.getBootstrapNode(name), nodeId);
}

void Node::initiate(const Name& vnetname, const SpoVNetProperties& parm) {
	utility::OverlayParameterSet ovrpset =
		(utility::OverlayParameterSet::_OverlayStructure) parm.getBaseOverlayType();
	spovnetId = vnetname.toSpoVNetId();
	nodeId = name.toNodeId();
	this->context = ariba_mod.underlay_abs->createSpoVNet(spovnetId, nodeId,
			ariba_mod.ip_addr, ariba_mod.tcp_port);
}

void Node::leave() {
	// not implemeted yet.
}

void Node::bind(NodeListener* listener) {
	this->context->getOverlay().bind(new ServiceInterfaceWrapper(listener),
			Node::anonymousService);
}

void Node::unbind(NodeListener* listener) {
	// TODO: allow unbinding
}

const SpoVNetProperties& Node::getSpoVNetProperties() const {
	return SpoVNetProperties::DEFAULT;
}

const SpoVNetID& Node::getSpoVNetId() const {
	return SpoVNetID::UNSPECIFIED;
}

const NodeID& Node::getNodeId(const LinkID& lid) const {
	return NodeID::UNSPECIFIED;
}

NodeID Node::generateNodeId(const Name& name) const {
	return name.toNodeId();
}

LinkID Node::establishLink(const NodeID& nid, const ServiceID& sid,
		const LinkProperties& req, const Message* msg) {
	return context->getOverlay().establishLink(nid, sid);
}

void Node::dropLink(const LinkID& lnk) {
	context->getOverlay().dropLink(lnk);
}

seqnum_t Node::sendMessage(Message* msg, const NodeID& nid,
		const ServiceID& sid, const LinkProperties& req) {
	return context->getOverlay().sendMessage(msg, nid, sid);
}

seqnum_t Node::sendMessage(Message* msg, const LinkID& lnk) {
	return context->getOverlay().sendMessage(msg, lnk);
}

void Node::bind(CommunicationListener* listener, const ServiceID& sid) {
	this->context->getOverlay().bind(new ServiceInterfaceWrapper(listener), sid);
}

void Node::unbind(CommunicationListener* listener, const ServiceID& sid) {
	// TODO
}

// service directory
/*
 void Node::put(const Identifier<>& key, Message* value) {
 }

 void Node::get(const Identifier<>& key) {

 }
 */

// @see Module.h
void Node::initialize() {

}

// @see Module.h
void Node::start() {

}

// @see Module.h
void Node::stop() {

}

// @see Module.h
string Node::getName() const {

}

// @see Module.h
void Node::setProperty(string key, string value) {

}

// @see Module.h
const string Node::getProperty(string key) const {

}

// @see Module.h
const vector<string> Node::getProperties() const {

}

} // namespace ariba
