#ifndef GAME_SOUND_SOUNDMANAGER_H
#define GAME_SOUND_SOUNDMANAGER_H

#include <string>
#include <utility>
#include <map>

#include <OgreResourceGroupManager.h>

#include "../mwworld/ptr.hpp"


namespace Ogre
{
    class Root;
    class Camera;
}

namespace MWWorld
{
    struct Environment;
}

namespace MWSound
{
    class Sound_Output;
    struct Sound_Decoder;
    class Sound;

    typedef boost::shared_ptr<Sound_Decoder> DecoderPtr;
    typedef boost::shared_ptr<Sound> SoundPtr;

    class SoundManager
    {
        Ogre::ResourceGroupManager& mResourceMgr;

        MWWorld::Environment& mEnvironment;

        std::auto_ptr<Sound_Output> mOutput;

        boost::shared_ptr<Sound> mMusic;
        std::string mCurrentPlaylist;

        typedef std::pair<MWWorld::Ptr,std::string> PtrIDPair;
        typedef std::map<SoundPtr,PtrIDPair> SoundMap;
        SoundMap mActiveSounds;

        std::string lookup(const std::string &soundId,
                  float &volume, float &min, float &max);
        void streamMusicFull(const std::string& filename);
        bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const;
        void updateSounds(float duration);
        void updateRegionSound(float duration);

        SoundManager(const SoundManager &rhs);
        SoundManager& operator=(const SoundManager &rhs);

    protected:
        DecoderPtr getDecoder();
        friend class OpenAL_Output;

    public:
        SoundManager(bool useSound, MWWorld::Environment& environment);
        ~SoundManager();

        void stopMusic();
        ///< Stops music if it's playing

        void streamMusic(const std::string& filename);
        ///< Play a soundifle
        /// \param filename name of a sound file in "Music/" in the data directory.

        void startRandomTitle();
        ///< Starts a random track from the current playlist

        bool isMusicPlaying();
        ///< Returns true if music is playing

        void playPlaylist(const std::string &playlist);
        ///< Start playing music from the selected folder
        /// \param name of the folder that contains the playlist

        void say(MWWorld::Ptr reference, const std::string& filename);
        ///< Make an actor say some text.
        /// \param filename name of a sound file in "Sound/Vo/" in the data directory.

        bool sayDone(MWWorld::Ptr reference) const;
        ///< Is actor not speaking?

        SoundPtr playSound(const std::string& soundId, float volume, float pitch, bool loop=false);
        ///< Play a sound, independently of 3D-position

        SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId,
                             float volume, float pitch, bool loop,
                             bool untracked=false);
        ///< Play a sound from an object

        void stopSound3D(MWWorld::Ptr reference, const std::string& soundId);
        ///< Stop the given object from playing the given sound,

        void stopSound3D(MWWorld::Ptr reference);
        ///< Stop the given object from playing all sounds.

        void stopSound(const MWWorld::Ptr::CellStore *cell);
        ///< Stop all sounds for the given cell.

        void stopSound(const std::string& soundId);
        ///< Stop a non-3d looping sound

        bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const;
        ///< Is the given sound currently playing on the given object?

        void updateObject(MWWorld::Ptr reference);
        ///< Update the position of all sounds connected to the given object.

        void update(float duration);
    };
}

#endif
