/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * 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_EVENTDISPATCHER_H
#define __IWEAR_EVENTDISPATCHER_H

#include <queue>

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

#ifndef __IWEAR_SERVICE_H
#include <iwear/service.h>
#endif

#include <boost/function.hpp>

namespace iwear
{

enum event_priority
{
    prio_low,
    prio_normal,
    prio_urgent,
    num_event_priority,
};

inline const char * to_string( event_priority ep )
{
    switch(ep)
    {
	case prio_low:
	    return "event_priority::prio_low";
	case prio_normal:
	    return "event_priority::prio_normal";
	case prio_urgent:
	    return "event_priority::prio_urgent";
	default:
	    return "event_priority::<invalid_value>";
    }
}

inline std::ostream& operator<<( std::ostream& o, event_priority ep )
{
    o << to_string(ep);
    o << "(";
    o << static_cast<uint32_t>(ep);
    o << ")";
    return o;
}

class EventBase;
class EventScheduler;
/**
 * The actual new EventDispatcher is now mainly a wrapper around some
 * eventscheduler. Why not simply use some EventScheduler directly ? Because
 * with the configuration we should be able to have a general setup within the
 * EventDispatcher about which the user does not need to care.
 */
class EventDispatcher : public ThreadLocked, public Service
{
private:

    EventScheduler* evsched;

    /**
     * Does the actual event execution which is independent from real priority.
     */
IWLOCAL void execute_event( EventBase* ev );
   
    /**
     * Checks the queues for events and delivers them.
     */
/*
IWLOCAL void deliver_events( void );

IWLOCAL void deliver_events( std::queue<EventBase*>& );
*/
IWLOCAL void sync_state( void );
protected:
public:
    /**
     * We get the configuration from the service manager
     */
    EventDispatcher( ServiceManager* ) IWAPI;

IWAPI virtual ~EventDispatcher();
    /**
     * This will save an event in the internal event queue, which will be
     * delivered in another thread context. 
     * The Event you pass will be derived by Event<>, see there for more
     * information about how to create your own events.
     * @note If you specify a priority, you should be aware that first all
     * events with the highest priority are delivered, and if there are no more
     * left those with the next lower are delivered and so on. This means that
     * if during this process another event arrives, it will be executed before
     * the one thats waiting longer. So it might happen that if the system is
     * really busy an event with low priority will never be delivered.
     */
IWAPI void dispatch( EventBase& evt, event_priority prio = prio_normal );

    /**
     * This is a convenience function which will internally create an event
     * object. With this function, you can make use of the facilities offered
     * by boost::bind and maybe even by boost::lambda expressions.
     * @note Whenever feasible this version should be preferred over the old interface.
    */
    void dispatch( const boost::function<void(void)>&, event_priority prio = prio_normal ); 

    /**
     * Starts execution of the dispatcher and its thread.
     */
IWAPI virtual void Start( void );

    /**
     * Initializes needed resources
     */
IWAPI virtual void Init( void );

    /**
     * Stops the thread and empties all queues (delivers pending events but
     * does not accept new ones).
     */
IWAPI virtual void Stop( void );

    /**
     * Resets the Event Dispatcher.
     * @warning All events in the queue will be removed without beeing delivered ! 
     */
IWAPI virtual void Reset( void );

    /**
     * Suspends execution. This means, empties all queues(and deliveres pending
     * events) and then does not accept new ones.
     */
IWAPI virtual void Suspend( void );

    /**
     * Paused event delivery. New events will be accepted and queued, but
     * delivered after resume.
     */
IWAPI virtual void Pause( void );

    /**
     * Goes on with event accepting and event delivery.
     */
IWAPI virtual void Resume( void );

    /**
     * Returns our name ;)
     */
IWAPI virtual const std::string get_name( void );

IWAPI virtual service_type get_type( void ) { return service_system; }

IWAPI virtual service_state get_state( void );

};

}
#endif
