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

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

#include <algorithm> // for_each, find_if

namespace odemx {
namespace protocol {

//------------------------------------------------------construction/destruction

ServiceProvider::ServiceProvider( base::Simulation& sim, const data::Label& label )
:	base::Process( sim, label )
,	layer_( 0 )
,	saps_()
{
	ODEMX_TRACE << log( "create" ).scope( typeid(ServiceProvider) );
	this->activate();
}

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

	std::for_each( saps_.begin(), saps_.end(), DeletePtr< Sap >() );
}

//------------------------------------------------------------process life cycle

int ServiceProvider::main()
{
	while( true )
	{
		if( sapQueues_.empty() )
		{
			error << log( "ServiceProvider::main(): "
					"no SAPs registered, cannot enter wait state" )
					.scope( typeid(ServiceProvider) );
			return -1;
		}

		synchronization::IMemory* alerter = base::Process::wait( &sapQueues_ );
		if( alerter != 0 )
		{
			Sap::BufferHead* sapQ = static_cast< Sap::BufferHead* >( alerter );
			const std::string& sapName = sapQ->getSap().getName();
			
			ODEMX_TRACE << log( "handle input" )
					.detail( "SAP", sapName )
					.scope( typeid(ServiceProvider) );

			handleInput( sapName, sapQ->getSap().read() );
		}
		else
		{
			error << log( "ServiceProvider::main(): alerter is 0" )
					.scope( typeid(ServiceProvider) );
		}
	}
	return 0;
}

//-----------------------------------------------------------------member access

void ServiceProvider::setLayer( Layer* layer )
{
	assert( layer );

	ODEMX_TRACE << log( "set layer" )
			.detail( "label", layer->getLabel() )
			.scope( typeid(ServiceProvider) );

	layer_ = layer;
}

Layer* ServiceProvider::getLayer() const
{
	return layer_;
}

Sap* ServiceProvider::addSap( const std::string& name )
{
	SapVec::iterator found = std::find_if(
			saps_.begin(), saps_.end(), Sap::MatchName( name ) );

	if( found != saps_.end() )
	{
		warning << log( "ServiceProvider::addSap(): SAP already exists" )
				.detail( "name", name )
				.scope( typeid(ServiceProvider) );
		return *found;
	}

	ODEMX_TRACE << log( "add SAP" )
			.detail( "name", name )
			.scope( typeid(ServiceProvider) );

	Sap* sap = new Sap( getSimulation(), getLabel(), name );
	saps_.push_back( sap );
	sapQueues_.push_back( sap->getBuffer() );

	if( layer_ )
	{
		layer_->addSap( sap );
	}
	return sap;
}

bool ServiceProvider::removeSap( const std::string& name )
{
	SapVec::iterator found = std::find_if(
			saps_.begin(), saps_.end(), Sap::MatchName( name ) );

	if( found != saps_.end() )
	{
 		ODEMX_TRACE << log( "remove SAP" )
 				.detail( "name", name )
 				.scope( typeid(ServiceProvider) );

 		if( layer_ )
 		{
 			layer_->removeSap( name );
 		}

 		delete *found;
 		saps_.erase( found );
 		return true;
	}
 	return false;
}

Sap* ServiceProvider::getSap( const std::string& name ) const
{
	SapVec::const_iterator found = std::find_if(
			saps_.begin(), saps_.end(), Sap::MatchName( name ) );
			
	if( found != saps_.end() )
	{
		return *found;
	}
	return 0;
}

const ServiceProvider::SapVec& ServiceProvider::getSaps() const
{
	return saps_;
}

} } // namespace odemx protocol
