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

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

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

#ifndef __AUDIODATA_H
#include <iwear_output/audiodata.h>
#endif

#ifndef __IWEAR_STOPWATCH_H
#include <iwear/stopwatch.h>
#endif

#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>

#include <iostream>
using namespace std;
namespace iwear{

namespace output{

class AudioDataFunctor;

/**
 * This class AudioOutputModule derives from OutputModule and at
 * least has to implement the display-function that should contain
 * the main functionality of this module.
 */ 
class AudioOutputModule : public OutputModule 
{

 public:
    /**
     * The name of this output module.
     */
    static const string NAME;

    /**
     * The standard constructor of thes module. The module will register
     * itself with the OutputManager.
     *
     * @param output_manager the manager that is responsible for this module.
     *
     * @param num_channels the maximum number of channels to be allocated.
     *
     * @param c the configuration we are using for storing default and
     * user-configured values.
     */
    AudioOutputModule(OutputManager* output_manager, 
		      Configuration& c);

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

    /**
     * Inherited from Module and has to be implemented.
     * @param p_state the state to be set
     * @return if the operation was successful.
     * @todo: Think about decent return values
     */
    virtual uint32_t activate_power_state(power_state p_state);

    /**
     * The most important function of this class. Inherited
     * from OutputModule and implemented here.
     
     * @param data the outputdata to be displayed.
     */
    display_state display(OutputData* data);

    /**
     * Stop displaying an outputdata. Inherited from OutputModule and
     * implemented here.
     *
     * @param data The outputdata which shouldn't be displayed any more.
     */
    bool stop_display(OutputData* data);

    /**
     * Perfom an internal change of the application in focus
     * TODO: Think about decent switch strategy and implement
     *
     * @param app_id the application where we should switch to.
     */
    void apply_application_focus_change(const uid& app_id);

    /**
     * Change the volume of a channel.
     *
     * @param functor the functor which has called this method. Needed to
     * determine the outputdata and channel.
     */
    void apply_volume_change(AudioDataFunctor* functor);

    /**
     * Change the play status of a channel.
     *
     * @param functor the functor which has called this method. Needed to
     * determine the outputdata and channel.
     */
    void apply_status_change(AudioDataFunctor* functor);

    /**
     * Change the file playing in a channel.
     *
     * @param functor the functor which has called this method. Needed to
     * determine the outputdata and channel.
     */
    void apply_audio_file_change(AudioDataFunctor* functor);

 protected:


 private:

    /**
     * Internal method that actually does the job.
     *
     * @param data the audiodata to be played.
     */
    display_state display_audio(AudioData* data);

    class AudioModuleInternals{
    private:
	static AudioModuleInternals* internals;

    public:
	static AudioModuleInternals* get_instance(void);

	static void channel_done(int32_t c){
	    d_dbg << __FFL__ << "Channel done: " << c << endl;
	    AudioData* data = internals->active_channel_to_data[c];
	    if(data != NULL){
		data->audio_finished();
		internals->active_channel_to_data[c] = NULL;
	    }
	}

	static void music_done(){
	    d_dbg << __FFL__ << "Music done" << endl;
	    internals->active_music->audio_finished();
	    // TODO: clean up the other maps
	    internals->active_music = NULL;
	}

	AudioModuleInternals(void);

	/**
	 * A pointer to the currently playing audiodata containing music.
	 */
	AudioData* active_music;

	std::map<int32_t, AudioData*> active_channel_to_data;

	/**
	 * A map that stores the uid's of applications together with pointers to
	 * the audiodata they sent here.
	 */
	std::multimap<const uid*, AudioData*, deref_less<const uid*> > app_to_data;

	/**
	 * Here we hold the audiodata and the belonging channel and sample pointer
	 * that we need to play sound samples (wav, aiff, riff, ogg, voc).
	 */
	std::map<AudioData*, pair<int32_t, Mix_Chunk*> > data_to_channel_sample;
    
	/**
	 * Here we hold the audiodata and the belonging stopwatch and music
	 * pointer that we need to play music samples (wav, mod, midi, ogg, mp3).
	 */
	std::map<AudioData*, pair<StopWatch<SW::clock>*, Mix_Music*> > data_to_time_music;
    
	/**
	 * A map to connect the functor with the audiodata it belongs to.
	 */
	std::map<AudioData*, AudioDataFunctor* > data_to_functor;

	/**
	 * A map to connect the audiodata with the functor belonging to it.
	 */
	std::map<AudioDataFunctor*, AudioData* > functor_to_data;
    };

    AudioModuleInternals* internals;


};



} // namespace output
} // namespace iwear

#endif // __AUDIOOUTPUTMODULE_H

