//////////////////////////////////////////////////////////////////////////////
//
// Asura_Music.cpp
//
// Copyright (c) 2003 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// core header
#include "Core/Asura.h"

#if !defined(ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM)

// own header
#include "Sound/Asura_Music.h"

// engine independent headers
#include "Core/Asura_Handle.h"
#include "Core/Asura_String.h"
#include "Core/Asura_Timers.h"
#include "Debugging/Asura_Assert.h"
#include "Debugging/Asura_DebugOverlay.h"
#include "Sound/Asura_Sound.h"
#include "Sound/Asura_StreamingBackgroundSound_System.h"
#include "Sound/Asura_Sound_Mixer.h"

#define MUSIC_TEST_HACK 0

#if MUSIC_TEST_HACK

Asura_Music_TrackID evilg_eMusicTrack = DREDD_MUSIC_MILITARY1;
bool evilg_bPauseMusic = false;
float evilg_fFadeTime = 3.0f;
#include "Core/Asura_UserInput.h"
void UpdateHack()
{
    if (Asura_UserInput::DebouncedKeyPressed('0'))
    {
        evilg_eMusicTrack = (Asura_Music_TrackID)0;
    }
    else if (Asura_UserInput::DebouncedKeyPressed('1'))
    {
        evilg_eMusicTrack = (Asura_Music_TrackID)1;
    }
    else if (Asura_UserInput::DebouncedKeyPressed('2'))
    {
        evilg_eMusicTrack = (Asura_Music_TrackID)2;
    }
    else if (Asura_UserInput::DebouncedKeyPressed('3'))
    {
        evilg_eMusicTrack = (Asura_Music_TrackID)3;
    }
    if (Asura_UserInput::DebouncedKeyPressed('p'))
    {
        evilg_bPauseMusic = evilg_bPauseMusic ? false : true;
    }

    if (evilg_eMusicTrack != Asura_Music_System::GetCurrentTrack())
    {
        if (evilg_eMusicTrack == ASURA_MUSIC_TRACK_NONE)
        {
            Asura_Music_System::Stop(evilg_fFadeTime);
        }
        else
        {
            Asura_Music_System::Play(evilg_eMusicTrack);
        }
    }
    if (evilg_bPauseMusic)
    {
        Asura_Music_System::Pause(false);
    }
    else
    {
        Asura_Music_System::Unpause(false);
    }
}
#endif //#if MUSIC_TEST_HACK

// C O N S T A N T S /////////////////////////////////////////////////////////
enum Asura_Music_System_ActiveTrackID
{
    ASURA_MUSIC_PRIMARY_TRACK,
    ASURA_MUSIC_SECONDARY_TRACK,
    ASURA_MUSIC_MAX_ACTIVE_TRACKS
};

DEBUGVAR float dbg_fMusicFadeTime = 0.5f;


// C L A S S   D E F I N I T I O N S /////////////////////////////////////////
class Asura_Music_System::ActiveTrack
{
public:
    
    // types
    enum State
    {
        ATS_NONE,
        ATS_PLAYING,
        ATS_FADING_UP,
        ATS_FADING_DOWN,
        ATS_FADING_DOWN_TO_PAUSE,
        ATS_PAUSED,
        ATS_MAX
    };

    // constructor
    ActiveTrack()
    {
        m_eState = ATS_NONE;
        m_eTrackID = ASURA_MUSIC_TRACK_NONE;
        m_iStreamingSoundHandle = ASURA_INVALID_HANDLE;
        m_bLoop = false;
        m_fTimer = 0.0f;
        m_fStateTime = 0.0f;
		m_uFilenameHash = ASURA_HASH_ID_UNSET;
		m_fVolume = 1.0f;
		m_bPrepared = false;
    }

    // other member functions
    void Update(bool bForceVolumeUpdate);
    void CheckStreamingSoundHandle();
    void SetVolume(float fVolume);
    void Play(Asura_Music_TrackID eTrackID, float fVolume,bool bLoop = true,float fFadeTime = 0.5f);
    void Play(const char* pszFilename, float fVolume,bool bLoop = true,float fFadeTime = 0.5f);
	
	void Prepare		(const char* pszFilename);
	void Prepare		(Asura_Music_TrackID eTrackID);
	void PlayPrepared	(float fVolume, bool bLoop = true,float fFadeTime = 0.5f);

	void FadeOut(float fTime);
    void Pause(bool bInstant);
    void Resume(bool bInstant);
    void StopDead();

	Asura_Music_System::ActiveTrack &operator = (const Asura_Music_System::ActiveTrack& xRhs);

    // member data
    State m_eState;
    Asura_Music_TrackID m_eTrackID;
    Asura_Handle m_iStreamingSoundHandle;
    bool  m_bLoop;          // (NJD - 19.05.2003) - added for purposes of saving the state
    float m_fTimer;
    float m_fStateTime;
	Asura_Hash_ID m_uFilenameHash;
	float m_fVolume;
	bool m_bPrepared;
};

// S T A T I C   C L A S S   D A T A /////////////////////////////////////////
Asura_Music_System::ActiveTrack* Asura_Music_System::s_axActiveTracks = NULL;
Asura_Music_System::ActiveTrack* Asura_Music_System::s_pxPreparedTrack = NULL;
u_int Asura_Music_System::s_uPrimaryTrack = 0;
float Asura_Music_System::s_fCurrentTrackVolumeBias = 1.0f;
float Asura_Music_System::s_fMixerVolume = 1.0f;

// C L A S S   F U N C T I O N S /////////////////////////////////////////////

void Asura_Music_System::Initialise()
{
    s_axActiveTracks = new ActiveTrack[ASURA_MUSIC_MAX_ACTIVE_TRACKS];
	s_pxPreparedTrack = new ActiveTrack();
}

void Asura_Music_System::Shutdown()
{
    Stop(true);

	ClearPreparedTrack();
	delete s_pxPreparedTrack;
	s_pxPreparedTrack = NULL;

    delete [] s_axActiveTracks;
    s_axActiveTracks = NULL;
}

void Asura_Music_System::Update()
{
#if MUSIC_TEST_HACK
    UpdateHack();
#endif
	bool bForceVolumeUpdate = false;

	//get the volume from the music mixer (or the master mixer if this doesn't exist)
 	float fOldVolume = s_fMixerVolume;
	s_fMixerVolume = Asura_Sound_Mixer_System::GetMixerVolume(Asura_Sound_Mixer_System::FindChannel(uMIXER_HASHID_MUSIC));

	if(s_fMixerVolume != fOldVolume)
	{
		//mixer has changed , so make sure all tracks recalcalculate the volume this frame
		bForceVolumeUpdate = true;
	}
	
    for (u_int u = 0; u < ASURA_MUSIC_MAX_ACTIVE_TRACKS; ++u)
    {
        s_axActiveTracks[u].Update(bForceVolumeUpdate);
    }
}

void Asura_Music_System::Pause(bool bInstant)
{
    for (u_int u = 0; u < ASURA_MUSIC_MAX_ACTIVE_TRACKS; ++u)
    {
        s_axActiveTracks[u].Pause(bInstant);
    }
}

void Asura_Music_System::Unpause(bool bInstant)
{
    for (u_int u = 0; u < ASURA_MUSIC_MAX_ACTIVE_TRACKS; ++u)
    {
        s_axActiveTracks[u].Resume(bInstant);
    }
}

void Asura_Music_System::Play(Asura_Music_TrackID eTrack,bool bLoop /* = true */, float fCrossfadeTime /* = 0.0f */)
{
	Play(eTrack,1.0f,bLoop,fCrossfadeTime);
}

void Asura_Music_System::Play(Asura_Music_TrackID eTrack, float fVolume,bool bLoop, float fCrossfadeTime)
{
	//Tell background sound system that we want some music , so it can release some sound
	//handles if needed. RAR 15/07/2005
	Asura_StreamingBackgroundSound_System::NotifyMusicStarting(fCrossfadeTime>0.0f);
	
	// KOR - 05/09/2003 12:24:39 - If the platform can't handle multiple streaming sounds, don't crossfade
	// (AW - 29.01.2005) - Changed to account for the number of active streaming sounds that might already be playing..
	if(Asura_Sound_System::GetMaxStreamingSounds() - Asura_Sound_System::GetNumberActiveStreamingSounds() > 0)
	{
		Stop(fCrossfadeTime);
	}
	else
	{
		Stop(0.0f);
	}

    if (eTrack != ASURA_MUSIC_TRACK_NONE)
	{
		//Check if this was a prepared sound
		if( s_pxPreparedTrack->m_bPrepared && ( eTrack == s_pxPreparedTrack->m_eTrackID ) )
		{
			//yup.. copy to the active track and clear the prepared one
			s_axActiveTracks[s_uPrimaryTrack] = *s_pxPreparedTrack;
			s_pxPreparedTrack->m_bPrepared = false;
			s_pxPreparedTrack->m_iStreamingSoundHandle = ASURA_INVALID_HANDLE;
			s_axActiveTracks[s_uPrimaryTrack].PlayPrepared(fVolume * s_fCurrentTrackVolumeBias, bLoop, fCrossfadeTime);
		}
		else
		{
			s_axActiveTracks[s_uPrimaryTrack].Play(eTrack, fVolume * s_fCurrentTrackVolumeBias, bLoop, fCrossfadeTime);
		}
	}
}


void Asura_Music_System::Play(const char* pszFilename, float fVolume, bool bLoop, float fCrossfadeTime)
{
	//Tell background sound system that we want some music , so it can release some sound
	//handles if needed. RAR 15/07/2005
	Asura_StreamingBackgroundSound_System::NotifyMusicStarting(fCrossfadeTime>0.0f);

	// KOR - 05/09/2003 12:24:39 - If the platform can't handle multiple streaming sounds, don't crossfade
	// (AW - 29.01.2005) - Changed to account for the number of active streaming sounds that might already be playing..
	if(Asura_Sound_System::GetMaxStreamingSounds() - Asura_Sound_System::GetNumberActiveStreamingSounds() > 0)
	{
		Stop(fCrossfadeTime);
	}
	else
	{
		Stop(0.0f);
	}

	if (pszFilename)
	{
		//Check if this was a prepared sound
		if( s_pxPreparedTrack->m_bPrepared && ( Asura_GetHashID(pszFilename) == s_pxPreparedTrack->m_uFilenameHash ) )
		{
			//yup.. copy to the active track and clear the prepared one
			s_axActiveTracks[s_uPrimaryTrack] = *s_pxPreparedTrack;
			s_pxPreparedTrack->m_bPrepared = false;
			s_pxPreparedTrack->m_iStreamingSoundHandle = ASURA_INVALID_HANDLE;
			s_axActiveTracks[s_uPrimaryTrack].PlayPrepared(fVolume * s_fCurrentTrackVolumeBias, bLoop, fCrossfadeTime);
		}
		else
		{
			s_axActiveTracks[s_uPrimaryTrack].Play(pszFilename, fVolume * s_fCurrentTrackVolumeBias, bLoop, fCrossfadeTime);
		}
	}
}


bool Asura_Music_System::Prepare (const char* pszFilename)
{
	if(!s_pxPreparedTrack)
	{
		return false;
	}
	if(s_pxPreparedTrack->m_bPrepared)
	{
		Asura_Assert(false, "Music track was prepared but never played");
		ClearPreparedTrack();
	}

	s_pxPreparedTrack->Prepare(pszFilename);

	return true;
}


bool Asura_Music_System::Prepare (Asura_Music_TrackID eTrack)
{
	if(!s_pxPreparedTrack)
	{
		return false;
	}
	if(s_pxPreparedTrack->m_bPrepared)
	{
		Asura_Assert(false, "Music track was prepared but never played");
		ClearPreparedTrack();
	}

	s_pxPreparedTrack->Prepare(eTrack);

	return true;
}


void Asura_Music_System::Stop(float fFadeoutTime /* = 0.5f */)
{
    // stop primary track
    if (fFadeoutTime == 0.0f)
    {
        s_axActiveTracks[s_uPrimaryTrack].StopDead();
    }
    else
    {
        s_axActiveTracks[s_uPrimaryTrack].FadeOut(fFadeoutTime);
    }

    // kill the secondary track
    s_axActiveTracks[1 - s_uPrimaryTrack].StopDead();
    // use the old secondary track for the new primary
    s_uPrimaryTrack = 1 - s_uPrimaryTrack;
}

bool Asura_Music_System::StopSecondary()
{
	if(s_axActiveTracks[1 - s_uPrimaryTrack].m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)	
	{
		s_axActiveTracks[1 - s_uPrimaryTrack].StopDead();
		return true;		
	}
	//no secondary track was playing
	return false;
}

Asura_Music_TrackID Asura_Music_System::GetCurrentTrack()
{
    return s_axActiveTracks[s_uPrimaryTrack].m_eTrackID;
}

void Asura_Music_System::GetCurrentTrackData( Asura_Music_TrackID& eTrackId, bool& bLoop )
{
    eTrackId = s_axActiveTracks[ s_uPrimaryTrack ].m_eTrackID;
    bLoop    = s_axActiveTracks[ s_uPrimaryTrack ].m_bLoop;
}

Asura_Hash_ID Asura_Music_System::GetCurrentTrackHash()
{
    if(s_axActiveTracks[ s_uPrimaryTrack ].m_iStreamingSoundHandle  != ASURA_INVALID_HANDLE)
	{
		return s_axActiveTracks[ s_uPrimaryTrack ].m_uFilenameHash;
	}
	return ASURA_HASH_ID_UNSET;
}


float Asura_Music_System::GetCurrentTrackPosition()
{
    if(s_axActiveTracks[ s_uPrimaryTrack ].m_iStreamingSoundHandle  != ASURA_INVALID_HANDLE)
	{
		return Asura_Sound_System::GetStreamingSoundPosition(s_axActiveTracks[ s_uPrimaryTrack ].m_iStreamingSoundHandle);
	}
	return 0;
}

float Asura_Music_System::GetCurrentTrackLength()
{
    if(s_axActiveTracks[ s_uPrimaryTrack ].m_iStreamingSoundHandle  != ASURA_INVALID_HANDLE)
	{
		return Asura_Sound_System::GetStreamingSoundLength(s_axActiveTracks[ s_uPrimaryTrack ].m_iStreamingSoundHandle);
	}
	return 0;
}

bool Asura_Music_System::IsCurrentTrackFading()
{
    if(s_axActiveTracks[ s_uPrimaryTrack ].m_iStreamingSoundHandle  != ASURA_INVALID_HANDLE)
	{
		return s_axActiveTracks[ s_uPrimaryTrack ].m_eState == ActiveTrack::ATS_FADING_UP ||
				s_axActiveTracks[ s_uPrimaryTrack ].m_eState == ActiveTrack::ATS_FADING_DOWN ||
				s_axActiveTracks[ s_uPrimaryTrack ].m_eState == ActiveTrack::ATS_FADING_DOWN_TO_PAUSE;
	}
	return false;
}


bool Asura_Music_System::IsSecondaryTrackFading()
{
	if(s_axActiveTracks[ 1 - s_uPrimaryTrack ].m_iStreamingSoundHandle  != ASURA_INVALID_HANDLE)
	{
		return s_axActiveTracks[ 1 - s_uPrimaryTrack ].m_eState == ActiveTrack::ATS_FADING_UP ||
			s_axActiveTracks[ 1 - s_uPrimaryTrack ].m_eState == ActiveTrack::ATS_FADING_DOWN ||
			s_axActiveTracks[ 1 - s_uPrimaryTrack ].m_eState == ActiveTrack::ATS_FADING_DOWN_TO_PAUSE;
	}
	return false;
}


bool Asura_Music_System::IsCurrentTrackLooping()
{
    if(s_axActiveTracks[ s_uPrimaryTrack ].m_iStreamingSoundHandle  != ASURA_INVALID_HANDLE)
	{
		return s_axActiveTracks[ s_uPrimaryTrack ].m_bLoop;
	}
	return false;
}

int Asura_Music_System::GetNumberOfSoundHandlesUsed()
{
	int iHandles = 0;
    for (u_int u = 0; u < ASURA_MUSIC_MAX_ACTIVE_TRACKS; ++u)
	{
		if(s_axActiveTracks[u].m_iStreamingSoundHandle != ASURA_INVALID_HANDLE) iHandles++;
	}
	return iHandles;
}

void Asura_Music_System::SetCurrentTrackVolumeBias(const float fVolBias)
{
	s_fCurrentTrackVolumeBias = Asura_Maths::ClampToRange(fVolBias, 0.0f, 1.0f);
	s_axActiveTracks[s_uPrimaryTrack].SetVolume((s_axActiveTracks[s_uPrimaryTrack].m_fVolume));
}

void Asura_Music_System::ClearPreparedTrack ()
{
	if(s_pxPreparedTrack)
	{
		if(s_pxPreparedTrack->m_bPrepared)
		{
			//Looks like we didnt use this prepared sound, so we should destroy it
			Asura_Sound_System::ReleaseStreamingSound(s_pxPreparedTrack->m_iStreamingSoundHandle);
			s_pxPreparedTrack->m_bPrepared = false;
			s_pxPreparedTrack->m_iStreamingSoundHandle = ASURA_INVALID_HANDLE;
		}
	}
}

void Asura_Music_System::ActiveTrack::Update(bool bForceVolumeUpdate)
{
    switch (m_eState)
    {
        case ATS_NONE:
        {}
        break;

        case ATS_PLAYING:
        {
            CheckStreamingSoundHandle();
			if(bForceVolumeUpdate) SetVolume(m_fVolume);
        }
        break;

        case ATS_FADING_UP:
        {
            CheckStreamingSoundHandle();
            m_fTimer -= Asura_Timers::GetFrameTime();
            if (m_fTimer <= 0.0f)
            {
                SetVolume(m_fVolume);
                m_eState = ATS_PLAYING;
            }
            else
            {
                float fVolumeScale = 1.0f - (m_fTimer / m_fStateTime);
				//Try a non-linear fade. RAR 30/11/2004
				fVolumeScale = 1.0f - (1.0f-fVolumeScale)*(1.0f-fVolumeScale);
                SetVolume(fVolumeScale*m_fVolume);
            }
        }
        break;

        case ATS_FADING_DOWN:
        {
            CheckStreamingSoundHandle();
            m_fTimer -= Asura_Timers::GetFrameTime();
            if (m_fTimer <= 0.0f)
            {
                StopDead();
            }
            else
            {
                float fVolumeScale = m_fTimer / m_fStateTime;
				//Try a non-linear fade. RAR 30/11/2004
				fVolumeScale = 1.0f - (1.0f-fVolumeScale)*(1.0f-fVolumeScale);
				SetVolume(fVolumeScale * m_fVolume);
            }
        }
        break;

        case ATS_FADING_DOWN_TO_PAUSE:
        {
            CheckStreamingSoundHandle();
            m_fTimer -= Asura_Timers::GetFrameTime();
            if (m_fTimer <= 0.0f)
            {
                Pause(true);    // instant pause
            }
            else
            {
                float fVolumeScale = m_fTimer / m_fStateTime;
				//Try a non-linear fade. RAR 30/11/2004
				fVolumeScale = 1.0f - (1.0f-fVolumeScale)*(1.0f-fVolumeScale);
                SetVolume(fVolumeScale * m_fVolume);
            }
        }
        break;

        case ATS_PAUSED:
        {}
        break;

        default:
        {
            Asura_Assert(false, "unexpected state");
            break;
        }
    }
}

void Asura_Music_System::ActiveTrack::CheckStreamingSoundHandle()
{
    if (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
	{
		if(Asura_Sound_System::StreamingSoundIsFinished(m_iStreamingSoundHandle))
		{
			StopDead();
		}
	}
}

void Asura_Music_System::ActiveTrack::SetVolume(float fVolume)
{
    if (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
    {
		Asura_Sound_System::StreamingSoundSetVolume(m_iStreamingSoundHandle, fVolume * s_fCurrentTrackVolumeBias * s_fMixerVolume);
    }
}


void Asura_Music_System::ActiveTrack::Play(Asura_Music_TrackID eTrackID, float fVolume,bool bLoop /* = true */, float fFadeTime /*= 0.5f*/)
{
	if(!m_bPrepared)
	{
		Asura_Assert(m_iStreamingSoundHandle == ASURA_INVALID_HANDLE, "handle leak");
		char szFilename[256];
		Asura_PrintfToBfr(szFilename, "%s%s", 256, true, s_szPath, s_aszFilenames[eTrackID]);
		m_iStreamingSoundHandle = Asura_Sound_System::CreateStreamingSound(szFilename);

		m_uFilenameHash = Asura_GetHashID(szFilename);
	}
    if (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
    {
		Asura_Sound_System::StreamingSoundSetVolume(m_iStreamingSoundHandle, fVolume * s_fMixerVolume);
        Asura_Sound_System::PlayStreamingSound(m_iStreamingSoundHandle, bLoop);
    }

    m_eState   = ATS_FADING_UP;
    m_eTrackID = eTrackID;
    m_bLoop    = bLoop;
	m_fTimer = fFadeTime;
	m_fStateTime = fFadeTime;
	m_fVolume = fVolume;
	m_bPrepared = false;
}

void Asura_Music_System::ActiveTrack::Play(const char* pszFilename, float fVolume, bool bLoop /* = true */, float fFadeTime /*= 0.5f*/)
{
    if(!m_bPrepared)
	{
		Asura_Assert(m_iStreamingSoundHandle == ASURA_INVALID_HANDLE, "handle leak");
		m_iStreamingSoundHandle = Asura_Sound_System::CreateStreamingSound(pszFilename);
	}
    if (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
    {
		Asura_Sound_System::StreamingSoundSetVolume(m_iStreamingSoundHandle, fVolume * s_fMixerVolume);
        Asura_Sound_System::PlayStreamingSound(m_iStreamingSoundHandle, bLoop);
    }

    m_eState   = ATS_FADING_UP;
    m_eTrackID = ASURA_MUSIC_TRACK_NONE;//Not an ideal choice for track ID , but will work for now... RAR
    m_bLoop    = bLoop;
	m_fTimer = fFadeTime;
	m_fStateTime = fFadeTime;
	m_uFilenameHash = Asura_GetHashID(pszFilename);
	m_fVolume = fVolume;
	m_bPrepared = false;
}


void Asura_Music_System::ActiveTrack::Prepare(const char* pszFilename)
{
	Asura_Assert(m_iStreamingSoundHandle == ASURA_INVALID_HANDLE, "handle leak");
	m_iStreamingSoundHandle = Asura_Sound_System::CreateStreamingSound(pszFilename);
	m_uFilenameHash = Asura_GetHashID(pszFilename);
	m_bPrepared = true;
}

void Asura_Music_System::ActiveTrack::Prepare (Asura_Music_TrackID eTrackID)
{
	char szFilename[256];
	Asura_PrintfToBfr(szFilename, "%s%s", 256, true, s_szPath, s_aszFilenames[eTrackID]);
	m_iStreamingSoundHandle = Asura_Sound_System::CreateStreamingSound(szFilename);
	m_eTrackID = eTrackID;
	m_uFilenameHash = Asura_GetHashID(szFilename);
}

void Asura_Music_System::ActiveTrack::PlayPrepared(float fVolume, bool bLoop /* = true */, float fFadeTime /*= 0.5f*/)
{
	Asura_Assert((m_iStreamingSoundHandle != ASURA_INVALID_HANDLE) && m_bPrepared, "Expected a valid sound handle and prepared sound");
	if (m_bPrepared && (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE))
	{
		m_bPrepared = false;
		Asura_Sound_System::StreamingSoundSetVolume(m_iStreamingSoundHandle, fVolume * s_fMixerVolume);
		Asura_Sound_System::PlayStreamingSound(m_iStreamingSoundHandle, bLoop);
	}

	m_eState   = ATS_FADING_UP;
	m_bLoop    = bLoop;
	m_fTimer = fFadeTime;
	m_fStateTime = fFadeTime;
	m_fVolume = fVolume;
}

void Asura_Music_System::ActiveTrack::FadeOut(float fTime)
{
    m_eState = ATS_FADING_DOWN;
    m_fTimer = fTime;
    m_fStateTime = fTime;
}

void Asura_Music_System::ActiveTrack::Pause(bool bInstant)
{
    if (m_eState == ATS_PAUSED) return;
    
    if(m_eState == ATS_FADING_DOWN)
	{
		//Treat tracks that are fading out to stop slightly differently , since
		//we don't want them to start up again when resumed.RAR 19/08/2005
     	if (bInstant)
		{
			StopDead();
		}
		else
		{
			//May want to hurry up the fade if the fade time is longer than the pause fade.
			if(m_fTimer > dbg_fMusicFadeTime)
			{
				//scale the timer so there isn't a jump in volume
				m_fTimer = (m_fTimer/m_fStateTime)*dbg_fMusicFadeTime;
		        m_fStateTime = dbg_fMusicFadeTime;

			}
		}
	}
	else
	{
    	if (bInstant)
    	{
    	    if (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
    	    {
    	        Asura_Sound_System::PauseStreamingSound(m_iStreamingSoundHandle);
    	    }

    	    m_eState = ATS_PAUSED;
			
    	}
    	else if (m_eState != ATS_FADING_DOWN_TO_PAUSE)
    	{
    	    m_eState = ATS_FADING_DOWN_TO_PAUSE;
    	    m_fTimer = dbg_fMusicFadeTime;
    	    m_fStateTime = dbg_fMusicFadeTime;
    	}
	}
}

void Asura_Music_System::ActiveTrack::Resume(bool bInstant)
{
    if (m_eState == ATS_PLAYING) return;
    
    if (bInstant)
    {
        SetVolume(m_fVolume);
        if (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
        {
            Asura_Sound_System::ResumeStreamingSound(m_iStreamingSoundHandle);
        }
        m_eState = ATS_PLAYING;
    }
    else if (m_eState != ATS_FADING_UP && m_eState != ATS_FADING_DOWN)
    {
        SetVolume(0.0f);
        if (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
        {
            Asura_Sound_System::ResumeStreamingSound(m_iStreamingSoundHandle);
        }
        m_eState = ATS_FADING_UP;
        m_fTimer = dbg_fMusicFadeTime;
        m_fStateTime = dbg_fMusicFadeTime;
    }
}

void Asura_Music_System::ActiveTrack::StopDead()
{
    if (m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
    {
        Asura_Sound_System::StopStreamingSound(m_iStreamingSoundHandle);
        Asura_Sound_System::ReleaseStreamingSound(m_iStreamingSoundHandle);
        m_iStreamingSoundHandle = ASURA_INVALID_HANDLE;
    }

    m_eState   = ATS_NONE;
    m_eTrackID = ASURA_MUSIC_TRACK_NONE;
    m_bLoop    = false;
	m_uFilenameHash = ASURA_HASH_ID_UNSET;
}


Asura_Music_System::ActiveTrack &Asura_Music_System::ActiveTrack::operator = (const Asura_Music_System::ActiveTrack& xRhs)
{
	// member data
	m_eState				= xRhs.m_eState;
	m_eTrackID				= xRhs.m_eTrackID;
	m_iStreamingSoundHandle = xRhs.m_iStreamingSoundHandle;
	m_bLoop					= xRhs.m_bLoop;
	m_fTimer				= xRhs.m_fTimer;
	m_fStateTime			= xRhs.m_fStateTime;
	m_uFilenameHash			= xRhs.m_uFilenameHash;
	m_fVolume				= xRhs.m_fVolume;
	m_bPrepared				= xRhs.m_bPrepared;
    
	return *this;
}

#ifdef ASURA_TOOLS
const char* Asura_Music_System::GetTrackName(int iIndex)
{
	if(iIndex>=0 && iIndex< ASURA_NUM_MUSIC_TRACKS)
	{
		return s_aszNames[iIndex];
	}

	return 0;
}
#endif

#if defined( ASURA_USE_DEBUGOVERLAY )

static const char* g_apszMusicStateStrings[] =
{
	"None",
	"Playing",
	"Fading up",
	"Fading down",
	"Fading down to pause",
	"Paused",
	"Max"
};

void Asura_Music_System::DoMusicDebugOverlay ( void* const pxIgnore )
{
	if(!s_axActiveTracks || !s_pxPreparedTrack)
	{
		return;
	}
	ActiveTrack* pxTrack = 0;

	pxTrack = &s_axActiveTracks[ s_uPrimaryTrack ];
	if(pxTrack && pxTrack->m_iStreamingSoundHandle  != ASURA_INVALID_HANDLE)
	{
		Asura_DebugOverlay::DrawConsoleText( ASURA_DO_METAMUSIC, "Primary   - Hash: %X, State: %s, Volume: %.2f ", pxTrack->m_uFilenameHash, g_apszMusicStateStrings[pxTrack->m_eState], Asura_Maths::FtoD(pxTrack->m_fVolume));
	}
	
	pxTrack = &s_axActiveTracks[ 1 - s_uPrimaryTrack ];
	if(pxTrack && pxTrack->m_iStreamingSoundHandle  != ASURA_INVALID_HANDLE)
	{
		Asura_DebugOverlay::DrawConsoleText( ASURA_DO_METAMUSIC, "Secondary - Hash: %X, State: %s, Volume: %.2f ", pxTrack->m_uFilenameHash, g_apszMusicStateStrings[pxTrack->m_eState], Asura_Maths::FtoD(pxTrack->m_fVolume));
	}
	
	pxTrack = s_pxPreparedTrack;
	if(pxTrack && pxTrack->m_iStreamingSoundHandle != ASURA_INVALID_HANDLE)
	{
		Asura_DebugOverlay::DrawConsoleText( ASURA_DO_METAMUSIC, "Prepared  - Hash: %X, State: %s, Prepared: %s ", pxTrack->m_uFilenameHash, g_apszMusicStateStrings[pxTrack->m_eState], pxTrack->m_bPrepared ? "Yes" : "No");
	}
	
}
#endif

#endif	//!defined(ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM)

//eof

