
/**
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the Framework UIservices
 *
 * 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 __MENU_H
#define __MENU_H

// Standard includes
#include <list>

// iWear includes
#include <iwear/uid.h>
#include <iwear/eventdispatcher.h>
#include <iwear/threadlocked.h>
#include <iwear_input/inputmanager.h>
#include <iwear_uiservices/menunodesubmenu.h>

#include <iwear_uiservices/menufunctor.h>
#include <iwear_uiservices/menuevent.h>

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

using namespace iwear::input;

namespace iwear {
namespace uiservices {

	// Forward Declarations -- same namespace 
	class ApplicationBase;
	class MenuJoystickInputFunctor;
	class MenuKeyInputFunctor;
	class MenuMouseInputFunctor;
	class MenuSignalInputFunctor;
	class MenuNode;

/**
 * This class is the base menu representation
 * @author Carsten Rachuy
 */
class Menu : public virtual ThreadLocked {

 public:

    /**
     * Constructor
     * @param application_id The uid of the application the 
     *        menu belongs to
     * @param input_manager A pointer to the input manager. The input
     *        manager is needed for the menu to register the 
     *        listeners at.
     * @param have_switch_button A boolean defining whether a button
     *        which is used to switch between applications is build or
     *        not.
     * @param have_quit_button A boolean defining whether a button
     *        which is used to quit the applications is build or
     *        not.
     */
    Menu(ApplicationBase* application_base, 
	 InputManager*    input_manager,
	 bool have_switch_button = true, 
	 bool have_quit_button   = true,
	 bool have_up_button     = true );


    /**
     * Destructor for OutputData.
     * @todo Check, whether the destruction of the whole thing is
     * sound. For example consider the call of a 'getter' while
     * another thread tries to delet the whole menu...
     */
    virtual ~Menu(void);


    // ------------------- Button adding / removing -------------------
    
    /**
     * Adds a button to a given submenu and returns the id of the
     * newly created element.
     * @param parent_element The id (as an uiint32_t) of the parent
     *        element (e.g. the submenu).
     * @param button_name The name of the button
     * @param button_description The description of the button
     * @param default_representation The representation of the
     *        button (txt, bmp etc.).
     * @throws invalidargument_error Throws this error when 
     *         the given parent_element is not a valid submenu
     */
    uint32_t add_button(uint32_t      parent_element, 
			const string& name,
			const string& description,
			const string& default_representation);


    /**
     * Adds a submenu to a given submenu and returns the id of the
     * newly created element.
     * @param parent_element The id (as an uiint32_t) of the parent
     *        element (e.g. the submenu).
     * @param button_name The name of the button
     * @param button_description The description of the button
     * @param default_representation The representation of the
     *        button (txt, bmp etc.).
     * @throws invalidargument_error Throws this error when 
     *         the given parent_element is not a valid submenu
     */
    uint32_t add_submenu(uint32_t      parent_element, 
			 const string& name,
			 const string& description,
			 const string& default_representation);


    /**
     * Removes an element from the menu. All elements below (if
     * any exist) are deleted too.
     * @throws invalidargument_error Throws this error when 
     *         the given parent_element is not a valid submenu
     */
    void remove_element(uint32_t element_id);


    /**
     * @return The id of the root menu
     */
    inline uint32_t get_root_submenu_id(void){
	return this->root_submenu->get_id();
    }





    // ------------- Reaction on keys -------------------
    
    /**
     * Reaction on a "left" event.
     */
    void go_left(void);
    
    /**
     * Reaction on a "right" event.
     */
    void go_right(void);

    /**
     * Reaction on a "up" event.
     */
    void go_up(void);

    /**
     * Reaction on a "down" event.
     */
    void go_down(void);

    /**
     * Reaction on a  'activate' event
     */
    void activate(void);



    // ------------- Registering and deregistering of functors ---------

    /**
     * @param element_id The id of the element which is the source of
     *        the event.
     * @param menu_event The event which occured.
     * @param priority   The priority of the event.
     */
    void notify(uint32_t element_id, 
		MENU_EVENT menu_event, 
		MENU_EVENT_INFORMATION menu_event_information = 
		num_MENU_EVENT_INFORMATION,
		event_priority priority = prio_normal);


    /**
     * @param menu_functor The menu functor which should be registered.
     */
    void register_functor(MenuFunctor& menu_functor);

    /**
     * @param menu_functor The menu functor which should be
     *        deregistered.
     */
    void deregister_functor(MenuFunctor& menu_functor);


    // ------------------------ Other ------------------------

    /**
     * @return the selected element id
     * @TODO return value?
     */
    inline uint32_t get_selected_element_id(void){
	if (this->selected_element != NULL){
	    return this->selected_element->get_id();
	} else {
	    return 0;
	}
    }


    /**
     * Get a export of the Menu
     */
    ExportableMenuNode* export_node(void);

    // Display
    void display_menu(void);

    





    // ------------- Some private status things -------------
    
 private:

    // ------ Esentials - it's all about the application ------

    /**
     * The pointer to an aplication base
     */
    ApplicationBase* application_base;

    /**
     * A pointer to the input manager, needed for registering the
     * input funtcors.
     */
    InputManager* input_manager;

    /**
     * Do we have a switch button in every menu
     */
    bool have_switch_button;

    /**
     * Do we have a quit button in the root menu
     */
    bool have_quit_button;

    /**
     * Do we have an up button in every menu
     */
    bool have_up_button;

    /**
     * The functor which is registered on joystick events
     */
    MenuJoystickInputFunctor* menu_joystick_input_functor; 

    /**
     * The functor which is registered on key events
     */
    MenuKeyInputFunctor*      menu_key_input_functor;

    /**
     * The functor which is registered on mouse events
     */
    MenuMouseInputFunctor*    menu_mouse_input_functor;

    /**
     * The functor which is registered on signal events
     */
    MenuSignalInputFunctor*   menu_signal_input_functor;

    // --------------- Button handling ------------------


    // Button handling

    // Evil and being replaced whith something better
    uint32_t number_of_elements;

    // Even more evil...
    inline uint32_t get_next_id(void){
	number_of_elements++;
	return number_of_elements;
    }

    /**
     * The currently selected element
     */
    MenuNode* selected_element;

    /**
     * The root submenu which is the base anchor-point for all
     * other elements in this menu
     */
    MenuNodeSubMenu* root_submenu;
    
    /**
     * A map which holds the buttons / submenus. They are indexed by
     * their uint32_t id.
     */
    map<uint32_t, MenuNode*> menu_elements;


    // ---------------- Functors ----------------

    /**
     * A list of all registered functors which will be
     * invoked when 'dispatch' is called.
     */
    list<MenuFunctor*> registered_functors;
    
    map<MenuFunctor*, AtomicCounter<uint32_t> > functor_to_counter;

};

} // namespace uiservices
} // namespace iwear


#endif // __MENU_H

