//------------------------------------------------------------------------------
//	Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin
//
//	This library is free software; you can redistribute it and/or
//	modify it under the terms of the GNU Lesser General Public
//	License as published by the Free Software Foundation; either
//	version 2.1 of the License, or (at your option) any later version.
//
//	This library is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//	Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/**
 * @file Layer.h
 * @author Ronald Kluth
 * @date created at 2009/10/13
 * @brief Declaration of class odemx::protocol::Layer
 * @sa Layer.cpp
 * @since 3.0
 */

#ifndef ODEMX_PROTOCOL_LAYER_INCLUDED
#define ODEMX_PROTOCOL_LAYER_INCLUDED

#include <odemx/data/Producer.h>

//---------------------------------------------------------forward decalarations

namespace odemx {
namespace protocol {

class ServiceProvider;
class Sap;

//----------------------------------------------------------header decalarations

/**
 * @brief Models the layers of a protocol stack and contains service providers
 * @ingroup protocol
 * @author Ronald Kluth
 * @since 3.0
 * @see odemx::protocol::Stack odemx::protocol::ServiceProvider odemx::protocol::Sap
 *
 * ODEMx protocol stacks consist of a number of layers that each offer services
 * to the layer above. The services are implemented by ServiceProvider subclasses,
 * while access to them is provided via service access points (SAPs).
 *
 * A Layer can hold an arbitrary number of ServiceProviders while making all
 * of their SAPs visible to the layers above and below in the stack. Layers
 * always own their ServiceProvider objects and delete them automatically upon
 * destruction.
 */
class Layer
:	public data::Producer
{
public:
	/// Vector type to store pointers to all kinds of service providers
	typedef std::vector< ServiceProvider* > ServiceProviderVec;
	/// Map type to associate service types with suitable SAPs
	typedef std::map< std::string, Sap* > SapMap;

	/// Construction
	Layer( base::Simulation& sim, const data::Label& label );

	/**
	 * @brief Destruction
	 *
	 * As the Layer owns all ServiceProviders, it deletes them here.
	 */
	virtual ~Layer();

	/**
	 * @brief Register a new service provider object
	 * @param sp The new service provider
	 *
	 * This layer is set as the service provider's layer so that it may
	 * have access to SAPs offered by the upper and lower layer.
	 * In addition, all SAPs of the new service provider are added to the
	 * SAP map of this layer so they can be retrieved by name. Finally,
	 * the service provider is stored in an internal vector.
	 */
	void addServiceProvider( ServiceProvider* sp );

	/// Get read access to the internal vector holding service providers
	const ServiceProviderVec& getServiceProviders() const;

	/// Get a pointer to an SAP by providing its name
	Sap* getSap( const std::string& sap ) const;

	/// Get a reference to the map containing all registered SAPs
	SapMap& getSaps();

	/// Get access to the upper layer, usually to access its SAPs
	Layer* getUpperLayer() const;

	/// Get access to the lower layer, usually to access its SAPs
	Layer* getLowerLayer() const;

	/**
	 * @brief Set the layer above this one in the stack's hierarchy
	 * @param layer The layer above
	 *
	 * This method is usually not called manually. It is used when adding
	 * layers to the protocol stack. In that way, adjacent layers get
	 * connected automatically.
	 */
	void setUpperLayer( Layer* layer );

	/**
	 * @brief Set the layer below this one in the stack's hierarchy
	 * @param layer The layer above
	 *
	 * This method is usually not called manually. It is used when adding
	 * layers to the protocol stack. In that way, adjacent layers get
	 * connected automatically.
	 */
	void setLowerLayer( Layer* layer );

	/**
	 * @brief Add an SAP to the layer
	 * @param sap The SAP object to be registered
	 *
	 * This method is usually not called manually. It is used when adding
	 * service providers to make their SAPs known to users of this layer.
	 */
	void addSap( Sap* sap );

	/**
	 * @brief Remove a registered SAP from the layer
	 * @param sap Name of the SAP object to be removed
	 *
	 * This method is usually not called manually. It is used when SAPs
	 * are removed from service providers in order to notify the layer that
	 * an SAP is no longer available.
	 */
	bool removeSap( const std::string& sap );

protected:
	/// Stores all of the layer's service providers
	ServiceProviderVec serviceProviders_;
	/// Stores all of the SAPs offered by the layer's service providers
	SapMap saps_;
	/// Stores a pointer to the upper layer in the hierarchy
	Layer* upperLayer_;
	/// Stores a pointer to the lower layer in the hierarchy
	Layer* lowerLayer_;
};

} } // namespace odemx::protocol

#endif /* ODEMX_PROTOCOL_LAYER_INCLUDED */
