//=============================================================================
// Copyright (C) 2002 Radical Entertainment Ltd.  All rights reserved.
//
// File:        soundmanager.h
//
// Description: Manager interface that the other game components use to
//              interact with sound.
//
// History:     01/06/2002 + Created -- Darren
//
//=============================================================================

#ifndef _SOUNDMANAGER_H
#define _SOUNDMANAGER_H

#ifndef RAD_RELEASE
#define SOUNDDEBUG_ENABLED
#endif


//
// Debug display macros
//
#ifndef SOUNDDEBUG_ENABLED

#define SOUNDDEBUG_RENDER()

#else

#define SOUNDDEBUG_RENDER()  GetSoundManager()->DebugRender()

#endif

//========================================
// Nested Includes
//========================================

#include <enums.h>

#include <sound/soundloader.h>
#include <sound/avatar/avatarsoundplayer.h>
#include <sound/listener.h>
#include <sound/nis/nissoundplayer.h>

#include <data/gamedata.h>
#include <events/eventlistener.h>
#include <contexts/contextenum.h>

#ifdef RAD_WIN32
#include <data/config/gameconfig.h>
#endif

//========================================
// Forward References
//========================================

class MusicPlayer;
class DialogCoordinator;
class SoundDebugDisplay;
class MovingSoundManager;
class Vehicle;
class Character;
class SoundEffectPlayer;
struct IRadSoundClip;
struct IRadSoundClipPlayer;

//=============================================================================
//
// Synopsis:    NIS loading and playback completion callbacks
//
//=============================================================================

struct NISSoundLoadedCallback
{
    virtual void NISSoundLoaded() = 0;
};

struct NISSoundPlaybackCompleteCallback
{
    virtual void NISSoundPlaybackComplete() = 0;
};

enum SoundMode
{
    SOUND_MONO,
    SOUND_STEREO,
    SOUND_SURROUND
};

//=============================================================================
//
// Synopsis:    SoundManager class declaration
//
//=============================================================================

class SoundManager : public EventListener,
                     #ifdef RAD_WIN32
                     public GameConfigHandler,  //ziemek: this is ugly..doh
                     #endif
                     public GameDataHandler
{
    public:
        //
        // Singleton accessors
        //
        static SoundManager* CreateInstance( bool muteSound, bool noMusic, 
                                             bool noEffects, bool noDialogue );
        static SoundManager* GetInstance();
        static void DestroyInstance();
        void Initialize();

        //
        // EventListener interface
        //
        void HandleEvent( EventEnum id, void* pEventData );
        
        //
        // All-purpose sound file loading.  Coordinates the sound system
        // with the loading system
        //
        void LoadSoundFile( const char* filename, SoundFileHandler* callbackObj );

        //
        // Update routines.
        //
        void Update();
        // This one is for expensive stuff like positional sound calculations
        // that we can get away with doing once per frame
        void UpdateOncePerFrame( unsigned int elapsedTime, 
                                 ContextEnum context, 
                                 bool useContext = true,
                                 bool isPausedForErrors = false );
        
        // Prepare to load level sounds
        void QueueLevelSoundLoads();

        // Load the sounds associated with a car
        void LoadCarSound( Vehicle* theCar, bool unloadOtherCars );

        // Called when bootup context starts and ends
        void OnBootupStart();
        void OnBootupComplete();

        // Called when front end starts and ends
        void OnFrontEndStart();
        void OnFrontEndEnd();
        
        // Called when gameplay starts and ends
        void OnGameplayStart();
        void OnGameplayEnd( bool goingToFE );

        // Called when pause menu starts and ends (ends going back to gameplay,
        // not loading)
        void OnPauseStart();
        void OnPauseEnd();

        // Called for pseudo-pause stuff like clothing and phone booth
        //
        void OnStoreScreenStart( bool playMusic = true );
        void OnStoreScreenEnd();

        // Called when we want to kill everything but music (e.g. loading,
        // minigame standings)
        void DuckEverythingButMusicBegin( bool playMuzak = false );
        void DuckEverythingButMusicEnd( bool playMuzak = false );

        // Called when mission briefing screen starts and ends
        void OnMissionBriefingStart();
        void OnMissionBriefingEnd();

        // Called when in-game credits start
        //
        void DuckForInGameCredits();

        // Call these before and after FMVs
        void StopForMovie();
        void ResumeAfterMovie();
        bool IsStoppedForMovie();

        // Hack!  Need to mute gags during conversations
        void MuteNISPlayers();
        void UnmuteNISPlayers();

        //
        // Supersprint
        //
        void RestartSupersprintMusic();

        // Surround sound control
        void SetSoundMode(SoundMode mode);
        SoundMode GetSoundMode();

        // Function for getting that funky beat.  Values from 0.0f to 4.0f, assuming
        // that Marc doesn't write any waltzes
        float GetBeatValue();

        // Special case dialog handling
        static bool IsFoodCharacter( Character* theGuy );
        
        //
        // Volume controls.  Values range from 0.0f to 1.0f
        //
        void SetMasterVolume( float volume );
        float GetMasterVolume();
        
        void SetSfxVolume( float volume );
        float GetSfxVolume();

        void SetCarVolume( float volume );
        float GetCarVolume();
        
        void SetMusicVolume( float volume );
        float GetMusicVolume();
        
        void SetAmbienceVolume( float volume );
        float GetAmbienceVolume();
        
        void SetDialogueVolume( float volume );
        float GetDialogueVolume();

        float GetCalculatedAmbienceVolume();

        //
        // Option menu stinger stuff
        //
        void PlayCarOptionMenuStinger();
        void PlayDialogueOptionMenuStinger();
        void PlayMusicOptionMenuStinger();
        void PlaySfxOptionMenuStinger();

        //
        // Ducking stuff
        //
        void ResetDucking();

        //
        // NIS Interface
        //
        void LoadNISSound( radKey32 NISSoundID, NISSoundLoadedCallback* callback = NULL );
        void PlayNISSound( radKey32 NISSoundID, rmt::Box3D* boundingBox, NISSoundPlaybackCompleteCallback* callback = NULL );
        void StopAndDumpNISSound( radKey32 NISSoundID );

        //
        // Language interface
        //
        void SetDialogueLanguage( Scrooby::XLLanguage language );

        //
        // Sound debug functions
        //
        void DebugRender();
        
        //
        // TODO: move these functions, they're not intended for use outside
        // of the sound system
        //
        SoundLoader* GetSoundLoader() { return( m_soundLoader ); }
        SoundDebugDisplay* GetDebugDisplay() { return( m_debugDisplay ); }

        //
        // This should NOT be called outside the sound system.  Unfortunately,
        // to keep things clean, what I should do is split the MusicPlayer class
        // and move a low-level controller into the soundrenderer layer.  I don't
        // have time for this.  Things to do for the next round.
        //
        void SetMusicVolumeWithoutTuner( float volume );
        void SetAmbienceVolumeWithoutTuner( float volume );

        // Implements GameDataHandler
        //
        virtual void LoadData( const GameDataByte* dataBuffer, unsigned int numBytes );
        virtual void SaveData( GameDataByte* dataBuffer, unsigned int numBytes );
        virtual void ResetData();

        #ifdef RAD_WIN32
        // Implementation of the GameConfigHandler interface
        virtual const char* GetConfigName() const;
        virtual int GetNumProperties() const;
        virtual void LoadDefaults();
        virtual void LoadConfig( ConfigString& config );
        virtual void SaveConfig( ConfigString& config );
        #endif

        DialogCoordinator* m_dialogCoordinator;
        
    protected:
        //
        // Hide the SoundManager constructor and destructor so everyone
        // is forced to use singleton accessors
        //
        SoundManager( bool noSound, bool noMusic, bool noEffects, bool noDialogue );
        ~SoundManager();

    private:
        //Prevent wasteful constructor creation.
        SoundManager( const SoundManager& original );
        SoundManager& operator=( const SoundManager& rhs );

        //
        // Hack!
        //
        void prepareStartupSounds();
        void playStartupAcceptSound();
        void playStartupScrollSound();
        void dumpStartupSounds();

        // Pointer to the one and only instance of this singleton.
        static SoundManager* spInstance;

        struct SoundSettings
        {
            float musicVolume;
            float sfxVolume;
            float carVolume;
            float dialogVolume;
            bool isSurround;
        };
        
        // Sound loading subsystem
        SoundLoader* m_soundLoader;

        // Avatar sound subsystem
        AvatarSoundPlayer m_avatarSoundPlayer;

        // Music player subsystem
        MusicPlayer* m_musicPlayer;

        // Sound effect subsystem
        SoundEffectPlayer* m_soundFXPlayer;
        
        // Dialog subsystem


        // NIS subsystem
        NISSoundPlayer* m_NISPlayer;
        
        // RadSound listener update
        Listener m_listener;

        // AI Vehicle sound subsystem
        MovingSoundManager* m_movingSoundManager;

        // Sound debug display subsystem
        SoundDebugDisplay* m_debugDisplay;
        
        // Mute options
        bool m_isMuted;

        bool m_noMusic;
        bool m_noEffects;
        bool m_noDialogue;

        // Pointer to sound rendering interface
        Sound::daSoundRenderingManager* m_pSoundRenderMgr;
        
        // [ps] avoid hammering on pause.
        bool m_stoppedForMovie;

        //
        // Hack for stinky pre-script-loading menu sounds
        //
        IRadSoundClip* m_selectSoundClip;
        IRadSoundClip* m_scrollSoundClip;

        IRadSoundClipPlayer* m_selectSoundClipPlayer;
        IRadSoundClipPlayer* m_scrollSoundClipPlayer;

        
        SoundMode m_soundMode;
};

// A little syntactic sugar for getting at this singleton.
inline SoundManager* GetSoundManager() { return( SoundManager::GetInstance() ); }

#endif //SOUNDMANAGER_H

