// File: inputmanager.h
// Created by: <Joern Reimerdes>
// Created on: 25.02.2005

// $Id$
// $Revision$
// $Date$

#ifndef __INPUTMANAGER_H
#define __INPUTMANAGER_H

extern "C"{
#include <stdint.h>
}

#include <map>

#ifndef __BASEMODULEMANAGER_H
#include <iwear/basemodulemanager.h>
#endif

#ifndef __EVENTDISPATCHER_H
#include <iwear/eventdispatcher.h>
#endif

#ifndef __FUNCTOR_H
#include <iwear/functor.h>
#endif

#ifndef __INPUTENUMS_H
#include <iwear_input/inputenums.h>
#endif

#ifndef __INPUTMODULE_H
#include <iwear_input/inputmodule.h>
#endif

#ifndef __INPUTDATA_H
#include <iwear_input/inputdata.h>
#endif

#ifndef __KEYINPUTDATA_H
#include <iwear_input/keyinputdata.h>
#endif

#ifndef __MOUSEINPUTDATA_H
#include <iwear_input/mouseinputdata.h>
#endif

#ifndef __SIGNALINPUTDATA_H
#include <iwear_input/signalinputdata.h>
#endif

#ifndef __JOYSTICKINPUTDATA_H
#include <iwear_input/joystickinputdata.h>
#endif

#ifndef __REGISTEREDINPUTFUNCTOR_H
#include <iwear_input/registeredinputfunctor.h>
#endif

using namespace std;
using namespace iwear;

namespace iwear {
namespace input {

/** Typedef for the pair which is to be inserted into the map. */
typedef pair<KeyInputEventType, 
	     RegisteredInputFunctor< Functor<KeyInputData> >*> KeyFunctorPair;
    
/** Typedef for the pair which is to be inserted into the map. */
typedef pair<MouseInputEventType, 
	     RegisteredInputFunctor< Functor<MouseInputData> >*> MouseFunctorPair;

/** Typedef for the pair which is to be inserted into the map. */
typedef pair<SignalInputEventType, 
	     RegisteredInputFunctor< Functor<SignalInputData> >*> SignalFunctorPair;

/** Typedef for the pair which is to be inserted into the map. */
typedef pair<JoystickInputEventType, 
	     RegisteredInputFunctor< Functor<JoystickInputData> >*> JoystickFunctorPair;

/** Map Typedef for input key functors. */
typedef multimap<KeyInputEventType, 
		 RegisteredInputFunctor< Functor<KeyInputData> >*> KeyInputFunctorMap;
	
/** Map Typedef for input mouse functors. */
typedef multimap<MouseInputEventType, 
		 RegisteredInputFunctor< Functor<MouseInputData> >*> MouseInputFunctorMap;

/** Map Typedef for input signal functors. */
typedef multimap<SignalInputEventType, 
		 RegisteredInputFunctor< Functor<SignalInputData> >*> SignalInputFunctorMap;

/** Map Typedef for input joystick functors. */
typedef multimap<JoystickInputEventType, 
		 RegisteredInputFunctor< Functor<JoystickInputData> >*> JoystickInputFunctorMap;

/** InputManager inherits from template class ModuleManager, the
 * template is instanciated with an enum of the known
 * input-module types (from input_enums.h) and the base-class of
 * all input-modules: InputModule.
 */
class InputManager : public 
ModuleManager<const string, InputModule, BaseModuleManager>{
    
public: 

    /** Creates a new InputManager.
     * @param basemodulemanager The global BaseModuleManager.
     * @param event_dispatcher The global EventDispatcher is needed to
     *  dispatch the input events.
     */	
    InputManager(BaseModuleManager* basemodulemanager, 
		 EventDispatcher* event_dispatcher, Configuration& c);

    EventDispatcher* get_eventdispatcher() { return event_dispatcher; }

    /** 
     * The destructor is virtual, for polymorphic reasons.
     */
    virtual ~InputManager(void);
	
    /**
     * Inherited function from ModuleManager - not needed here.
     */
    virtual const string get_type(const InputModule& input_module) const{
	return input_module.get_input_module_type();
    }

    /** The UID of the active application must be set, so the
     * inputmanagament can fire events as desired.
     * @param active_application_uid The uid of the active application.
     */
    inline void set_active_application(const uid& active_application_uid){
	this->active_application_uid = &(active_application_uid);
    }

    /** Gets the uid of the active application.
     * @return The uid of the active application.
     */
    inline const uid* get_active_application_uid( void ){
	return this->active_application_uid;
    }
	
    /** Add and register an external InputModule.
     * @param input_module A pointer to the InputModule which should 
     *  be registered.
     */
    virtual void register_external_module(Module* module);
	
    /** Add and register an internal InputModule.
     * @param input_module A pointer to the InputModule which should 
     *  be registered.
     */
    virtual void register_internal_module(Module* module);
	
    /** Deregisters an InputModule.
     * @param input_module A pointer to the InputModule which should
     *  be deregistered.
     */
    virtual void deregister_module(Module* module);
    
    /** Registers a KeyInputFunctor at the InputManagemer.
     * The functor will be encapsulated within a KeyInputEvent if the
     * the event is triggered.
     * @param key_input_event_type The type of the events on which the
     *  functor should be called.
     * @param key_input_functor The key input functor which should be
     *  called.
     */
    inline void 
    register_input_functor(KeyInputEventType key_input_event_type, 
			   Functor<KeyInputData>* key_input_functor,
			   const uid& application_uid,
			   bool call_when_not_active = false){
	d_nons << ANSI_CYAN << __FL__ << ANSI_NORMAL 
	       << "Registered Key Input Functor for application \"" 
	       << application_uid << "\". " << endl;
	RegisteredInputFunctor< Functor<KeyInputData> >* registered_input_functor = 
	    new RegisteredInputFunctor<Functor<KeyInputData> >(application_uid, 
							       key_input_functor, 
							       call_when_not_active);
  	KeyFunctorPair functor_pair = KeyFunctorPair(key_input_event_type, 
						     registered_input_functor);
  	this->key_input_functor_map.insert( functor_pair );
    }


    /** Registers a MouseInputFunctor at the InputManagemer.
     * The functor will be encapsulated within a MouseInputEvent if the
     * the event is triggered.
     * @param mouse_input_event_type The type of the events on which the
     *  functor should be called.
     * @param mouse_input_functor The mouse input functor which should be
     *  called.
     */
    inline void 
    register_input_functor(MouseInputEventType mouse_input_event_type, 
			   Functor<MouseInputData>* mouse_input_functor,
			   const uid& application_uid,
			   bool call_when_not_active = false){
	d_nons << ANSI_CYAN << __FL__ << ANSI_NORMAL 
	       << "Registered Mouse Input Functor for application \"" 
	       << application_uid << "\". " << endl;
	RegisteredInputFunctor< Functor<MouseInputData> >* registered_input_functor = 
	    new RegisteredInputFunctor<Functor<MouseInputData> >(application_uid, 
							       mouse_input_functor, 
							       call_when_not_active);
  	MouseFunctorPair functor_pair = MouseFunctorPair(mouse_input_event_type, 
						     registered_input_functor);
  	this->mouse_input_functor_map.insert( functor_pair );
    }

    /** Registers a SignalInputFunctor at the InputManagemer.
     * The functor will be encapsulated within a SignalInputEvent if the
     * the event is triggered.
     * @param signal_input_event_type The type of the events on which the
     *  functor should be called.
     * @param signal_input_functor The signal input functor which should be
     *  called.
     */
    inline void 
    register_input_functor(SignalInputEventType signal_input_event_type, 
			   Functor<SignalInputData>* signal_input_functor,
			   const uid& application_uid,
			   bool call_when_not_active = false){
	d_nons << ANSI_CYAN << __FL__ << ANSI_NORMAL 
	       << "Registered Signal Input Functor for application \"" 
	       << application_uid << "\". " << endl;

	RegisteredInputFunctor< Functor<SignalInputData> >* registered_input_functor = 
	    new RegisteredInputFunctor<Functor<SignalInputData> >(application_uid, 
							       signal_input_functor, 
							       call_when_not_active);
  	SignalFunctorPair functor_pair = SignalFunctorPair(signal_input_event_type, 
						     registered_input_functor);
  	this->signal_input_functor_map.insert( functor_pair );
    }

    /** Registers a JoystickInputFunctor at the InputManagemer.
     * The functor will be encapsulated within a JoystickInputEvent if the
     * the event is triggered.
     * @param joystick_input_event_type The type of the events on which the
     *  functor should be called.
     * @param joystick_input_functor The joystick input functor which should be
     *  called.
     */
    inline void 
    register_input_functor(JoystickInputEventType joystick_input_event_type, 
			   Functor<JoystickInputData>* joystick_input_functor,
			   const uid& application_uid,
			   bool call_when_not_active = false){
	d_nons << ANSI_CYAN << __FL__ << ANSI_NORMAL 
	       << "Registered Joystick Input Functor for application \"" 
	       << application_uid << "\". " << endl;
	RegisteredInputFunctor< Functor<JoystickInputData> >* registered_input_functor = 
	    new RegisteredInputFunctor<Functor<JoystickInputData> >(application_uid, 
							       joystick_input_functor, 
							       call_when_not_active);
  	JoystickFunctorPair functor_pair = JoystickFunctorPair(joystick_input_event_type, 
						     registered_input_functor);
  	this->joystick_input_functor_map.insert( functor_pair );
    }

    /** Deregisters an input functor from the InputManager.
     * @param key_input_event_type The type of the events on which the
     *  functor should be called. This is used for faster location of
     *  the functor which should be deregistered.
     * @param key_input_functor The key input functor which should be
     *  deregistered.
     */
    void deregister_input_functor(KeyInputEventType key_input_event_type, 
				  Functor<KeyInputData>* key_input_functor);
    
    /** Deregisters an input functor from the InputManager.
     * @param mouse_input_event_type The type of the events on which the
     *  functor should be called. This is used for faster location of
     *  the functor which should be deregistered.
     * @param mouse_input_functor The mouse input functor which should be
     *  deregistered.
     */
    void deregister_input_functor(MouseInputEventType mouse_input_event_type, 
				  Functor<MouseInputData>* mouse_input_functor);
    
    /** Deregisters an input functor from the InputManager.
     * @param signal_input_event_type The type of the events on which the
     *  functor should be called. This is used for faster location of
     *  the functor which should be deregistered.
     * @param signal_input_functor The signal input functor which should be
     *  deregistered.
     */
    void deregister_input_functor(SignalInputEventType signal_input_event_type, 
				  Functor<SignalInputData>* signal_input_functor);
    
    /** Deregisters an input functor from the InputManager.
     * @param joystick_input_event_type The type of the events on which the
     *  functor should be called. This is used for faster location of
     *  the functor which should be deregistered.
     * @param joystick_input_functor The joystick input functor which should be
     *  deregistered.
     */
    void deregister_input_functor(JoystickInputEventType joystick_input_event_type, 
				  Functor<JoystickInputData>* joystick_input_functor);

    /** Dispatches a key input event.
     * @param key_input_data A reference to the KeyInputData
     *  which should be dispatched by the InputManager.
     */
    void dispatch_key_event(KeyInputData& key_input_data);
    
    /** Dispatches a mouse input event.
     * @param mouse_input_data A reference to the MouseInputData
     *  which should be dispatched by the InputManager.
     */
    void dispatch_mouse_event(MouseInputData& mouse_input_data);
    
    /** Dispatches a signal input event.
     * @param signal_input_data A reference to the SignalInputData
     *  which should be dispatched by the InputManager.
     */
    void dispatch_signal_event(SignalInputData& signal_input_data);
    
    /** Dispatches a joystick input event.
     * @param joystick_input_data A reference to the JoystickInputData
     *  which should be dispatched by the InputManager.
     */
    void dispatch_joystick_event(JoystickInputData& joystick_input_data);
    

protected:
		
private:

    /** The uid of the active application. */
    const uid* active_application_uid;
	
    /**
     * The EventDispatcher used for the InputEvents.
     */
    EventDispatcher* event_dispatcher;

    /** Map for all key input functors which should be called. */
    KeyInputFunctorMap key_input_functor_map;
    
    /** Map for all mouse input functors which should be called. */
    MouseInputFunctorMap mouse_input_functor_map;

    /** Map for all signal input functors which should be called. */
    SignalInputFunctorMap signal_input_functor_map;

    /** Map for all joystick input functors which should be called. */
    JoystickInputFunctorMap joystick_input_functor_map;

    template<class P, class T, class Q>
    void dispatch_new_events(P& special_input_data, T special_input_all_event_type, 
			     multimap<T,RegisteredInputFunctor<Functor<P> >*>& functor_map);
    

}; // InputManager

    template<class P, class T, class Q> inline 
    void InputManager::dispatch_new_events(P& special_input_data, 
					   T special_input_event_type, 
					   multimap<T,RegisteredInputFunctor<Functor<P> >*>& functor_map){
	ThreadLocker thread_locker(Mutex); 
	/* Check the functors which are registered to a event type. */
 	typename multimap<T,RegisteredInputFunctor<Functor<P> >*>::iterator functor_iterator = 
 	    functor_map.find(special_input_event_type);
 	/* Go to next element of the multimap until the key changes. */
  	while (functor_iterator != functor_map.end() && 
	       functor_iterator->first == special_input_event_type ) {
	    /* If the functor should be called even if the application
	       is not acitve or of the active application uid fits to
	       the uid appliaction which created the functor dispatch
	       the event. */
	    if (functor_iterator->second->get_call_when_not_active()
		|| (this->active_application_uid != NULL 
		    && (*(functor_iterator->second->get_application_uid()) 
			== *(this->active_application_uid)))){
		Functor<P>* special_input_functor = 
		    functor_iterator->second->get_functor();
		/* Create key input event and dispatch it. */
		Q* special_input_event = 
		    new Q(*(special_input_functor), special_input_data);
//  		d_nons << ANSI_CYAN << __FFL__
//  		       << "Dispatch input event for Application: " 
//  		       << ANSI_NORMAL
//  		       << *(this->active_application_uid) 
//  		       << endl;
		event_dispatcher->dispatch(*special_input_event);  		       
//		special_input_event->dispatch();
	    }
  	    ++functor_iterator;
  	}
    }


} // input
} // iwear

#endif	//__INPUTMANAGER_H

