// [Licence]
// 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 ARIBA PROJECT 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.
// [Licence]

#include "BaseOverlay.h"

#include "ariba/utility/misc/OvlVis.h"
using ariba::utility::OvlVis;

namespace ariba {
namespace overlay {

use_logging_cpp(BaseOverlay);

BaseOverlay::BaseOverlay( BaseCommunication& _basecomm, const NodeID& _nodeid )
	: 	bc( _basecomm ), nodeId( _nodeid ), spovnetId( SpoVNetID::UNSPECIFIED), overlayInterface( NULL ),
		initiatorLink( LinkID::UNSPECIFIED ), state( BaseOverlayStateInvalid ) {

	logging_info("creating base overlay");

	bc.registerMessageReceiver( this );
	bc.registerEventListener( this );

	ovl.visCreate( ovlId, nodeId, string(""), string("") );
	ovl.visChangeNodeColor(ovlId, nodeId, OvlVis::NODE_COLORS_GREY);

// 	if (Identifier(Configuration::instance().read<unsigned long>("BASE_nodeid")) ==
// 	    Identifier(Configuration::instance().read<unsigned long>("SOURCE"))) {
// 		ovl.visChangeNodeIcon(ovlId, nodeId, OvlVis::ICON_ID_CAMERA);
// 	} else if (Identifier(Configuration::instance().read<unsigned long>("BASE_nodeid")) ==
// 	    Identifier(Configuration::instance().read<unsigned long>("MR_A"))) {
// 		ovl.visChangeNodeIcon(ovlId, nodeId, OvlVis::ICON_ID_CHARACTER_A);
// 	} else if (Identifier(Configuration::instance().read<unsigned long>("BASE_nodeid")) ==
// 	    Identifier(Configuration::instance().read<unsigned long>("MR_W"))) {
// 		ovl.visChangeNodeIcon(ovlId, nodeId, OvlVis::ICON_ID_CHARACTER_W);
// 	}
}

BaseOverlay::~BaseOverlay() {

	logging_info("deleting base overlay");

	bc.unregisterMessageReceiver( this );
	bc.unregisterEventListener( this );
}

void BaseOverlay::joinSpoVNet(const SpoVNetID& id, const EndpointDescriptor& bootstrapEp){

	ovl.visShowNodeBubble ( ovlId, nodeId, "joining..." );
	logging_info( "starting to join spovnet " << id.toString() << "...");

	//
	// contact the spovnet initiator and request
	// to join. if the join is granted we will
	// receive further information on the structure
	// of the overlay that is used in the spovnet
	//
	// but first, we have to establish a link to the initiator...
	//

	spovnetId = id;
	state = BaseOverlayStateJoinInitiated;

	initiatorLink = bc.establishLink( bootstrapEp );
}

void BaseOverlay::leaveSpoVNet(){

	logging_info( "leaving spovnet " << spovnetId );

	// first, leave the overlay interface
	overlayInterface->leaveOverlay();

	if( state != BaseOverlayStateInitiator ){

		// then, leave the spovnet baseoverlay
		OverlayMsg overMsg( OverlayMsg::OverlayMessageTypeBye, nodeId );
		bc.sendMessage( initiatorLink, &overMsg );

		// drop the link and set to correct state
		bc.dropLink( initiatorLink );
		initiatorLink = LinkID::UNSPECIFIED;
	}

	state = BaseOverlayStateInvalid;
	ovl.visShutdown( ovlId, nodeId, string("") );

	// inform all registered services of the event
	BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
		i->onOverlayDestroy( spovnetId );
	}
}

void BaseOverlay::createSpoVNet(const SpoVNetID& id, const OverlayParameterSet& param, const SecurityParameterSet& sec, const QoSParameterSet& qos){

	//
	// set the state that we are an initiator,
	// this way incoming messages are handled correctly
	//

	logging_info("creating spovnet " + id.toString());

	spovnetId = id;
	state = BaseOverlayStateInitiator;

	overlayInterface = OverlayFactory::create( *this, param, nodeId, this );
	if( overlayInterface == NULL ){
		logging_fatal( "overlay structure not supported" );
		state = BaseOverlayStateInvalid;
		return;
	}

	//
	// create the overlay
	// and bootstrap against ourselfs
	//

	overlayInterface->createOverlay();
	overlayInterface->joinOverlay();

	ovl.visChangeNodeIcon ( ovlId, nodeId, OvlVis::ICON_ID_CAMERA );
	ovl.visChangeNodeColor( ovlId, nodeId, OvlVis::NODE_COLORS_GREEN);

	// inform all registered services of the event
	BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
		i->onOverlayCreate( spovnetId );
	}
}

const EndpointDescriptor& BaseOverlay::getEndpointDescriptor(const LinkID& link) const {

	return bc.getEndpointDescriptor( link );
}

const EndpointDescriptor& BaseOverlay::getEndpointDescriptor(const NodeID& node) const {

	if( node == nodeId || node == NodeID::UNSPECIFIED )
		return bc.getEndpointDescriptor();

	if( overlayInterface == NULL ){
		logging_error( "overlay interface not set, cannot resolve endpoint" );
		return EndpointDescriptor::UNSPECIFIED;
	}

	// TODO: if this is not a onehop overlay the operation will go asynchronously
	return overlayInterface->resolveNode( node );
}

const LinkID BaseOverlay::establishLink(const NodeID& node, const ServiceID& service){

	// TODO: if this is not a onehop overlay the operation will go asynchronously
	const EndpointDescriptor& endpoint = overlayInterface->resolveNode( node );
	if( endpoint == EndpointDescriptor::UNSPECIFIED ){
		logging_error( "could not resolve node to endpoint. unable to establish link" );
		return LinkID::UNSPECIFIED;
	}

	logging_debug( "baseoverlay called to establish link between node " <<
			node.toString() << " on endpoint " << endpoint.toString() <<
			" for service " << service.toString() );

	return establishLink( endpoint, service );
}

const LinkID BaseOverlay::establishLink(const EndpointDescriptor& ep, const ServiceID& service){

	if( !listenerMux.contains( service ) ){
		logging_error( "no registered listener on serviceid " << service.toString() );
		return LinkID::UNSPECIFIED;
	}

	ServiceInterface* receiver = listenerMux.get( service );
	const LinkID link = bc.establishLink( ep );

	LinkItem item (link, NodeID::UNSPECIFIED, service, receiver);
	linkMapping.insert( make_pair(link, item) );

	return link;
}

void BaseOverlay::dropLink(const LinkID& link){

	logging_debug( "baseoverlay dropping link " << link.toString() );
	LinkMapping::iterator i = linkMapping.find( link );

	if( i == linkMapping.end() ){
		logging_warn( "can't drop link, mapping unknown " << link.toString() );
		return;
	}

	linkMapping.erase( i );

	LinkItem item = i->second;
	bc.dropLink( link );

	if( item.interface != NULL )
		item.interface->onLinkDown( spovnetId, nodeId, item.node );
}

seqnum_t BaseOverlay::sendMessage(const Message* message, const LinkID& link ){

	logging_debug( "baseoverlay is sending message on link " << link.toString() );

	LinkMapping::iterator i = linkMapping.find( link );
	if( i == linkMapping.end() ){
		logging_error( "could not send message. link not found " << link.toString() );
		return -1;
	}

	OverlayMsg overmsg( OverlayMsg::OverlayMessageTypeData, i->second.service, nodeId );
	overmsg.encapsulate( const_cast<Message*>(message) );

	return bc.sendMessage( link, &overmsg );
}

seqnum_t BaseOverlay::sendMessage(const Message* message, const NodeID& node, const ServiceID& service){

	LinkID link = LinkID::UNSPECIFIED;

	LinkMapping::iterator i = linkMapping.begin();
	LinkMapping::iterator iend = linkMapping.end();

	for( ; i != iend; i++ ){
		if( i->second.node == node && i->second.service == service ){
			link = i->second.link;
			break;
		}
	}

	if( link == LinkID::UNSPECIFIED ){
		logging_error( "no link could be found to send message to node " <<
				node.toString() << " for service " << service.toString() );
		return -1;
	}

	return sendMessage( message, link );
}

bool BaseOverlay::bind(ServiceInterface* service, const ServiceID& sid) {

	logging_debug( "binding service on serviceid " << sid.toString() );

	if( listenerMux.contains( sid ) ){
		logging_error( "some service already registered for service id " << sid.toString() );
		return false;
	}

	listenerMux.registerItem( service, sid );
	return true;
}

bool BaseOverlay::unbind(ServiceInterface* service, const ServiceID& sid){

	logging_debug( "unbinding service on serviceid " << sid.toString() );

	if( !listenerMux.contains( sid ) ){
		logging_warn( "cannot unbind service. no service registered on service id " << sid.toString() );
		return false;
	}

	listenerMux.unregisterItem( service );
	return true;
}

void BaseOverlay::onLinkUp(const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote){

	logging_debug( "base overlay received linkup event " + id.toString() );
	// TODO: updateOvlVis( getNodeID(id) );

	//
	// if we get up a link while we are in the
	// join phase and this is the link that
	// we have initiated towards the spovnet owner
	// continue the join process by sending
	// a join request message through the link
	//

	if( state == BaseOverlayStateJoinInitiated && id == initiatorLink){

		logging_info( "join has been initiated by me and the link is now up. " <<
				"sending out join request for spovnet " <<
				spovnetId.toString() );

		OverlayMsg overMsg( OverlayMsg::OverlayMessageTypeJoinRequest, nodeId );
		JoinRequest joinmsg( spovnetId, nodeId );
		overMsg.encapsulate( &joinmsg );

		state = BaseOverlayStateJoinInitiated; // state remains in JoinInitiated
		bc.sendMessage( id, &overMsg );

		return;

	} // if( state == BaseOverlayStateJoinInitiated && id == initiatorLink)

	//
	// otherwise this is a link initiated by a service
	// then we exchange update messages to exchange the
	// service id and node id for the link. in this case
	// we should have a link mapping for this link. if
	// we have no link mapping this link was initiated by
	// the remote side.
	//

	LinkMapping::iterator i = linkMapping.find( id );

	if( i == linkMapping.end() ){

		LinkItem item (id, NodeID::UNSPECIFIED, ServiceID::UNSPECIFIED, NULL );
		linkMapping.insert( make_pair(id, item) );

	} else {

		logging_debug( "sending out OverlayMessageTypeUpdate" <<
				" for service " << i->second.service.toString() <<
				" with local node id " << nodeId.toString() <<
				" on link " << id.toString() );

		OverlayMsg overMsg( OverlayMsg::OverlayMessageTypeUpdate, i->second.service, nodeId );
		bc.sendMessage( id, &overMsg );

	} // if( i == linkMapping.end() )

	// the link is only valid for the service when we receive
	// the OverlayMessageTypeUpdate from the remote node and
	// have the nodeid and serviceid for the link!
}

void BaseOverlay::onLinkDown(const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote){

	logging_debug( "link went down " << id.toString() );

	//
	// tell the service that the link went
	// down and remove the mapping
	//

	LinkMapping::iterator i = linkMapping.find( id );
	if( i == linkMapping.end() ) {
		// this can also be one of the baseoverlay links that
		// no mapping is stored for. therefore we issue no warning
		return;
	}

	if( i->second.interface != NULL )
		i->second.interface->onLinkDown( id, nodeId, i->second.node );

	linkMapping.erase( i );
}

void BaseOverlay::onLinkChanged(const LinkID& id, const NetworkLocator* oldlocal, const NetworkLocator* newlocal, const NetworkLocator* oldremote, const NetworkLocator* newremote){

	logging_debug( "link changed " << id.toString() );

	//
	// tell the service that the link changed
	//

	LinkMapping::iterator i = linkMapping.find( id );
	if( i == linkMapping.end() ) return;

	if( i->second.interface != NULL )
		i->second.interface->onLinkChanged( id, nodeId, i->second.node );
}

void BaseOverlay::onLinkFail(const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote){

	logging_debug( "link failed " << id.toString() );

	//
	// tell the service that the link failed
	//

	LinkMapping::iterator i = linkMapping.find( id );
	if( i == linkMapping.end() ) return;

	if( i->second.interface != NULL )
		i->second.interface->onLinkFail( id, nodeId, i->second.node );
}

void BaseOverlay::onLinkQoSChanged(const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote, const QoSParameterSet& qos) {

	logging_debug( "link qos changed " << id.toString() );

	//
	// tell the service that the link qos has changed
	//

	LinkMapping::iterator i = linkMapping.find( id );
	if( i == linkMapping.end() ) return;

	if( i->second.interface != NULL )
		i->second.interface->onLinkQoSChanged( id, nodeId, i->second.node, qos );
}

bool BaseOverlay::receiveMessage(const Message* message,
	const LinkID& link, const NodeID& /*the nodeid is invalid in this case! removed var to prevent errors*/ ){

	OverlayMsg* overlayMsg = ((Message*)message)->decapsulate<OverlayMsg>();
	if( overlayMsg == NULL ) return false;

	//
	// handle user date that we forward to the
	// appropriate service using the service id
	// in the message. as we don't know the class
	// of message that the service handles, we
	// forward it as a pure Message*
	//

	if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeData) ) {

		logging_debug( "baseoverlay received message of type OverlayMessageTypeData" );

		const ServiceID& service = overlayMsg->getService();
		ServiceInterface* serviceListener = listenerMux.get( service );

		logging_debug( "received data for service " << service.toString() );

		if( serviceListener != NULL )
			serviceListener->receiveMessage( overlayMsg, link, overlayMsg->getSourceNode() );

		return true;

	} // if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeData) )

	//
	// handle spovnet instance join requests
	//

	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeJoinRequest) &&
						state == BaseOverlayStateInitiator){

		logging_debug( "baseoverlay received message of type OverlayMessageTypeJoinRequest" );

		JoinRequest* joinReq = overlayMsg->decapsulate<JoinRequest>();
		logging_info( "received join request for spovnet " <<
					 joinReq->getSpoVNetID().toString() );

		//
		// make sure that the node actually wants to join
		// the correct spovnet id that we administrate
		//

		if( joinReq->getSpoVNetID() != spovnetId ){
			logging_error( "received join request for spovnet we don't handle " <<
					joinReq->getSpoVNetID().toString() );
			return false;
		}

		//
		// only if all services allow the node to join it is allowed
		// using the isJoinAllowed interface security policies can be
		// implemented by higher layer services
		//

		bool allow = true;

		BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
			allow &= i->isJoinAllowed( overlayMsg->getSourceNode(), spovnetId );
		}

		logging_info( "sending back join reply for spovnet " <<
				spovnetId.toString() << " to node " <<
				overlayMsg->getSourceNode().toString() <<
				". result: " << (allow ? "allowed" : "denied") );

		joiningNodes.push_back( overlayMsg->getSourceNode() );

		//
		// send back our spovnetid, default overlay parameters,
		// join allow result, and ourself as the endpoint
		// to bootstrap the overlay against
		//

		OverlayMsg retmsg( OverlayMsg::OverlayMessageTypeJoinReply, nodeId );
		JoinReply replyMsg( spovnetId, OverlayParameterSet::DEFAULT,
					allow, getEndpointDescriptor() );

		retmsg.encapsulate(&replyMsg);
		bc.sendMessage( link, &retmsg );

		return true;

	} // else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeJoinRequest) && state == BaseOverlayStateInitiator)

	//
	// handle replies to spovnet instance join requests
	//

	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeJoinReply) &&
						state == BaseOverlayStateJoinInitiated){

		logging_debug( "baseoverlay received message of type OverlayMessageTypeJoinReply" );

		JoinReply* replyMsg = overlayMsg->decapsulate<JoinReply>();
		logging_info( "received spovnet join reply" );

		//
		// make sure that we actually wanted to get
		// into the spovnet whose id is in the message
		//

		if( replyMsg->getSpoVNetID() != spovnetId ){
			logging_error( "received spovnet join reply for spovnet " <<
					replyMsg->getSpoVNetID().toString() <<
					" but we wanted to join spovnet " <<
					spovnetId.toString() );

			// state does not change here, maybe
			// the reply does come in later
			return false;
		}

		//
		// if we did not get access to the spovnet
		// notify of the failure and
		// close the link to the initiator
		//

		if( ! replyMsg->getJoinAllowed() ){

			logging_warn( "our join request has been denied" );

			bc.dropLink( initiatorLink );
			initiatorLink = LinkID::UNSPECIFIED;
			state = BaseOverlayStateInvalid;

			// inform all registered services of the event
			BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
				i->onJoinFail( spovnetId );
			}

			return true;
		}

		logging_info( "join request has been accepted for spovnet " << spovnetId.toString() );

		//
		// if we did get access to the spovnet
		// we try to create the overlay structure
		// as given in the reply message
		//

		overlayInterface = OverlayFactory::create( *this, replyMsg->getParam(), nodeId, this );

		if( overlayInterface == NULL ){
			logging_error( "overlay structure not supported" );

			bc.dropLink( initiatorLink );
			initiatorLink = LinkID::UNSPECIFIED;
			state = BaseOverlayStateInvalid;

			// inform all registered services of the event
			BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
				i->onJoinFail( spovnetId );
			}

			return true;
		}

		//
		// now start the join process for the overlay.
		// the join process for the spovnet baseoverlay
		// is now complete. we use the endpoint for
		// overlay structure bootstrapping that the
		// initiator provided in his reply message
		//

		state = BaseOverlayStateCompleted;
		ovl.visChangeNodeColor( ovlId, nodeId, OvlVis::NODE_COLORS_GREEN);

		overlayInterface->createOverlay();

		// inform all registered services of the event
		BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
			i->onOverlayCreate( spovnetId );
		}

		overlayInterface->joinOverlay( replyMsg->getBootstrapEndpoint() );

		// inform all registered services of the event
		BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
			i->onJoinSuccess( spovnetId );
		}

		return true;

	} // else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeJoinReply) && state == BaseOverlayStateJoinInitiated)


	//
	// handle update messages for link establishment
	//

	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeUpdate) ){

		logging_debug( "baseoverlay received message of type OverlayMessageTypeUpdate" );

		const NodeID& sourcenode = overlayMsg->getSourceNode();
		const ServiceID& service = overlayMsg->getService();

		//
		// we should have a linkmapping for the link, otherwise
		// we ignore update messages
		//

		LinkMapping::iterator i = linkMapping.find( link );
		if( i == linkMapping.end() ){
			logging_warn( "received overlay update message for link " <<
					link.toString() << " for which we have no mapping" );
			return false;
		}

		//
		// update our link mapping information for this link
		//

		bool changed = ( i->second.node != sourcenode ) || ( i->second.service != service );

		i->second.node = sourcenode;
		i->second.service = service;

		//
		// if our link information changed, we send out an update, too
		//

		if( changed ){
			OverlayMsg overMsg( OverlayMsg::OverlayMessageTypeUpdate, i->second.service, nodeId );
			bc.sendMessage( link, &overMsg );
		}

		//
		// set the correct listener service for the linkitem
		// now we can tell the registered service of the linkup event
		//

		if( !listenerMux.contains( service ) ){
			logging_warn( "linkup event for service that has not been registered" );
			return false;
		}

		ServiceInterface* iface = listenerMux.get( service );
		if( iface == NULL ){
			logging_warn( "linkup event for service that has been registered with a NULL interface" );
			return true;
		}

		i->second.interface = iface;
		iface->onLinkUp( link, nodeId, sourcenode );

		return true ;

	} // else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeUpdate) )

	//
	// bye messages to say goodbye
	//

	else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeBye)){

		logging_debug( "baseoverlay received message of type OverlayMessageTypeBye" );

		logging_debug( "received bye message from " <<
				overlayMsg->getSourceNode().toString() );

		//
		// if we are the initiator and receive a bye from a node
		// the node just left. if we are a node and receive a bye
		// from the initiator, we have to close, too.
		//

		if( overlayMsg->getSourceNode() == spovnetInitiator ){

			bc.dropLink( initiatorLink );
			initiatorLink = LinkID::UNSPECIFIED;
			state = BaseOverlayStateInvalid;

			logging_fatal( "initiator ended spovnet" );

			// inform all registered services of the event
			BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
				i->onOverlayDestroy( spovnetId );
			}

		} else {

			// a node that said goodbye and we are the initiator
			// don't have to do much here, as the node also
			// will go out of the overlay structure
			logging_info( "node left " << overlayMsg->getSourceNode() );

			// inform all registered services of the event
			BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
				i->onNodeLeave( overlayMsg->getSourceNode(), spovnetId );
			}
		}

		return true;

	} // else if( overlayMsg->isType(OverlayMsg::OverlayMessageTypeBye))

	//
	// something wrong ...
	//

	else {

		logging_error( "received message in invalid state! don't know " <<
				"what to do with this message of type " <<
				overlayMsg->getType() );
		return false;

	} // else

	return false;
}

void BaseOverlay::broadcastMessage(Message* message, const ServiceID& service){

	logging_debug( "broadcasting message to all known nodes " <<
			"in the overlay from service " + service.toString() );

	OverlayInterface::NodeList nodes = overlayInterface->getKnownNodes();

	OverlayInterface::NodeList::iterator i = nodes.begin();
	OverlayInterface::NodeList::iterator iend = nodes.end();

	for( ; i != iend; i++ ){
		if( *i == nodeId) continue; // don't send to ourselfs
		sendMessage( message, *i, service ); // TODO: sollte auto links aufbauen für sowas
	}
}

void BaseOverlay::updateOvlVis( const NodeID& n ) {
	NodeID node = n;
/*	void visShowNodeBubble (
        NETWORK_ID network,
        NodeID& node,
        string label
        );
*/
	using namespace std;

	if (node == nodeId || node.isUnspecified()) return;

	// min/max
	if ( node < min || min.isUnspecified() ) min = node;
	if ( node > max || max.isUnspecified() ) max = node;

	// successor
	if ( succ.isUnspecified() || (node > nodeId && (succ < nodeId || (node-nodeId) < (succ-nodeId))) ) {
		if (!succ.isUnspecified() && node != succ)
			ovl.visDisconnect(ovlId, nodeId, succ, string(""));
		succ = node;
		ovl.visConnect(ovlId, nodeId, succ, string(""));
	}

	// set successor (circle-wrap)
	if (succ.isUnspecified() && !min.isUnspecified()) {
		succ = min;
		ovl.visConnect(ovlId, nodeId, succ, string(""));
	}
}

const NodeID& BaseOverlay::getNodeID(const LinkID& lid) const {

	if( lid == LinkID::UNSPECIFIED ) return nodeId;

	LinkMapping::const_iterator i = linkMapping.find( lid );
	if( i == linkMapping.end() ) return NodeID::UNSPECIFIED;
	else return i->second.node;
}

void BaseOverlay::incomingRouteMessage(Message* msg){
	// gets handled as normal data message
	// TODO: passt das so?
	receiveMessage( msg, LinkID::UNSPECIFIED, NodeID::UNSPECIFIED );
}

void BaseOverlay::onNodeJoin(const NodeID& node){

	JoiningNodes::iterator i = std::find( joiningNodes.begin(), joiningNodes.end(), node );
	if( i == joiningNodes.end() ) return;

	logging_info( "node has successfully joined baseoverlay and overlay structure "
				<< node.toString() );

	BOOST_FOREACH( ServiceInterface* i, listenerMux.getOneList() ){
		i->onNodeJoin( node, spovnetId );
	}

	joiningNodes.erase( i );
}

}} // namespace ariba, overlay
