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

	\author Ralf Gerstenberger

	\date created at 2003/06/06

	\brief Declaration of odemx::synchronization::Wait

	\sa Wait.cpp

	\since 1.0
*/

#ifndef ODEMX_WAIT_INCLUDED
#define ODEMX_WAIT_INCLUDED

#ifdef ODEMX_USE_OBSERVATION

#include <odemx/base/Process.h>
#include <odemx/data/Producer.h>

#include <list>


namespace odemx {
namespace synchronization {

/** \class Wait

	\ingroup synch

	\author Ralf Gerstenberger

	\brief %Wait for termination of a number of process objects

	\note Wait supports Trace
	@note This class can only be used when ODEMX_USE_OBSERVATION is defined
	in odemx/setup.h

	%Wait is used to synchronize a process with the termination of
	one ore more partner processes.

	\since 1.0
*/
class Wait
:	public data::Producer
,	public base::ProcessObserver
{
public:

	/**
		\brief Construction for user-defined Simulation
		\param s
			pointer to Simulation object
		\param l
			label of this object
	*/
	Wait( base::Simulation& sim, const data::Label& label );

	/**
		\brief Construction and wait for user-defined Simulation
		\param s
			pointer to Simulation object
		\param l
			label of this object
		\param p1
			process to wait for

		This constructor creates a Wait object and waits for
		Process \p p1 to finish. If the blocked Process is interrupted,
		it is reactivated and the constructor returns. To check whether
		the process was interrupted, use the isInterrupted() method of
		Process.
	*/
	Wait( base::Simulation& sim, const data::Label& label, base::Process* p1 );

	/**
		\brief Construction for user-defined Simulation
		\param s
			pointer to Simulation object
		\param l
			label of this object
		\param p1
			first process to wait for
		\param p2
			second process to wait for
		\param all
			wait for \p all processes

		This constructor creates a Wait object and waits for the Process
		objects \p p1 and (or) \p p2 to finish. If the blocked Process
		is interrupted, it is reactivated and the constructor returns.
		To check whether the process was interrupted, use the isInterrupted()
		method of Process.
	*/
	Wait( base::Simulation& sim, const data::Label& label, base::Process* p1,
			base::Process* p2, bool all = true );

	/**
		\brief Construction for user-defined Simulation
		\param s
			pointer to Simulation object
		\param l
			label of this object
		\param p1
			first process to wait for
		\param p2
			second process to wait for
		\param p3
			third process to wait for
		\param all
			wait for \p all processes

		This constructor creates a Wait object and waits for the Process
		objects \p p1, \p p2 and(or) \p p3 to finish. If the blocked Process
		is interrupted, it is reactivated and the constructor returns.
		To check whether the process was interrupted, use the isInterrupted()
		method of Process.
	*/
	Wait( base::Simulation& sim, const data::Label& label, base::Process* p1,
			base::Process* p2, base::Process* p3, bool all = true );

	/**
		\brief Construction for user-defined Simulation
		\param s
			pointer to Simulation object
		\param l
			abel of this object
		\param size
			number of processes in \p p
		\param p
			processes to wait for
		\param all
			wait for \p all processes

		This constructor creates a Wait object and waits for the Process
		objects stored in \p p to finish. If the blocked Process
		is interrupted, it is reactivated and the constructor returns.
		To check whether the process was interrupted, use the isInterrupted()
		method of Process.
	*/
	Wait( base::Simulation& sim, const data::Label& label, int size, base::Process* p[],
			bool all = true );

	/// Destruction
	virtual ~Wait();

	/// Add process \p p to list of observed processes
	void addProcess( base::Process* p );

	/// Remove process \p p from list of observed processes
	void removeProcess( base::Process* p );

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

	/// Get Condition (wait for one or all observed Process objects to finish)
	bool getCondition() const;

	/// Set Condition (wait for one or all observed Process objects to finish)
	void setCondition( bool all = true );

	/**
		\brief Wait for one / all observed processes to finish

		Wait for one or all observed processes to finish. If the blocked
		Process is interrupted it is reactivated and wait() returns false.
		Otherwise wait() returns true.
	*/
	bool wait();

public:
	// ProcessObserver functions
	virtual void onChangeProcessState( base::Process* sender,
			base::Process::ProcessState oldState,
			base::Process::ProcessState newState );

private:
	base::Process* waitCaller_; ///< blocked process
	base::ProcessList observedProcesses_; ///< observed processes
	bool waitForAll_; ///< condition

	void initObservedList( size_t size, base::Process* p[] ); ///< init observed list
	bool checkObserved(); ///< check condition
};

} } // namespace odemx::synchronization

#endif /* ODEMX_USE_OBSERVATION */

#endif
