#ifndef __LINK_DESCRIPTOR_H
#define __LINK_DESCRIPTOR_H

#include <iostream>
#include <sstream>
#include <ctime>
#include <deque>
#include <boost/foreach.hpp>

#include "ariba/utility/messages.h"
#include "ariba/utility/types.h"
#include "ariba/CommunicationListener.h"

namespace ariba {
	class CommunicationListener;
}

using std::deque;
using ariba::utility::Message;
using ariba::utility::NodeID;
using ariba::utility::SpoVNetID;
using ariba::utility::ServiceID;
using ariba::utility::LinkID;
using ariba::CommunicationListener;

namespace ariba {
namespace overlay {

class LinkDescriptor;

std::ostream& operator<<(std::ostream& s, const LinkDescriptor* ld );
std::ostream& operator<<(std::ostream& s, const LinkDescriptor& ld );

/// LinkDescriptor
class LinkDescriptor {
public:
	// ctor
	LinkDescriptor() {
		// default values
		this->up = false;
		this->dropWhenRelaysLeft = false;
		this->fromRemote = false;
		this->remoteNode = NodeID::UNSPECIFIED;
		this->overlayId  = LinkID::UNSPECIFIED;
		this->communicationUp = false;
		this->communicationId = LinkID::UNSPECIFIED;
		this->keepAliveTime = time(NULL);
		this->keepAliveMissed = 0;
		this->usedAsRelay     = false;
		this->timeUsedAsRelay = time(NULL);
		this->service  = ServiceID::UNSPECIFIED;
		this->listener = &CommunicationListener::DEFAULT;
		this->relay = false;
		this->localRelay   = NodeID::UNSPECIFIED;
		this->remoteRelay  = NodeID::UNSPECIFIED;
		this->remoteLinkId = LinkID::UNSPECIFIED;
		this->autolink = false;
		this->lastuse = time(NULL);
	}

	// dtor
	~LinkDescriptor() {
		flushQueue();
	}

	// general information about the link ---------------------------------

	bool up; ///< flag wheter this link is up and running
	bool dropWhenRelaysLeft;
	bool fromRemote; ///<flag, wheter this link was requested from remote

	NodeID remoteNode; ///< remote endpoint node

	LinkID overlayId; ///< the base overlay link id
	LinkID communicationId; ///< the communication id
	bool communicationUp; ///< flag, wheter the communication is up

	time_t keepAliveTime; ///< the last time a keep-alive message was received
	int keepAliveMissed; ///< the number of missed keep-alive messages

	void markAlive() {
		keepAliveMissed = 0;
		keepAliveTime = time(NULL);
	}

	// relay state --------------------------------------------------------

	bool   usedAsRelay; ///< flag, wheter this link has been used as relay
	time_t timeUsedAsRelay; ///< last time the link has been used as relay

	void markAsRelay() {
		usedAsRelay = true;
		timeUsedAsRelay = time(NULL);
	}

	// owner --------------------------------------------------------------
	ServiceID service; ///< service using this link
	CommunicationListener* listener; ///< the listener using this node

	// relay information --------------------------------------------------
	bool relay;          ///< flag whether this link is a relay link
	NodeID localRelay;   ///< the local relay node
	NodeID remoteRelay;  ///< the remote relay node
	LinkID remoteLinkId; ///< the remote link id

	// auto links ---------------------------------------------------------
	bool autolink;  ///< flag, whether this link is a auto-link
	time_t lastuse; ///< time, when the link was last used
	deque<Message*> messageQueue; ///< waiting messages to be delivered

	/// updates the timestamp
	void markAsUsed() {
		lastuse = time(NULL);
	}

	/// drops waiting messsages
	void flushQueue() {
		BOOST_FOREACH( Message* msg, messageQueue )
			delete msg;
		messageQueue.clear();
	}

	std::string to_string() const {
		std::ostringstream s;
		s << "up=" << up << " ";
		s << "fromRem=" << fromRemote << " ";
		s << "remNode=" << remoteNode.toString().substr(0,6) << " ";
		s << "serv=" << service.toString() << " ";
		s << "overId=" << overlayId.toString().substr(0,6) << " ";
		s << "commUp=" << communicationUp << " ";
		s << "commId=" << communicationId.toString().substr(0,6) << " ";
		s << "usedAsRel=" << usedAsRelay << " ";
		s << "KeepAliveMiss=" << keepAliveMissed << " ";
		if ( !localRelay.isUnspecified() ) {
			s << "locRel=" << localRelay.toString().substr(0,6) << " ";
			s << "remRel=" << remoteRelay.toString().substr(0,6) << " ";
			s << "remLink=" << remoteLinkId.toString().substr(0,6) << " ";
		}
		s << "auto=" << autolink;
		return s.str();
	}
};

}} // namespace ariba, overlay

#endif // __LINK_DESCRIPTOR_H

