/**
 * @file
 * $Id: eventdispatcher.h 2577 2005-10-02 09:47:13Z plasmahh $
 * $Revision: 2577 $
 * $Author: plasmahh $
 * $Date: 2005-10-02 11:47:13 +0200 (So, 02 Okt 2005) $
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation as in version 2 of the License.

 * 
 * The iWear Framework 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 General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_EVENTSCHEDULER_H
#define __IWEAR_EVENTSCHEDULER_H

#ifndef __IWEAR_THREAD_H
#include <iwear/thread.h>
#endif

#include <iwear/conditional.h>
#include <iwear/service.h>
#include <vector>
#include <queue>

using std::vector;

namespace iwear
{

class EventBase;
/**
 * One thread that schedules events to be delivered. This one should not be
 * used outside the librar so we mark it as local.
 */
class IWLOCALT ScheduleThread : public Thread
{
private:
protected:
    /**
     * if we still need to run this thread.
     */
    bool needrun;

    /**
     * last time this thread did anything.
     */
    timeval lastfire;

    /**
     * the queue with all the events.
     */
    std::queue<EventBase*> equeue;

    virtual void Run( void );

    Conditional cond;

    uint32_t maxev;
    
    float softo;

    float hato;

    /**
     * For debugging purposes only. Never use this pointer for anything else
     * than printing !
     */
    EventBase* actual_event; 

    /**
     * Actually deliver the event, we assume were in unlocked state in this
     * function and so dont touch internal things other than the lastfire.
     */
    void deliver_event( EventBase* );
public:

    /**
     * If any of those values is 0, it means unlimited.
     */
    ScheduleThread( EventDispatcher&, uint32_t max_events, float soft_timeout, float hard_timeout );

    ~ScheduleThread( );
    void Stop( void );

    bool soft_timeout( void );

    bool hard_timeout( void );

    void dump ( void );
    /**
     * This asks for an event to be scheduled. On succes (the event is queued
     * to be delivered) 0 is returned, if the event is rejected (e.g. because
     * of full queues, or timeouts reached) the event is returned back.
     */
    EventBase* schedule( EventBase* ev );
};

/**
 * Base scheduler class that will schedule to the single threads. This is the
 * class api that will be used to interface with things. Since we only use it
 * internally within the evdis only, we make this whole thing local.
 */
class IWLOCALT EventScheduler: public virtual ThreadLocked, public Service
{
private:
protected:
    EventDispatcher& evdis;
public:

    EventScheduler( EventDispatcher&, ServiceManager* );

    virtual void schedule( EventBase& ev ) = 0;

    virtual ~EventScheduler();
};

/**
 * Round Robin scheduler. Schedules the events to the threads in a round robin
 * way, trying to detect deadlocked threads by imposing a timeout on them. If
 * a timeout was detected then the thread is not used any more.
 * XXX maybe put this in its own header ?
 */
class IWLOCALT RREventScheduler: public EventScheduler
{
private:
protected:
    vector<ScheduleThread*> threads;

    uint32_t actual_thread;
    uint32_t max_t;
    uint32_t min_t;
    uint32_t maxev;
    float hard_to;
    float soft_to;
    bool abandon;

    IWLOCAL void examine_thread( ScheduleThread* st );

public:
    /**
     * The event dispatcher should read its config values and instatiate the
     * correct scheduler with parameters here.
     *
     * @param max_threads This is maximum number of threads the system should
     * use at all.
     * @param min_threads Is the minimum number of threads in the system. This
     * number will be spawned at start, and if the load decreases, threads
     * might get deleted down to a minimum number.
     * @param max_event_per_thread maximum number of events a thread should have in its queue. If
     * the number is reached, a thread will reject an event to be delivered.
     * @param thread_soft_timeout If this timeout for event delivery is
     * reached, a thread refuses further events to be delivered.
     * @param thread_hard_timeout If this timeout is reached, the thread will
     * be abandoned, its queue emptied to another thread and a new one as a
     * replacement will be started.
     * @param hard_abandon If set to true, the system will try to kill the thread.
     * @warning setting hard_abandon to true might result in memory leaks, as
     * well as a recursion effect that will spawn threads indefinetly if the
     * target thread cannot be killed.
     */
    RREventScheduler( EventDispatcher&, ServiceManager* sm, uint32_t max_threads, uint32_t min_threads,
	    uint32_t max_event_per_thread,
	    float thread_soft_timeout, float thread_hard_timeout, bool hard_abandon ) IWLOCAL;

    IWLOCAL virtual ~RREventScheduler( );
    IWLOCAL virtual void schedule( EventBase& ev );

    /**
     * Starts all the threads created in init
     */
IWLOCAL virtual void Start( void );

    /**
     * Creates threads, but does not start them.
     */
IWLOCAL virtual void Init( void );

    /**
     */
IWLOCAL virtual void Stop( void );

    /**
     */
IWLOCAL virtual void Reset( void );

    /**
     */
IWLOCAL virtual void Suspend( void );

    /**
     */
IWLOCAL virtual void Pause( void );

    /**
     */
IWLOCAL virtual void Resume( void );

IWLOCAL virtual const string get_name( void );

IWLOCAL virtual service_type get_type( void );
};

}
#endif
