/**
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.  
 *
 * In particular this file is part of the Framework Output 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; either version 2 of
 * the License, or (at your option) any later version.
 * 
 * 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 __OUTPUTMANAGER_H
#define __OUTPUTMANAGER_H

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

#ifndef __OUTPUT_ENUMS_H
#include <iwear_output/outputenums.h>
#endif

#ifndef __OUTPUTDATA_H
#include <iwear_output/outputdata.h>
#endif

#ifndef __OUTPUTMODULE_H
#include <iwear_output/outputmodule.h>
#endif

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

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



namespace iwear { 
    namespace output {

    // Forward Declarations
    class OutputAdvisor;
    class OutputModuleChangedODOFunctor;

    /** OutputManager inherits from template class ModuleManager, the
     * template is instanciated with an enum of the known
     * output-module types (from output_enums.h) and the base-class of
     * all output-modules: OutputModule.
     */
    class OutputManager 
	:  public ModuleManager<bool, OutputModule, BaseModuleManager>
    {
   
    private:
	
	/** 
	 * The OutputAdvisor - will be asked to advise, which output
	 * should be chosen best. 
	 */
	OutputAdvisor* output_advisor;

	/**
	 * The OutputData this manager is responsible for. That means all the
	 * registered OutputData will also be destroyed only here.
	 */
	map<const uid*, OutputData*, deref_less<const uid*> > registered_outputdata;


	/** 
	 * The active outputs that are displaying in this moment.
	 */
	map<OutputData*, OutputModule*> active_outputs;

	/**
	 * The EventDispatcher used for the OutputData events.
	 */
	EventDispatcher* event_dispatcher;

	/**
	 * Get an iterator to the pair in the vector active_outputs containing
	 * the given OutputData.
	 *
	 * @param data the OutputData to be searched.
	 *
	 * @return an iterator to the pair in the vector active_outputs
	 * containing the given OutputData.
	 */
	vector< pair<OutputData*, uid*>* >::iterator 
	    get_active_position(OutputData* data);

	/**
	 * A dummy uid which is used whenever no application have yet
	 * been started 
	 */
	uid* dummy_application_id;

	/*
	 * The uid of the active application
	 */
	uid* active_application_id;

    public:

	uid* get_active_application_id(void){
	    return this->active_application_id;
	}

	OutputManager(BaseModuleManager* basemodulemanager, 
		      EventDispatcher* event_dispatcher, Configuration& c);

	/** 
	 * The destructor is virtual, for polymorphic reasons.
	 */
	virtual ~OutputManager(void);

	/**
	 * Inherited function from ModuleManager - not needed here. The
	 * function is only useful if we had to spread the modules we get
	 * among subordinated managers. Since we are the "last" manager we
	 * dont use the function.
	 */
	virtual bool get_type(const OutputModule& om) const{
		// TODO : Decent implementation
		if(!&om){ std::cout << "Error" << std::endl; } 
	    return true;
	}

	/** 
	 * Add an OutputModule and make it known to the
	 * OutputManager.
	 * @param module the OutputModule to be added.
	 */
	virtual void register_external_module( Module* );

	/** 
	 * Add an OutputModule and make it known to the
	 * OutputManager.
	 * @param module the OutputModule to be added.
	 */
	virtual void register_internal_module( Module* );
	
	/** 
	 * Remove an OutputModule and make it unknown to the
	 * OutputManager.
	 * @param module the OutputModule to be removed.
	 */
	virtual void deregister_module( Module* );

	/** The most important function of this class - displays the
	 * data of the given OutputData. The output can be
	 * context-sensitive at the beginning and the OutputAdvisor
	 * can go on monitoring the output and will maybe change 
	 * some options according to the current context. 
	 * @param data the OutputData to be displayed. 
	 * @param advise_at_start if the output should be set context 
	 * sensitive once when it is initialized.
	 * @param advise_continued if the OutputAdvisor should monitor
	 * the output.
	 * @param outputmodule_name can be set to specify the OutputModule to be used.
	 * @return a value different from 0 if the call was successful.
	 */
	uint32_t display(OutputData* data, 
			 bool advise_at_start = true, 
			 bool advise_continued = true,
			 string outputmodule_name = "");
	
	/**
	 * Is called by the OutputModule when all displaying is done and the
	 * OutputModule does not know about it anymore.
	 *
	 * @param data the finished OutputData.
	 */
	void finished_displaying(OutputData* data);

	/** Stop displaying the given OutputData.
	 * @param data the output to be stopped.
	 * @return a value different from 0 if the call was successful.
	 */
	uint32_t stop_displaying(OutputData* data);

	/**
	 * Is used exclusively by the application management service
	 * in order to bring a new application specified by the uid
	 * to the foreground. Replacement for aequivalent
	 * functor/event concept.
	 *
	 * @param app_id the uid of the application to be set in focus
	 */
	void set_application_focus(const uid& app_id);

	/**
	 * Register an OutputData here - so this manager will have the
	 * ownership from now on!! That means noone but this manager must
	 * delete the object!
	 *
	 * @throws illegalargument_error if there is already an OutputData
	 * with the same uid.
	 */
	void register_outputdata(OutputData* data);

	/**
	 * Deregister the OutputData with the given uid.
	 *
	 * @throws illegalargument_error if there is no OutputData with the
	 * given uid.
	 */
	 void deregister_outputdata(const uid& id);

	/**
	 * Is called by the OutputAdvisor if it wants to change the output
	 * module the OutputData is displayed on.
	 *
	 * @param odo_uid the uid of the OutputData
	 * @param om the new OutputModule.
	 */
	void change_output_module(const uid* odo_uid, OutputModule* om);

	/** Get the OutputModule, that can display the given
	 * OutputData.
	 * @param datatype which kind of OutputData do we have...
	 * @return vector of OutputModule that are capable of 
	 * displaying the given datatype.
	 */
	vector<OutputModule*> map_data_to_output(const string& type);

	/**
	 * Get the OutputModule of the specified type.
	 *
	 * @return the first OutputModule of the specified type - but there
	 * should be only one.
	 */
	OutputModule* get_outputmodule(const string& name);

	/**
	 * Get a registered OutputData by its uid. This function is
	 * provided for the output advisor.
	 *
	 * @param id the uid of the OutputData to be searched.
	 *
	 * @return a specialpointer to the OutputData with the given uid.
	 */
	OutputData* get_registered_outputdata(const uid* id);

	/**
	 * Get the EventDispatcher that this class got in its constructor.
	 *
	 * @return the EventDispatcher.
	 */
	EventDispatcher* get_event_dispatcher(void){
	    return event_dispatcher;
	}
    }; // class OutputManager

} // namespace output
} // namespace iwear

#endif // __OUTPUTMANAGER_H
