//------------------------------------------------------------------------------
//	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 Sched.h
 * @author Ronald Kluth
 * @date created at 2007/01/24
 * @brief Declaration of odemx::base::Sched
 * @sa Sched.cpp
 * @since 2.0
 */

#ifndef ODEMX_BASE_SCHED_INCLUDED
#define ODEMX_BASE_SCHED_INCLUDED

#include <odemx/base/SimTime.h>
#include <odemx/base/TypeDefs.h>
#include <odemx/data/Producer.h>

namespace odemx {

// forward declaration
namespace base { class Sched; }

/**
	\brief Comparison operator for Sched objects
	\par first
		first Process
	\par second
		second Process

	This operator compares two Sched objects. The
	operator returns true if the execution time of
	\p first is less than that of \p second. If both have the same
	execution time, the priority is used. True is returned if priority
	of \p first is higher than that of \p second.
*/
extern bool operator<( const base::Sched& first, const base::Sched& second );

namespace base {

// forward declaration
class ExecutionList;

/** \class Sched

	\ingroup base

	\author Ronald Kluth

	\brief %Sched is the interface for all schedulable objects in a model.

	\sa Simulation, ExecutionList, Event, Process

	%Sched is the abstract base class for all schedulable bjects.
	It declares all functions needed for the scheduling
	mechanism of ODEMx. This layer of abstraction was inserted to allow
	scheduling of different kinds of objects. The schedule works on
	polymorphic pointers of type Sched. The library supports event-based
	as well as process-based simulation models. Event and Process are
	Sched-derived classes that implement the interface.

	\since 2.0
*/
class Sched
:	public data::Producer
{
public:
	/**
		\brief Sched types

		Sched types are a means to handle the execution of different
		types of simulation objects, in this case Events and Processes.
		When different kinds of objects can be scheduled, the Simulation
		has to decide how to proceed when the simulation time reaches the
		execution time of an object.
	*/
	enum SchedType
	{
		PROCESS,	///< Simulation must start this process's coroutine
		EVENT		///< Simulation only needs to execute an event action
	};

public:

	/**
		\brief Construction
		\param st
			type of the schedulable object, from enum Sched::SchedType
	*/
	Sched( Simulation& sim, const data::Label& label, SchedType st );

	/// Destruction
	virtual ~Sched();

	/**
		\name Scheduling interface

		These functions are used by the ExecutionList to schedule objects
		according to their execution time and their priority. Every
		class of schedulable objects must implement these pure virtual
		functions.

		@{
	*/
	/**
		\brief Get execution time
		\return
			execution time of the object

		This function returns the execution time of the Sched object.
		Processes and Events are scheduled for execution at their execution
		time.
	*/
	virtual SimTime getExecutionTime() const = 0;

	/**
		\brief Set execution time
		\return
			previous execution time

	 	This internal function is used by the library. It should
	 	never be called directly! Use scheduling functions instead.
	*/
	virtual SimTime setExecutionTime( SimTime time ) = 0;

	/**
		\brief Get priority
		\return
			scheduling priority

		This function returns the current Sched priority.
		If the priority is changed, the position of the object in the
		execution schedule and in queues is updated. This can cause a
		switch to another Sched object.
	*/
	virtual Priority getPriority() const = 0;

	/**
		\brief Set new priority
		\return
			previous Sched priority

		This function changes the scheduling priority. The position
		in the execution schedule and in queues is affected by
		priority changes.
	*/
	virtual Priority setPriority( Priority newPriority ) = 0;

	/**
		\brief Check if Sched object is in schedule

		This function checks a boolean member which is set to true
		when a scheduling function was called on this event.
	*/
	bool isScheduled() const;
	//@}

	/**
		\name Sched execution

		These functions are used to schedule a process
		in simulation time.

		@{
	*/
	/**
		\brief Determine the Sched object's type
		\returns
			SchedType of this schedulable Object

		The type of Sched objects cannot change, it is set in
		the constructors of Event and Process. This internal
		function is used during simulation computation to
		determine the the correct path of execution for this object.
	*/

	SchedType getSchedType() const;

	/**
		\brief Execution of Sched object

		This virtual function is used polymorphically by Simulation
		to execute the current Sched object.

		\sa getSchedType(), Simulation::exec()
	*/
	virtual void execute() = 0;
	//@}

	/**
		\brief Get current simtime
		\return
		current simulation time

		This function returns the current simulation time.
	*/
	SimTime getTime() const;
private:
	SchedType schedType_; 	///< Event or Process
	bool scheduled_; 		///< determine whether the object is scheduled
	std::pair< SimTime, SchedList* > scheduleLoc_;
	SchedList::iterator execListIter_; ///< remember position in ExecutionList

	friend class ExecutionList;
	friend bool odemx::operator<( const base::Sched& first, const base::Sched& second );
};

} } // namespace odemx::base

#endif /* ODEMX_BASE_SCHED_INCLUDED */
