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

#include <odemx/protocol/Stack.h>
#include <odemx/protocol/Sap.h>
#include <odemx/protocol/Layer.h>
#include <odemx/util/DeletePtr.h>

namespace odemx {
namespace protocol {

Stack::Stack( base::Simulation& sim, const data::Label& label )
:	data::Producer( sim, label )
{
	ODEMX_TRACE << log( "create" ).scope( typeid(Stack) );

	layers_.push_back( new Layer( sim, label + " internal top layer" ) );
}

Stack::~Stack()
{
	ODEMX_TRACE << log( "destroy" ).scope( typeid(Stack) );

	// delete SAPs held by top layer
	// (the layer only deletes its service providers)
	Layer::SapMap& saps = layers_.front()->getSaps();
	for( Layer::SapMap::iterator iter = saps.begin(); iter != saps.end(); ++iter )
	{
		delete iter->second;
	}

	// delete all layers
	std::for_each( layers_.begin(), layers_.end(), DeletePtr< Layer >() );
}

Sap* Stack::getSap( const std::string& name ) const
{
	if( layers_.size() > 1 )
	{
		Sap* sap = layers_[ 1 ]->getSap( name );
		if( sap )
		{
			return sap;
		}
		else
		{
			error << log( "Stack::getSap(): SAP not found in top layer" )
					.detail( "name", name )
					.scope( typeid(Stack) );
		}
	}
	else
	{
		error << log( "Stack::getSap():"
				"no service providing layer, cannot access SAP" )
				.detail( "name", name )
				.scope( typeid(Stack) );
	}
	return 0;
}

void Stack::addLayer( Layer* layer )
{
	ODEMX_TRACE << log( "add layer" )
					.detail( "label", layer->getLabel() )
					.scope( typeid(Stack) );

	layers_.back()->setLowerLayer( layer );
	layer->setUpperLayer( layers_.back() );
	layers_.push_back( layer );
}

Sap* Stack::addReceiveSap( const std::string& name )
{
	Layer* topLayer = layers_.front();
	Sap* sap = topLayer->getSap( name );

	if( sap )
	{
		warning << log( "Stack::addReceiveSap(): SAP already exists" )
				.detail( "name", name )
				.scope( typeid(Stack) );
	}
	else
	{
		ODEMX_TRACE << log( "add receive SAP" )
				.detail( "name", name )
				.scope( typeid(Stack) );

		sap = new Sap( getSimulation(), getLabel(), name );
		topLayer->addSap( sap );
	}
	return sap;
}

Sap* Stack::getReceiveSap( const std::string& name ) const
{
	return layers_.front()->getSap( name );
}

const Stack::LayerVec& Stack::getLayers() const
{
	return layers_;
}

} } // namespace odemx::protocol
