// {{{ the iWear header 
/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the Framework Core Library
 *
 * 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 __APPLICATIONBASE_H
#define __APPLICATIONBASE_H

#ifndef __IWEAR_I18N_H
#include <iwear/i18n.h>
#endif

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

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

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

#ifndef __INPUTMANAGER_H
#include <iwear_input/inputmanager.h>
#endif

#ifndef __OUTPUTMANAGER_H
#include <iwear_output/outputmanager.h>
#endif

#ifndef __SENSORMANAGER_H
#include <iwsens/sensormanager.h>
#endif

#ifndef __MENU_H
#include <iwear_uiservices/menu.h>
#endif


// Our namespaces
using namespace std;
using namespace iwear;
using namespace iwear::output;
using namespace iwear::input;
using namespace iwear::sensor;


namespace iwear{

    // Forward Declarations (namespace iwear)
    class ServiceManager;
    class EventBase;
    class Configuration;

    namespace sensor{

	// Forward Declarations (namespace iwear::sensor)
	class SensorManager;

    }

    namespace uiservices{

using iwear::operator<<;

class ApplicationBase : public Thread, public Service 
{

public:

    /**
     * The standard constructor for applications in the iWear
     * framework
     * @param sm pointer to the service manager
     * @param im pointer to the input manager
     * @param om pointer to the output manager. Normal applications
     *        need the handle in order to hand over output datas to
     *        the manager for display purposes
     * @param application_name the application's short name
     * @param application_description short descriptive text which
     *        tells a user what the application is all about (e.g.
     *        in a tooltip)
     * @param have_switch_button Should the application menu have
     *        a button to leave the application and switch to the 
     *        iWear application service? Default value is 'true'
     * @param have_quit_button Should the application menu have
     *        a button to quit the application? Default value is 'true'
     * @param have_up_button Should the application menu have
     *        a button to go up one level? Default value is 'true'
     */
    ApplicationBase(Configuration* config,
	    EventDispatcher* ed,
		    ServiceManager* sm,
		    InputManager* im,
		    OutputManager* om,
		    SensorManager* sens,
		    const string& application_name,
		    const string& application_description);

    /**
     * The destructor
     */
    virtual ~ApplicationBase(void);

    /**
     * This method is called when the application thread is started
     */
    virtual void Run(void) = 0;

    /**
     * This method is called when the application thread is terminated
     */
    virtual void Final(void);

    // --- inherited from Service class ------------

    void Init(void);

    void Start( void );
    
    void Stop(void);

    void Reset(void);

    void Suspend(void);

    void Pause(void);

    void Resume(void);

    // --- END inherited from Service class END -----

    /**
     * Using this method either the application itself or its menu 
     * can dispatch events to be delivered in the iWear framework
     * @see eventdispatcher.h
     */
    virtual void dispatch( EventBase& evt, 
			   event_priority prio = prio_normal) = 0;

    /**
     * Return the service type which is service_ui_application
     * for all iWear applications
     */
    inline virtual service_type get_type(void) {
	return service_ui_application;
    }

    /**
     * Return the name of the application
     * @todo make const
     */
    inline virtual const string get_name(void) {
	return this->application_name;
    }

    /**
     * Return a short description for the application
     * @todo make const
     */
    inline virtual const string& get_description(void) const {
	return this->application_description;
    }

    /**
     * Compares the uid's contained in the applications.
     */
    inline bool operator<(const ApplicationBase& od) const{
        return this->ID < od.get_uid();
    }

    /**
     * Compares the uid's contained in the applications.
     */
    inline bool operator>(const ApplicationBase& od) const{
        return this->ID > od.get_uid();
    }

    /**
     * Compares the uid's contained in the applications.
     */
    inline bool operator==(const ApplicationBase& od) const{
        return this->ID == od.get_uid();
    }

    /**
     * Compares the uid's contained in the applications.
     */
    inline bool operator!=(const ApplicationBase& od) const{
        return !this->operator==(od);
    }

    /**
     * Method which allows other applications to register a menu
     * functor on the application's menu. Note that the menu itself
     * remains protected from abuse by third parties
     * @throws nullptr_error
     */
    inline virtual void register_menu_functor(MenuFunctor& menu_functor)
    {
	if(this->menu!=NULL){
	    this->menu->register_functor(menu_functor);
	}else{
	    throw nullptr_error("No menu available");
	}
    }

    /**
     * Method which allows other applications to deregister a menu
     * functor on the application's menu. Note that the menu itself
     * remains protected from abuse by third parties
     * @throws nullptr_error
     */
    inline virtual void deregister_menu_functor(MenuFunctor& menu_functor)
    {
	if(this->menu!=NULL){
	    this->menu->deregister_functor(menu_functor);
	}else{
	    throw nullptr_error("No menu available");
	}
    }

    /**
     * Push button IDs of pressed buttons into the dedicated 
     * button event queue
     */
    inline void push_button_event(const uint32_t& button_id){
	ThreadLocker tl(Mutex);
	this->button_event_queue.push(button_id);
    }

protected:

    /**
     * Each application can overwrite this function in order
     * to set its own set of configuration value/key-pairs
     */
    virtual void set_default_configuration( void );

    /**
     * This function handles the details of the configuration
     * load process
     */
    void init_configuration( void );


    virtual void Init_Application(void) = 0;

    inline virtual void Reset_Application(void){}

    inline virtual void Suspend_Application(void){}

    inline virtual void Pause_Application(void){}

    inline virtual void Resume_Application(void){}
    
    virtual void Final_Application(void) = 0;

    /**
     * Pop button IDs of pressed button out of the dedicated
     * button event queue for event handling 
     * Note: This is what this function is all about: Event Handling
     */
    inline const uint32_t pop_button_event( void ){
	ThreadLocker tl(Mutex);
	const uint32_t button_id = this->button_event_queue.front();
	this->button_event_queue.pop();
	return button_id;
    }

    /**
     * The application name
     */
    string application_name;

    /**
     * A short description of the application
     */
    string application_description;

    /**
     * Handle for the ionput manager which is required by the menus
     * of each application, so they can react to input events.
     */
    InputManager* input_manager;

    /**
     * Handle for the output manager which is required by each
     * application in order to send OuputDatas to be presented
     * to the user
     */
    OutputManager* output_manager;

    /**
     * Handle for the sensor manager which is required for direct
     * context aware adaption of the application themselves
     */
    SensorManager* sensor_manager;

    /**
     * The menu for the application
     */
    Menu* menu;

    /**
     * Reference to the iWear configuration file
     */
    Configuration* configuration;

    /**
     * In this queue button events are stored for processing
     */
    queue<uint32_t> button_event_queue;

};

    } // namespace uiservices
} // namespaces iwear

#endif // __APPLICATIONBASE_H

