//----------------------------------------------------------------------------
//	Copyright (C) 2007, 2008, 2009 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 Timer.h

	\author Ronald Kluth

	\date created at 2007/04/04

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

	\sa Timer.cpp

	\since 2.0
*/

#ifndef ODEMX_TIMER_INCLUDED
#define ODEMX_TIMER_INCLUDED

#include <odemx/base/Event.h>
#include <odemx/base/SimTime.h>
#include <odemx/synchronization/Memory.h>

namespace odemx {

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

namespace synchronization {

class TimerObserver;

/// maximum priority
extern const int MAX_PRIORITY;

/** \class Timer

	\ingroup synch

	\author Ronald Kluth

	\brief %Timers trigger an event to wake up suspended processes in a model.

	\note %Timer supports Observation.
	\note %Timer supports Trace.

	\sa Process, Event, Simulation

	%Timer is a class provided for convenience. When processes are suspended
	using the \p Process::wait() function, a Timer can be used to wake up
	processes if no other Memory object becomes available within a certain
	amount of time. Timers should not be used to implement arbitrary events,
	instead different kinds of events should be derived from the
	base class Event. By default, Timers have maximum priority of all
	schedulable objects and as such they will be triggered first when
	simulation time reaches their execution time.

	\since 2.0
*/

class Timer
:	public base::Event // is a DataProducer
,	public IMemory // derive from interface to avoid DataProducer ambiguity
,	public data::Observable< TimerObserver >
{
public:

	/**
		\brief Construction for user-defined Simulation
		\param sim
			pointer to the Simulation object
		\param l
			label of this object
		\param to
			initial timer observer
	*/
	Timer( base::Simulation& sim, const data::Label& label, TimerObserver* obs = 0 );

	/// Destruction
	virtual ~Timer();

	/**
		\name Timer Scheduling

		These functions are used to schedule a timeout event
		in simulation time. Timers are kept in the same
		schedule as processes and other events and they follow the
		same scheduling rules. However, their default priority is
		set to maximum.

		@{
	*/
	/**
		\brief Trigger the timeout at simulation time \p now + \p t

		This function schedules the timer at time \p now + \p t before
		all other processes and events at that point in simulation time.
		Scheduling a
		%Timer at SimTime \p now will not suspend the execution of
		the current process . The calling process, however, should suspend
		its execution via Process::wait(), which will automatically
		register that process with the Memory objects given as parameters.
	*/
	void setIn( base::SimTime t );

	/**
		\brief Trigger the timeout at absolute simulation time \p t

		This function schedules the timer at the absolute simulation
		time \p t before all other processes and events with the same
		execution time.
		Scheduling a %Timer at SimTime \p now will not suspend the execution of
		the current process. The calling process, however, should suspend
		its execution via Process::wait(), which will automatically
		register that process with the Memory objects given as parameters.
	*/
	void setAt( base::SimTime t );

	/**
		\brief Reschedule the timeout to simulation time \p now + \p t.

		This function reschedules the timer at time \p now + \p t before
		all other processes with the same execution time
	*/
	void reset( base::SimTime t );

	/**
		\brief Remove the %Timer from the schedule

		This function removes the timer from the execution list
	*/
	void stop();

	/**
		\brief Check if the %Timer is scheduled for execution
		\return
			true when listed in schedule

		This function reports whether the time is scheduled or not.
	*/
	bool isSet();
	//@}

	/**
		\brief Register a process to wake with this timer
		\return
			true if sucessfully added \p p to timer memory
		\param p
			process to be remembered

		This function stores process \p p in the timer's memory.
		All the stored processes are rescheduled when the
		timeout is triggered.

		\sa removeProcess()
	*/
	bool registerProcess( base::Process* p );

	/**
		\brief Remove a registered process from timer's memory
		\return
			true if sucessfully remove \p p
		\param p
			process to be removed

		This function removes process \p p from the timer's memory.

		\sa registerProcess()
	*/
	bool removeProcess( base::Process* p );

	/// Get a list of the waiting processes
	const base::SchedList& getWaiting() const;

protected:

	/**
		\brief Reimplemented from Event, schedules all remembered Processes

		This function alerts all processes in the timer's memory.
		These processes are then rescheduled at time \p now.
	*/
	virtual void eventAction();

	/**
	 * @name IMemory implementation
	 *
	 * To preserve a single inheritance line of DataProducer, Timer only
	 * inherits from IMemory and has to implement its functions almost
	 * identical to Memory.
	 * @{
	 *
	 * @sa IMemory
	 */
public:
	/// Get memory type
	virtual IMemory::Type getMemoryType() const;
	/// Check availability, timers are available when they are not scheduled
	virtual bool isAvailable();
	/// Alert all waiting processes after a timeout
	virtual void alert();

private:
//	friend class base::Process;

	/// Store a schedulable object
	virtual bool remember( base::Sched* newObject );
	/// Remove a schedulable object from memory
	virtual bool forget( base::Sched* rememberedObject );
	/// Erase all schedulable objects from memory
	virtual void eraseMemory();

private:
	/// Internal memory object to which all IMemory-calls are forwarded
	Memory memory_;
	//@}
};

/** \interface TimerObserver

	\author Ronald Kluth

	\brief Observer for Timer-specific calls.

	\sa Timer, Event

	\since 2.0
*/
class TimerObserver
:	public base::EventObserver
{
public:
	virtual ~TimerObserver() {}

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

	/// Observe activation with relative time
	virtual void onSetIn( Timer* sender, base::SimTime t ) {}
	/// Observe activation with absolute time
	virtual void onSetAt( Timer* sender, base::SimTime t ) {}
	/// Observe timer reset and rescheduling
	virtual void onReset( Timer* sender, base::SimTime oldTime, base::SimTime newTime ) {}
	/// Observe timer stop
	virtual void onStop( Timer* sender ) {}

	/// Observe process registration
	virtual void onRegisterProcess( Timer* sender, base::Process* p ) {}
	/// Observe process removal
	virtual void onRemoveProcess( Timer* sender, base::Process* p ) {}
	/// Observe timeout, execution of the timer
	virtual void onTimeout( Timer* sender ) {}
};

} } // namespace odemx::synchronization

#endif /*ODEMX_TIMER_INCLUDED*/

