//----------------------------------------------------------------------------
//	Copyright (C) 2002, 2004 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 Bin.h

	\author Ralf Gerstenberger

	\date created at 2002/03/26

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

	\sa Bin.cpp

	\since 1.0
*/

#ifndef ODEMX_BIN_INCLUDED
#define ODEMX_BIN_INCLUDED

#include <odemx/base/SimTime.h>
#include <odemx/data/Producer.h>
#include <odemx/synchronization/Queue.h>
#include <odemx/data/Observable.h>

namespace odemx {

// forward declarations
namespace base {
class Process;
class Simulation;
}

namespace synchronization {

class BinObserver;

/** \class Bin

	\ingroup synch

	\author Ralf Gerstenberger

	\brief %Bin is a single bounded (number of token greater or
	equal to zero) token abstract resource.

	\note Bin supports Observation
	\note Bin supports Trace
	\note Bin supports Report

	Bin is a low bounded (token number >= 0) token abstract resource
	for synchronising Process objects. A process is blocked in take()
	if the requested number of token is greater than the available
	number of token. It is reactivated when enough token are given (back)
	to the resource. If multiple processes are waiting for reactivation
	process-priority and FIFO-strategy are used to choose the process.
	Bin is generally used for producer and consumer synchronisation.

	\since 1.0
*/
class Bin
:	public data::Producer
,	public data::Observable< BinObserver >
{
public:

	/**
		\brief Construction for user-defined Simulation
		\param s
			pointer to Simulation object
		\param l
			label for this object
		\param startTokenNumber
			initial number of token in Bin
		\param o
			initial observer
	*/
	Bin( base::Simulation& sim, const data::Label& label, std::size_t initialTokens,
			BinObserver* obs = 0 );

	/// Destruction
	~Bin();

	/**
		\name Token management

		@{
	*/
	/**
		\brief Take \p n token

		Takes \p n token from resource if possible. Otherwise
		the current process is blocked until enough token are
		available. If a blocked process is interrupted it is
		reactivated and the function returns 0. Without interruption
		take returns \p n.
	*/
	std::size_t take( std::size_t n );

	/**
		\brief Give \p n token

		Gives \p n token to resource. Blocked process objects
		could be activated by this call.
	*/
	void give( std::size_t n );

	/// Number of tokens available
	std::size_t getTokenNumber() const;
	//@}

	/// Get list of blocked processes
	const base::ProcessList& getWaitingProcesses() const;

private:
	/// available number of tokens
	std::size_t tokens_;
	/// process management
	Queue takeQueue_;

	/// Helper for quick access to the current simulation time
	base::SimTime getTime() const;
	/// Helper for quick access to the currently running object
	base::Sched* getCurrentSched();
	/// Helper for quick access to the current process
	base::Process* getCurrentProcess();
	/// Get the label of the current context (process or simulation)
	const data::Label& getPartner();
};

/** \interface BinObserver

	\author Ralf Gerstenberger

	\brief Observer for Bin-specific events.

	\sa Bin

	\since 1.0
*/
class BinObserver
{
public:
	virtual ~BinObserver() {}

	/// Observe construction
	virtual void onCreate( Bin* sender ) {}

	/// Observe failed attempt to take @c n tokens
	virtual void onTakeFail( Bin* sender, std::size_t n ) {}
	/// Observe successful attempt to take @c n tokens
	virtual void onTakeSucceed( Bin* sender, std::size_t n ) {}
	/// Observe return of @c n tokens
	virtual void onGive( Bin* sender, std::size_t n ) {}

	/// Observe change of the number of tokens
	virtual void onChangeTokenNumber( Bin* sender, std::size_t oldTokenNumber,
			std::size_t newTokenNumber ) {}
};

} } // namespace odemx::synchronization

#endif

