//------------------------------------------------------------------------------
//	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 Stack.h
 * @author Ronald Kluth
 * @date created at 2009/10/16
 * @brief Declaration of class odemx::protocol::Stack
 * @sa Stack.cpp
 * @since 3.0
 */

#ifndef ODEMX_PROTOCOL_STACK_INCLUDED
#define ODEMX_PROTOCOL_STACK_INCLUDED

#include <odemx/data/Producer.h>

#include <map>
#include <vector>

//----------------------------------------------------------forward declarations

namespace odemx {
namespace protocol {

class Sap;
class Layer;
class Pdu;

//-----------------------------------------------------------header declarations

/**
 * @brief A class for assembling protocol stacks from layers and service providers
 * @ingroup protocol
 * @author Ronald Kluth
 * @since 3.0
 * @see odemx::protocol::Layer odemx::protocol::Entity odemx::protocol::Service odemx::protocol::Device
 *
 * Protocol stacks are composed of layers that each provide different services
 * to the layer above. Stack is the class that allows gluing these layers
 * together. Registered layers are owned by the stack and kept in a vector.
 * The registration order is important because the layers' internal pointers
 * to adjacent layers (upper/lower) are set during this phase.
 *
 * As the stack provides the means to transmit data between the applications
 * running on network nodes, it must also provide a means to listen for
 * incoming data. This is achieved by creating receive SAPs.
 *
 * @note It is not always necessary to use a complete protocol stack in order
 * to model node communication in a network. The simplest way to achieve this
 * is to use a Service implementation, which can be used as a replacement
 * for Stack objects as it includes the same interface.
 */
class Stack
:	public data::Producer
{
public:
	/// Vector type to hold pointers to protocol layers
	typedef std::vector< Layer* > LayerVec;

	/**
	 * @brief Construction
	 * @param sim The simulation context
	 * @param label The label of the object
	 *
	 * The constructor initializes an internal layer that is used for storing the
	 * receive SAPs that stack users can listen on.
	 */
	Stack( base::Simulation& sim, const data::Label& label );

	/**
	 * @brief Destruction
	 *
	 * The destructor deletes all receive SAPs and all layers owned by the stack.
	 */
	virtual ~Stack();

	/**
	 * @brief Get access to an SAP from the top layer of the stack hierarchy
	 *
	 * In order to use a protocol stack, data must be passed to it by writing
	 * data units to an SAP. This method is used to retrieve SAPs of the top
	 * layer in the stack hierarchy. The service providers of the layers will
	 * then take care of the transmission procedure.
	 */
	Sap* getSap( const std::string& name ) const;

	/**
	 * @brief Add a layer to the protocol stack
	 * 
	 * Protocol stacks are composed from layers. Thus, in order to configure a
	 * stack, one must first create the layers with appropriate service
	 * providers and then add them to the stack. The layers must be added in 
	 * order from top to bottom.
	 */
	void addLayer( Layer* layer );

	/**
	 * @brief Get a reference to the vector containing all registered layers
	 * @return Reference to the internal layer vector
	 * @note Provided for testing purposes
	 */
	const LayerVec& getLayers() const;

	/**
	 * @brief Add a new SAP to the stack in order to receive output
	 * @return Pointer to the SAP object, may be newly created or alreaady existing
	 *
	 * Users of the stack may need to add SAPs from which to receive data.
	 * These SAPs are managed by the Stack so users do not need to delete them.
	 * If the addition of an existing SAP is requested, the method will
	 * issue a warning message.
	 */
	Sap* addReceiveSap( const std::string& name );

	/**
	 * @brief Get a pointer to one of the protocol stack's SAPs
	 * @return Pointer to the requested SAP object, or 0 if the SAP does not exist
	 *
	 * Users of the stack can get access to receive SAPs by name in order
	 * to listen for the arrival of data.
	 */
	Sap* getReceiveSap( const std::string& name ) const;
	
private:
	/// Stores the layers that compose the protocol stack
	LayerVec layers_;
};

} } // namespace odemx::protocol

#endif /* ODEMX_PROTOCOL_STACK_INCLUDED */
