//------------------------------------------------------------------------------
//	Copyright (C) 2002, 2004, 2007, 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 ExecutionList.h
 * @author Ralf Gerstenberger
 * @date created at 2002/01/23
 * @brief Declaration of odemx::base::ExecutionList
 * @sa ExecutionList.cpp
 * @since 1.0
 */

#ifndef ODEMX_EXECUTIONLIST_INCLUDED
#define ODEMX_EXECUTIONLIST_INCLUDED

#include <odemx/base/SimTime.h>
#include <odemx/base/TypeDefs.h>
#include <odemx/data/Label.h>
#include <odemx/data/Producer.h>
#include <odemx/data/Observable.h>
#include <CppLog/Channel.h>

namespace odemx {

namespace data { class SimRecord; }

namespace base {

// forward declarations
class Scheduler;
class Simulation;

typedef std::tr1::shared_ptr< Log::Channel< data::SimRecord > > ChannelPtr;

/** \class ExecutionList

	\ingroup base

	\author Ralf Gerstenberger

	\brief ExecutionList implements an execution schedule for Sched objects.

	\note ExecutionList supports Observation.

	ExecutionList is used to manage the Sched execution order. A Sched object
	is scheduled at a given time considering its priority and a FIFO- or LIFO-
	strategy, or in relation to an already scheduled object.

	\since 1.0
*/
class ExecutionList
:	public data::Producer
{
public:
	/// Construction with Simulation
	ExecutionList( Simulation& sim, const data::Label& label );

	/// Destruction
	virtual ~ExecutionList();

	/**
		\brief Print the schedule

		This function prints a simple representation of the
		execution list to stdout.
	*/
	void logToChannel( const ChannelPtr channel ) const;

	/**
		\name Sched Management

		@{
	*/
	/**
		\brief append Sched

		\param p
			pointer to Sched

		Appends Sched \p p at its execution time.
		If there are already Sched objects scheduled at
		the execution time of \p p, addSched will consider
		the priorities and use the FIFO strategy.

		\sa insertSched
	*/
	void addSched( Sched* s );

	/**
		\brief insert Sched

		\param p
			pointer to Sched

		Inserts Sched \p p at its execution time.
		If there are already Sched objects scheduled at
		the execution time of \p p, insertSched will consider
		the priorities and use the LIFO strategy.

		\sa addSched
	*/
	void insertSched( Sched* s );

	/**
		\brief insert Sched \p p after \p previous

		\param p
			pointer to new Sched object

		\param previous
			pointer to Sched object after which the new Sched
			should be inserted

		Inserts Sched \p p after the \p previous Sched object
		in ExecutionList.

		\note insertSchedAfter will change the priority of
		Sched \p p if necessary.

		\sa insertSchedBefore
	*/
	void insertSchedAfter( Sched* s, Sched* partner );

	/**
		\brief insert Sched \p p before \p next

		\param p
			pointer to new Sched

		\param next
			pointer to Sched before which the new Sched
			should be inserted

		Inserts Sched \p p before the \p next Sched
		in ExecutionList.

		\note insertSchedBefore will change the priority of
		Sched \p p if necessary.

		\sa insertSchedAfter
	*/
	void insertSchedBefore( Sched* s, Sched* partner );

	/**
		\brief remove Sched

		Removes Sched \p p from ExecutionList.
	*/
	void removeSched( Sched* s );
	//@}

	/**
		\brief top most Sched in ExecutionList

		\return
			pointer to top most Sched in ExecutionList
	*/
	Sched* getNextSched() const;

	/**
	 * @brief Get the execution time of the first schedule entry
	 * @return 0 if schedule is empty
	 */
	SimTime getNextExecutionTime() const;

	/**
		\brief check if ExecutionList is empty
	*/
	bool isEmpty() const;

	/**
		\brief get simulation time

		\return
			current simulation time
	*/
	SimTime getTime();

	// Implementation
private:
	/// Map type to associate simulation times with lists of scheduled objects
	typedef std::map< SimTime, SchedList > Schedule;
	/// Actual schedule holding pointers to Sched objects sorted by time and priority
	Schedule schedule_;

	friend class Scheduler;
	/**
		\brief inSort Sched \p e in Sched list

		\param e
			pointer to Sched

		\param fifo
			use FIFO or LIFO strategy for inSort
	*/
	void inSort( Sched* s, bool fifo = true );
};

} } // namespace odemx::base

#endif
