//----------------------------------------------------------------------------
//	Copyright (C) 2002-2008 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 ResTChoice.h

	\author Ronald Kluth

	\date created at 2008/02/18

	\brief Declaration of odemx::synchronization::ResTChoice and observer

	\note This header file is not meant for inclusion, use
	odemx/synchronization/ResTemplate.h instead.

	\sa ResTChoice.cpp

	\since 2.1
*/

#ifndef ODEMX_RES_T_CHOICE_INCLUDED
#define ODEMX_RES_T_CHOICE_INCLUDED

#include <odemx/synchronization/res/ResTBase.h>

namespace odemx {
namespace synchronization {

//forward declaration
template < typename Token >
class ResTChoiceObserver;

/** \class ResTChoice

	\author Ronald Kluth

	\brief ResTChoice is an abstract base class for resources holding
	objects of type Token

	ResTChoice is a resource class for synchronizing Process objects based
	on the availability of selected resources. A process is blocked in
	acquire() if not enough tokens matching the selection criteria
	are available. It is reactivated when enough tokens are released
	to the resource. If multiple process objects are waiting for
	reactivation, process queue priority and FIFO-strategy are used to
	choose the process.

	\note ResTChoice supports Observation
	\note ResTChoice supports Trace

	\sa Res, ResT

	\since 2.1
*/
template < typename Token >
class ResTChoice:
	public ResTBase< Token >,
	public data::Observable< ResTChoiceObserver< Token > >
{
public:

	using data::Producer::trace;
	using data::Producer::debug;
	using data::Producer::info;
	using data::Producer::warning;
	using data::Producer::error;
	using data::Producer::fatal;
	using data::Producer::statistics;
	using data::Producer::log;
	using data::Producer::param;
	using data::Producer::count;
	using data::Producer::update;
	using data::Producer::reset;

	/// function type for coding selections
	typedef bool( *Selection )( base::Process* owner, Token* t );

	/**
	 * \copydoc ResTBase(Simulation*,Label,std::vector<Token>&,ResTBaseObserver<Token>*)
	 */
	ResTChoice( base::Simulation& sim, const data::Label& label,
			std::vector< Token >& initialResources,
			ResTChoiceObserver< Token >* o = 0 );

	/// Destruction
	virtual ~ResTChoice();

	/**
		\name Token usage

		These functions provade access for resource usage by Processes.
		Tokens can be requested and thus acquired when then are
		available. When the tokens are not needed anymore, the owning
		Process	can release them.

		@{
	*/
	/**
		\brief acquire a token

		Required implementation of acquire, will output an error
		to
	*/
	virtual Token* acquire();

	/**
		\brief find and acquire a token

		If no token matching the Selection condition is available,
		the current process is blocked
	*/
	Token* acquire( typename ResTChoice< Token >::Selection select );

	/**
		\brief find and acquire token

		If there are not enough tokens matching the Selection condition
		available, the current process is blocked
	*/
	const std::vector< Token* > acquire( Selection select, std::size_t n );

private:

	/// current simulation time
	base::SimTime getCurrentTime();
	
	/// current process
	base::Process* getCurrentProcess();
	
	/// current scheduled object
	base::Sched* getCurrentSched();

	/// help method to find tokens matching the selection
	bool getMatchingTokens( Selection select, std::size_t n,
							std::vector< Token* >& result );
};

/** \interface ResTChoiceObserver

	\author Ronald Kluth

	\brief Observer for ResTChoice-specific events

	\since 2.1

	\sa ResT
*/
template < typename Token >
class ResTChoiceObserver: public ResTBaseObserver< Token > {
public:
	typedef typename ResTBaseObserver< Token >::ResType ResType;

	virtual ~ResTChoiceObserver() {}

	/// Failed attempt to acquire n token
	virtual void onAcquireFail(ResType* sender, std::size_t n) {}
	/// Successful attempt to acquire n token
	virtual void onAcquireSucceed(ResType* sender, std::size_t n) {}
};

} } // namespace odemx::synchronization

#endif /*ODEMX_RES_T_CHOICE_INCLUDED*/
