/**
*
* \file Asura_PC_Sound.h
*
* Created by Andy Patrick - 02/08/2007
*
* Copyright (C) 2007 Rebellion, All Rights Reserved.
*
* \brief
*
**/

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_PC_SOUND_H__
#define __ASURA_PC_SOUND_H__

#if !defined(ASURA_USE_AUDIO_SYSTEM)

#ifdef ASURA_TOOLS
	#include "Core/Asura_String.h"
#endif

#include "Core/Asura_PlatformBasics.h"
#include "Sound/Asura_Sound.h"

//-----------------------------------------------------------------------------

#if defined( ASURA_USE_OPENAL ) && ( ASURA_USE_OPENAL == 1 )

	#include "Sound/Asura_OpenAL.h"

#else

	#if !defined( ASURA_PC_USE_NULLSOUND )
		#define ASURA_PC_USE_NULLSOUND (1)
		#pragma message( "Sound API not specified. Defaulting to NullSound." )
	#endif
	#include "Sound/Asura_NullSound.h"

#endif

//-----------------------------------------------------------------------------

#define ASURA_PC_SOUND_MAX_NUMBER_OF_ACTIVE_SOUNDS 100

//-----------------------------------------------------------------------------

class Asura_PC_LoadedSound
{
    friend class Asura_PC_Sound;
    friend class Asura_PC_ActiveSound;

public:
	Asura_PC_LoadedSound();
	~Asura_PC_LoadedSound();
    
    bool IsLoaded() const		{ return m_pucWaveData != NULL; }
    float GetFrequency() const	{ return m_fFrequency; }

private:
    
    u_int           			m_uSize;
    WAVEFORMATEX    			m_xWfx;
    u_char*         			m_pucWaveData;
    float           			m_fFrequency;

	#ifdef ASURA_TOOLS
		bool					m_bAttemptedLoad;
		Asura_String			m_xFilename;
	#endif
};

//-----------------------------------------------------------------------------

class Asura_PC_ActiveSound
{
	friend class Asura_PC_Sound;

public:

    // methods
    Asura_PC_ActiveSound();
    ~Asura_PC_ActiveSound();
    bool Create( Asura_PC_LoadedSound& xLoadedSound, bool bUseHardware3dPan );
	void Update();
    void Destroy();
    
	bool SetVolume( float fVolume );
	void SetReverbParams( const Asura_PC_Sound_ReverbParams& xReverbParams );

	bool AnyPauseFlagSet() const { return m_bPaused || m_bPausedByPitch; }

private:

	bool UpdateVolume();

	// member data (agnostic of exactly what low-level system we're using)
	Asura_PC_ActiveSound_API	m_xAPI;

    int                 		m_iLoadedSoundIndex;
	float						m_fVolume;

	// flags
    bool		        		m_bIsLooping;
    bool                		m_bPaused;
    bool                		m_bPausedByPitch;
	bool						m_bUseHardware3dPan;
	bool						m_bEnable3dPanning;
	bool						m_bUseForcedPanAndFade;

	#ifdef ASURA_TOOLS
		//For marking sounds that have had to be invalidated as a result of sounds being reloaded
		bool					m_bInvalidatedByTools;
	#endif
};

//-----------------------------------------------------------------------------

class Asura_PC_Sound
{
public:

	// Sound system functions

	static void Project_HandleInitialisationFailure();

	static bool Initialise();
	static bool Shutdown();
	static void Reset();
	static void Update();
	
	static Asura_PC_Sound_API& GetAPI()				{ return s_xAPI; }

	static void SetListener( const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation );
	static void SetReverb( Asura_Sound_System::ReverbType eType, float fReverbAmount );
	static void SetRollOffFactor( float fRollOff );

	// callbacks for traversal functions
	#if _DEBUG
		static void CheckSound( Asura_Handle iActiveSoundIndex );
	#endif
    static void UpdateReverb( Asura_Handle iActiveSoundIndex );
	static void UpdateSound( Asura_Handle iActiveSoundIndex );

	// Sets the overall volume setting for all sounds, taken as a logarithmic value
	// using the same scale as for individual sounds
	static void SetSoundFXVolume( float fVolume );
	static float GetSoundFXVolume()					{ return s_fSoundFXVolume; }

	static void SetReverbChanged( bool bChanged )	{ s_bReverbChanged = bChanged; }
	static bool HasReverbChanged()					{ return s_bReverbChanged; }

	// Loading and unloading sounds

	static bool LoadSound( const char* filename, int loadedSoundIndex);
    static bool LoadSoundFromResource( Asura_Handle fileHandle, int fileSize, int loadedSoundIndex );
	#ifdef ASURA_TOOLS
		static void ForceSoundToBeLoaded( int iLoadedSoundIndex );
		static void ReloadSound( int iLoadedSoundIndex );
	#endif
	static bool UnloadSound( int loadedSoundIndex );
	
	// Per-sound control

	static bool CreateSound( int iLoadedSoundID, Asura_Handle iPlayingSoundHandle, bool bUseHardware3dPan );
	static bool PlaySound( Asura_Handle iPlayingSoundHandle, bool bLooping );
	static bool SoundIsPlaying( Asura_Handle iPlayingSoundHandle );
	static bool StopSound( Asura_Handle iPlayingSoundHandle );
	static bool PauseSound( Asura_Handle iPlayingSoundHandle );
	static bool UnpauseSound( Asura_Handle iPlayingSoundHandle );
	static bool DestroySound( Asura_Handle iPlayingSoundHandle );
	
	static bool SetVolume( Asura_Handle iPlayingSoundHandle, float fVolume );
	static bool SetPan( Asura_Handle iPlayingSoundHandle, float fPan );
	static bool SetSpatial( Asura_Handle iPlayingSoundHandle, bool bIsSpatial );
	static bool SetPitch( Asura_Handle iPlayingSoundHandle, float fPitch );
	static bool SetUseReverb( Asura_Handle iPlayingSoundHandle, bool bUseReverb );
	static bool SetUseDistanceFilter( Asura_Handle iPlayingSoundHandle, bool bUseDistanceFilter );
	static bool SetSoundRadii( Asura_Handle iPlayingSoundHandle, float fInner, float fOuter );
	static bool SetSoundPosition( Asura_Handle iPlayingSoundHandle, const Asura_Vector_3& xPosition );
	static bool SetSoundForcedPanAndFade( Asura_Handle iPlayingSoundHandle, float fPan, float fFade );
	static bool SetCone( Asura_Handle iPlayingSoundHandle, const Asura_Vector_3& xDirection, float fInnerAngle, float fOuterAngle, float fVolumeOutsideCone );
	static bool SetOcclusionLPF( const Asura_Handle iPlayingSoundHandle, const float fOcclusion );
	static bool SetWetDryVolume ( Asura_Handle iPlayingSoundHandle, float fWetVolume, float fDryVolume );
	static bool SetDistanceFilterGain ( Asura_Handle iPlayingSoundHandle, float fGain );

	#ifdef ASURA_TOOLS
		static float GetSoundLength( int iLoadedSoundIndex );
	#endif

private:

    static void InitReverb();
	static bool LoadSoundInternal( const char* filename, int loadedSoundIndex );

	// Pauses/unpauses a sound based on the current setting of m_bPaused and m_bPausedByPitch
	static bool PauseSoundIfRequired( Asura_Handle iPlayingSoundHandle );
	static bool UnpauseSoundIfRequired( Asura_Handle iPlayingSoundHandle );
	
    static bool ReadWav( class CWaveSoundRead* pwaveSoundRead, int loadedSoundIndex );
	#ifdef ASURA_TOOLS
		static void CreateBlankWav( int iLoadedSoundIndex );
	#endif

	static bool                 s_bReverbChanged;
	
	static Asura_PC_LoadedSound	s_axLoadedSounds[ASURA_MAX_NUMBER_OF_LOADED_SOUNDS];
	static int					s_iNumberOfLoadedSounds;
	static int					s_iLoadedSoundsSizeTotal;

	static Asura_PC_ActiveSound	s_axActiveSounds[ASURA_PC_SOUND_MAX_NUMBER_OF_ACTIVE_SOUNDS];
	static int					s_iNumberOfActiveSounds;

	static float 				s_fSoundFXVolume;

	// Low-level system object, agnostic of exactly which low-level code we're using
	static Asura_PC_Sound_API	s_xAPI;

};

#endif	//!defined(ASURA_USE_AUDIO_SYSTEM)

#endif//__ASURA_PC_SOUND_H__
