// [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]

#ifndef BASEOVERLAY_H_
#define BASEOVERLAY_H_

#include <map>
#include <iostream>
#include <algorithm>
#include <ctime>
#include <list>
#include <vector>
#include <boost/foreach.hpp>

#include "ariba/utility/messages.h"
#include "ariba/utility/types.h"
#include "ariba/utility/misc/Helper.h"
#include "ariba/utility/misc/Demultiplexer.hpp"
#include "ariba/utility/logging/Logging.h"
#include "ariba/utility/system/Timer.h"

#include "ariba/communication/EndpointDescriptor.h"
#include "ariba/communication/BaseCommunication.h"
#include "ariba/communication/CommunicationEvents.h"

#include "ariba/interface/ServiceInterface.h"

#include "ariba/overlay/modules/OverlayInterface.h"
#include "ariba/overlay/modules/OverlayFactory.h"
#include "ariba/overlay/modules/OverlayStructureEvents.h"
#include "ariba/overlay/messages/OverlayMsg.h"
#include "ariba/overlay/messages/JoinRequest.h"
#include "ariba/overlay/messages/JoinReply.h"

using std::vector;
using std::list;
using std::cout;
using std::map;
using std::make_pair;
using std::pair;
using std::find;

using ariba::communication::EndpointDescriptor;
using ariba::communication::BaseCommunication;
using ariba::communication::CommunicationEvents;

using ariba::interface::ServiceInterface;

using ariba::overlay::OverlayMsg;
using ariba::overlay::JoinRequest;
using ariba::overlay::JoinReply;
using ariba::overlay::OverlayInterface;
using ariba::overlay::OverlayFactory;
using ariba::overlay::OverlayStructureEvents;

using ariba::utility::NodeID;
using ariba::utility::SpoVNetID;
using ariba::utility::LinkID;
using ariba::utility::Identifier;
using ariba::utility::ServiceID;
using ariba::utility::QoSParameterSet;
using ariba::utility::SecurityParameterSet;
using ariba::utility::Demultiplexer;
using ariba::utility::MessageReceiver;
using ariba::utility::MessageSender;
using ariba::utility::seqnum_t;
using ariba::utility::Timer;

#define ovl OvlVis::instance()
#define ovlId OvlVis::NETWORK_ID_BASE_OVERLAY

// needed for friend decleration
// in different namespace
namespace ariba {
	class Node;
}

namespace ariba {
namespace overlay {

class BaseOverlay :
	public MessageReceiver,
	public CommunicationEvents,
	public OverlayStructureEvents,
	protected Timer {

	use_logging_h( BaseOverlay );
	friend class ariba::Node;

public:

	/**
	 * Constructs a Base Overlay instance
	 */
	BaseOverlay( BaseCommunication& _basecomm, const NodeID& _nodeid );

	/**
	 * TODO
	 */
	virtual ~BaseOverlay();

	/**
	 * Starts a link establishment procedure to the specfied node
	 *
	 * @param node The node id
	 */
	const LinkID establishLink( const NodeID& node, const ServiceID& service );

	/**
	 * TODO
	 */
	const LinkID establishLink( const EndpointDescriptor& ep, const ServiceID& service );

	/**
	 * TODO
	 */
	void  dropLink( const LinkID& link );

	/**
	 * TODO
	 */
	seqnum_t sendMessage( const Message* message, const LinkID& link );

	/**
	 * TODO
	 */
	seqnum_t sendMessage( const Message* message, const NodeID& node, const ServiceID& service );

	/**
	 * Send out a message to all nodes that are known in the overlay structure.
	 * Depending on the structure of the overlay, this can be very different.
	 */
	void broadcastMessage(
		Message* message,
		const ServiceID& service
	);

	/**
	 * Get a list of overlay neighboring nodes.
	 */
	vector<NodeID> getOverlayNeighbors() const;

	/**
	 * Returns the end-point descriptor of a link.
	 *
	 * @param link the link id of the requested end-point
	 * @return The end-point descriptor of the link's end-point
	 */
	const EndpointDescriptor& getEndpointDescriptor( const LinkID& link = LinkID::UNSPECIFIED ) const;

	/**
	 * TODO
	 */
	const EndpointDescriptor& getEndpointDescriptor( const NodeID& node ) const;

	/**
	 * Registers a receiver.
	 *
	 * @param receiver An implementation of the receiver interface
	 */
	bool bind( ServiceInterface* service, const ServiceID& sid );

	/**
	 * Unregister a receiver.
	 *
	 * @param sid The service id to unregister
	 */
	ServiceInterface* unbind( const ServiceID& sid );

	/**
	 * Returns the own nodeID or the NodeID of the specified link
	 *
	 * @param lid The link identifier
	 * @return The NodeID of the link
	 */
	const NodeID& getNodeID( const LinkID& lid = LinkID::UNSPECIFIED ) const ;

protected:

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	void joinSpoVNet(
		const SpoVNetID& id,
		const EndpointDescriptor& bootstrapEp
	);

	void createSpoVNet(
		const SpoVNetID& id,
		const OverlayParameterSet& param = OverlayParameterSet::DEFAULT,
		const SecurityParameterSet& sec  = SecurityParameterSet::DEFAULT,
		const QoSParameterSet& qos = QoSParameterSet::DEFAULT
	);

	void leaveSpoVNet(
	);

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	virtual void onLinkUp( const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote );

	virtual void onLinkDown( const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote );

	virtual void onLinkChanged( const LinkID& id, const NetworkLocator* oldlocal, const NetworkLocator* newlocal, const NetworkLocator* oldremote, const NetworkLocator* newremote );

	virtual void onLinkFail( const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote );

	virtual void onLinkQoSChanged( const LinkID& id, const NetworkLocator* local, const NetworkLocator* remote, const QoSParameterSet& qos );

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	virtual bool receiveMessage( const Message* message, const LinkID& link, const NodeID& ); // nodeid is not valid in this case!

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	/**
	 * see OverlayStructureEvents.h, called from specific OverlayInterface class
	 */
	virtual void incomingRouteMessage( Message* msg );
	virtual void onNodeJoin( const NodeID& node );

	// for timer events
	virtual void eventFunction();

private:

	/**
	 * The BaseCommunication the BaseOverlay
	 * communicates over
	 */
	BaseCommunication& bc;

	/**
	 * The nodeid of this BaseOverlay instance.
	 */
	NodeID nodeId;

	/**
	 * The SpoVNetID that we are joined to
	 * or that we have created.
	 */
	SpoVNetID spovnetId;

	/**
	 * A demultiplexer that maps listeners to service ids
	 * to deliver upcoming messages to the correct service.
	 */
	Demultiplexer<ServiceInterface*, ServiceID> listenerMux;

	/**
	 * The abstract overlay interface that implements
	 * the overlay specific functionality.
	 */
	OverlayInterface* overlayInterface;

	/**
	 * The special link to the Initiator of the SpoVNet
	 * or LinkID::UNDEFINED if we are the Initiator
	 */
	LinkID initiatorLink;

	/**
	 * The state of the BaseOverlay
	 */
	typedef enum _BaseOverlayState {
		BaseOverlayStateInvalid        = 0,
		BaseOverlayStateInitiator      = 1,
		BaseOverlayStateJoinInitiated  = 2,
		BaseOverlayStateCompleted      = 3,
	} BaseOverlayState;

	BaseOverlayState state;

	/**
	 * The initiator node
	 */
	NodeID spovnetInitiator;

	/**
	 * OvlVis
	 */
	NodeID min, max;
	NodeID succ, pred;
	void updateOvlVis( const NodeID& node );

	/**
	 * Link management
	 */
	class LinkItem {
	public:
		static const LinkItem UNSPECIFIED;

		LinkItem( const LinkID& _link, const NodeID& _node,
				const ServiceID& _service, ServiceInterface* _interface )
			: link( _link ), node( _node ), service( _service ), interface( _interface ),
				autolink( false ), lastuse( time(NULL) ) {
		}

		// general information about the link

		const LinkID link;
		NodeID node;
		ServiceID service;
		ServiceInterface* interface;

		// information needed for auto links

		void markused(){
			lastuse = time(NULL);
		}

		bool autolink;
		time_t lastuse;
	};

	typedef map<const LinkID, LinkItem> LinkMapping;
	typedef pair<const LinkID,LinkItem> LinkPair;
	LinkMapping linkMapping;

	// nodes with pending joines. TODO: should be cleaned every some seconds
	// add timestamps to each, and check on occasion
	typedef vector<NodeID> JoiningNodes;
	JoiningNodes joiningNodes;

};

}} // namespace ariba, overlay

#endif /*BASEOVERLAY_H_*/
