//-----------------------------------------------------------------------------
// File: EnumSoundtrack.cpp
//
// Desc: Enumerate WMA soundtracks
//
// Hist: 02.16.01 - New for March XDK release
//       03.06.02 - Added audio level meters for April 02 XDK release
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include <string>
#include <vector>
using namespace std;

struct fileDisplay {
	string name;
	string path;
	bool isAGame;
	bool isARoot;
	bool isADirectory;
	bool topLevel;
	int soundTrack;
	int song;
	int archive;
};
extern vector<fileDisplay> fileList;
extern bool videoRender;
#include "EnumSoundtrack.h"
#include <cassert>
extern LPDIRECTSOUND8  m_pDSound ; 
extern int EnableVideoAudio; 

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------


// Maximum viewable songs
const DWORD MAX_SONGS_DISPLAYED = 10;

// Must be this far from center on 0.0 - 1.0 scale
const FLOAT JOY_THRESHOLD = 0.25f;

// Text colors
const DWORD COLOR_HIGHLIGHT = 0xff00ff00;
const DWORD COLOR_NORMAL = 0xffffffff;

// Controller repeat values
const FLOAT fINITIAL_REPEAT = 0.333f; // 333 mS recommended for first repeat
const FLOAT fSTD_REPEAT     = 0.085f; // 85 mS recommended for repeat rate




//-----------------------------------------------------------------------------
// Name: Song()
// Desc: Construct song object
//-----------------------------------------------------------------------------
Song::Song( DWORD dwId, const WCHAR* strAlbum, const WCHAR* strSong, DWORD dwLength )
{
    m_dwId = dwId;
    lstrcpynW( m_strAlbum, strAlbum, MAX_SOUNDTRACK_NAME );
    lstrcpynW( m_strSong, strSong, MAX_SONG_NAME );
    m_dwLength = dwLength;
}




//-----------------------------------------------------------------------------
// Name: GetAlbum()
// Desc: Returns the album name
//-----------------------------------------------------------------------------
const WCHAR* Song::GetAlbum() const
{
    return m_strAlbum;
}




//-----------------------------------------------------------------------------
// Name: GetSong()
// Desc: Returns the song name
//-----------------------------------------------------------------------------
const WCHAR* Song::GetSong() const
{
    return m_strSong;
}




//-----------------------------------------------------------------------------
// Name: GetLength()
// Desc: Returns length of song in mS
//-----------------------------------------------------------------------------
DWORD Song::GetLength() const
{
    return m_dwLength;
}




//-----------------------------------------------------------------------------
// Name: GetLength()
// Desc: Formats the incoming string as "MM:SS"
//-----------------------------------------------------------------------------
VOID Song::GetLength( CHAR* strMMSS ) const
{
    assert( strMMSS != NULL );

    // Convert to seconds
    DWORD dwSeconds = m_dwLength / 1000;

    // Round to nearest second
    if( m_dwLength - ( dwSeconds * 1000 ) >= 500 )
        ++dwSeconds;

    // Determine minutes
    DWORD dwMinutes = dwSeconds / 60;

    // Remaining seconds
    dwSeconds -= ( dwMinutes * 60 );

    // Format in strMMSS
    wsprintfA( strMMSS, "%lu:%02lu", dwMinutes, dwSeconds );
}




//-----------------------------------------------------------------------------
// Name: Open()
// Desc: Open the soundtrack WMA song and return file handle
//-----------------------------------------------------------------------------
HANDLE Song::Open( BOOL bAsync ) const
{
    return XOpenSoundtrackSong( m_dwId, bAsync );
}




//-----------------------------------------------------------------------------
// Name: main()
// Desc: Entry point to the program. Initializes everything, and goes into a
//       message-processing loop. Idle time is used to render the scene.
//-----------------------------------------------------------------------------
//VOID __cdecl main()
//{
  //  CXBEnumSoundtrack xbApp;

  //  if( FAILED( xbApp.Create() ) )
   //     return;

  //  xbApp.Run();
//}









//-----------------------------------------------------------------------------
// Name: DownloadEffectsImage()
// Desc: Downloads an effects image to the DSP
//-----------------------------------------------------------------------------
HRESULT stDownloadEffectsImage( CHAR* strScratchFile )
{
    HANDLE hFile;
    DWORD dwSize = 0;
    PVOID pBuffer = NULL;
    HRESULT hr = S_OK;
    LPDSEFFECTIMAGEDESC pDesc;
    DSEFFECTIMAGELOC EffectLoc;

    // Open scratch image file generated by xps2 tool
    hFile = CreateFile( strScratchFile, GENERIC_READ, 0, NULL,
                        OPEN_EXISTING, 0, NULL );
    if( hFile == INVALID_HANDLE_VALUE )
    {
        OUTPUT_DEBUG_STRING( "Failed to open the dsp image file.\n" );
        DWORD err = GetLastError();
        hr = HRESULT_FROM_WIN32(err);
    }

    if( SUCCEEDED(hr) )
    {
        // Determine the size of the scratch image by seeking to
        // the end of the file
        dwSize = SetFilePointer( hFile, 0, NULL, FILE_END );
        SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
    
        // Allocate memory to read the scratch image from disk
        pBuffer = new BYTE[dwSize];

        // Read the image in
        DWORD dwBytesRead;
        BOOL bResult = ReadFile( hFile, pBuffer, dwSize, &dwBytesRead, 0 );
        if (!bResult)
        {
            OUTPUT_DEBUG_STRING( "\n Failed to open the dsp image file.\n" );
            DWORD err = GetLastError();
            hr = HRESULT_FROM_WIN32(err);
        }
    }

    if( SUCCEEDED(hr) )
    {
        // Call DSound API to download the image..
        EffectLoc.dwI3DL2ReverbIndex = GraphI3DL2_I3DL2Reverb;
        EffectLoc.dwCrosstalkIndex   = GraphXTalk_XTalk;

        hr = m_pDSound->DownloadEffectsImage( pBuffer, dwSize, &EffectLoc, &pDesc );
    }

    delete[] pBuffer;

    if( hFile != INVALID_HANDLE_VALUE ) 
        CloseHandle( hFile );

    return hr;
}




//-----------------------------------------------------------------------------
// Name: Initialize()
// Desc: Sets up the enum soundtrack example
//-----------------------------------------------------------------------------
HRESULT stInitialize()
{
    // Set the matrices
  //  D3DXVECTOR3 vEye(-2.5f, 2.0f, -4.0f );
  //  D3DXVECTOR3 vAt( 0.0f, 0.0f, 0.0f );
  //  D3DXVECTOR3 vUp( 0.0f, 1.0f, 0.0f );

  //  D3DXMATRIX matWorld, matView, matProj;
 //   D3DXMatrixIdentity( &matWorld );
 //   D3DXMatrixLookAtLH( &matView, &vEye,&vAt, &vUp );
 //   D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 4.0f/3.0f, 1.0f, 100.0f );

 //   m_pd3dDevice->SetTransform( D3DTS_WORLD,      &matWorld );
  //  m_pd3dDevice->SetTransform( D3DTS_VIEW,       &matView );
 //   m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

    // Create a font
 //   if( FAILED( m_Font.Create( "Font.xpr" ) ) )
 //       return XBAPPERR_MEDIANOTFOUND;

    // Create help
 //   if( FAILED( m_Help.Create( "Gamepad.xpr" ) ) )
 //       return XBAPPERR_MEDIANOTFOUND;

   // if( FAILED( DirectSoundCreate( NULL, &m_pDSound, NULL ) ) )
   //     return E_FAIL;

    // download the standard DirectSound effects image
   // if( FAILED( stDownloadEffectsImage("d:\\media\\dsstdfx.bin") ) )
    //    return E_FAIL;

    //m_bDrawHelp = FALSE;

//	m_fRepeatDelay = fINITIAL_REPEAT;
 //   m_iCurrSong    = 0;
 //   m_iTopSong     = 0;
 //   m_hSongFile    = INVALID_HANDLE_VALUE;
 //   stm_pStream      = NULL;
   // m_bPlaying     = FALSE;

    // Load the list of soundtracks
    stInitSoundtrackList();

    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: InitSoundtrackList()
// Desc: Load all soundtracks into memory
//-----------------------------------------------------------------------------
VOID stInitSoundtrackList()
{
	//dprintf("stInitSoundtrackList()\n");
	fileList.clear();

    // Enumerate all soundtracks
    XSOUNDTRACK_DATA SoundtrackData;
    HANDLE hFind = XFindFirstSoundtrack( &SoundtrackData );
    if( hFind != INVALID_HANDLE_VALUE )
    {
		int i = 1;
        stAddSoundtrackSongs( SoundtrackData, i );
		i = 2;
		while( XFindNextSoundtrack( hFind, &SoundtrackData ) ) {
           
			stAddSoundtrackSongs( SoundtrackData, i);
			 i++;
		}
        XFindClose( hFind );
    }
	else {
		fileDisplay f;
		std::string a  = "No soundtracks found";
		f.name =  a;
		f.archive = 0;
		f.path = f.name;
		f.isAGame = true;
		f.isARoot = false;
		f.isADirectory = false;
		f.topLevel = false;
		f.soundTrack = -1;
		f.song = 0;
		fileList.push_back(f);
	}
}




//-----------------------------------------------------------------------------
// Name: AddSoundtrackSongs()
// Desc: Load all songs from the given soundtrack into the list
//-----------------------------------------------------------------------------
VOID stAddSoundtrackSongs( const XSOUNDTRACK_DATA& SoundtrackData, int track)
{
   int s = 0;   
	// Get each song
    for( UINT i = 0; i < SoundtrackData.uSongCount; ++i )
    {
        DWORD dwSongId;
        DWORD dwSongLength;
        WCHAR strSong[ MAX_SONG_NAME ];
        if( XGetSoundtrackSongInfo( SoundtrackData.uSoundtrackId, i, &dwSongId,
                                    &dwSongLength, strSong, MAX_SONG_NAME ) )
        {
            // Add it to the list
            m_SongList.push_back( Song( dwSongId, SoundtrackData.szName, 
                                        strSong, dwSongLength ) );


		   char bufa[32];
		   char bufb[32];
		   for(int i = 0; i < 32; i++) {
				bufa[i] = SoundtrackData.szName[i];
				bufb[i] = strSong[i];
		   }

			fileDisplay f;
			f.archive = 0;
			std::string a  = bufa;
			a = a + ": ";
			std::string b = bufb;
			a = a + b;
			f.name =  a;
			f.path = f.name;//pathToSearch + fileFound;

			f.isAGame = true;
			f.isARoot = false;
			f.isADirectory = false;
			f.topLevel = false;
			f.soundTrack = track;
			f.song = s;
			s++;
			fileList.push_back(f);
        }
    }
}






//-----------------------------------------------------------------------------
// Name: FrameMove()
// Desc: Called once per frame; the entry point for animating the scene
//-----------------------------------------------------------------------------
HRESULT stFrameMove()
{
   // stValidateState();

    // Toggle help
   // if( m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_BACK )
   // {
    //    m_bDrawHelp = !m_bDrawHelp;
   // }

    // Poll the system for events
    //Event ev = GetControllerEvent();

    // Update the current state
    //UpdateState( ev );

    // Keep any WMA file playing
	if( stm_pStream ) {
		if(FAILED(stm_pStream->Process()) ) {}	
	}
	
	if(!videoRender || !EnableVideoAudio)
	    DirectSoundDoWork();

    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Called once per frame, the call is the entry point for 3d rendering.
//       This function sets up render states, clears the viewport, and renders
//       the scene.
//-----------------------------------------------------------------------------
HRESULT stRender()
{
    // Draw a gradient filled background
    //RenderGradientBackground( 0xff102030, 0xff405060 );

    // Show title, frame rate, and help
   // if( m_bDrawHelp )
    //    m_Help.Render( &m_Font, g_HelpCallouts, NUM_HELP_CALLOUTS );
   // else
   // {
        // Draw title & framerate
        m_Font.Begin();
        m_Font.SetScaleFactors( 1.2f, 1.2f );
        m_Font.DrawText( 48, 36, 0xffffffff, L"EnumSoundtrack" );
        m_Font.SetScaleFactors( 1.0f, 1.0f );

        if( m_SongList.empty() )
        {
            m_Font.DrawText( 80.0f, 68.0f, 0xffffffff, L"No soundtracks available" );
        }
        else
        {
            // Show the list of songs
            FLOAT fTop = 90.0f;
            FLOAT fOffset = 24.0f;
            SongListIndex j = 0;
            for( SongListIndex i = m_iTopSong; i < m_SongList.size() &&
                                               j < MAX_SONGS_DISPLAYED; ++i, ++j )
            {
                const Song& song = m_SongList[i];

                CHAR strMMSS[32];
                song.GetLength( strMMSS );

                WCHAR strAlbum[256];
                WCHAR strSong[ 256 ];
                wsprintfW( strAlbum, L"%ls: ", song.GetAlbum() );
                wsprintfW( strSong, L"%ls (%hs)", song.GetSong(), strMMSS );
                DWORD dwColor1 = ( i == m_iCurrSong ) ? 0xffffffff : 0xff808080;
                DWORD dwColor2 = ( i == m_iCurrSong ) ? 0xffffff00 : 0xff808000;

                if( i == m_iCurrSong )
                    m_Font.DrawText( 80.0f, fTop + (fOffset * j ), 0xffffffff, GLYPH_RIGHT_TICK, XBFONT_RIGHT );

                m_Font.DrawText( 80.0f, fTop + (fOffset * j ), dwColor1, strAlbum );
                m_Font.DrawText( dwColor2, strSong );
            }

            // Show scroll arrows
            BOOL bShowTopArrow = m_iTopSong > 0;
            BOOL bShowBtmArrow = m_iTopSong + MAX_SONGS_DISPLAYED < m_SongList.size();
            if( bShowTopArrow )
                m_Font.DrawText( 64, 70, COLOR_NORMAL, GLYPH_UP_TICK );
            if( bShowBtmArrow )
                m_Font.DrawText( 64, 320, COLOR_NORMAL, GLYPH_DOWN_TICK );

            // Descriptive text
            m_Font.DrawText( 320, 340, 0xffffffff, m_bPlaying ? L"Playing..." : L"Stopped", XBFONT_CENTER_X );
            m_Font.DrawText( 320, 380, COLOR_NORMAL, GLYPH_A_BUTTON L" Play    " GLYPH_B_BUTTON L" Stop", XBFONT_CENTER_X );

            m_Font.End();
        }

        // Draw the on-screen audio level meters
        XBSound_DrawLevelMeters( m_pDSound, 64.0f, 400.0f, 60.0f, 30.0f );
    //}

    // Present the scene
    //Device->Present( NULL, NULL, NULL, NULL );

    return S_OK;
}






//-----------------------------------------------------------------------------
// Name: UpdateState()
// Desc: State machine updates the current context based on the incoming event
//-----------------------------------------------------------------------------
VOID stUpdateState( Event ev )
{
    switch( ev )
    {
        case EV_NULL:
            break;
        case EV_A_BUTTON:
//            stStart();
            break;
        case EV_B_BUTTON:
            stStop();
            break;
        case EV_UP:
            // If we're at the top of the displayed list, shift the display
            if( m_iCurrSong == m_iTopSong )
            {
                if( m_iTopSong > 0 )
                    --m_iTopSong;
            }
            // Move to previous song
            if( m_iCurrSong > 0 )
                --m_iCurrSong;
            break;
        case EV_DOWN:
            // If we're at the bottom of the displayed list, shift the display
            if( m_iCurrSong == m_iTopSong + MAX_SONGS_DISPLAYED - 1 )
            {
                if( m_iTopSong + MAX_SONGS_DISPLAYED < m_SongList.size() )
                    ++m_iTopSong;
            }
            // Move to next song
            if( m_iCurrSong < m_SongList.size() - 1 )
                ++m_iCurrSong;
            break;
    }
}




//-----------------------------------------------------------------------------
// Name: Start()
// Desc: Start the selected song
//-----------------------------------------------------------------------------
VOID stStart(int s)
{
	

	if( m_bPlaying ) {
        
		stStop();
	}

    m_hSongFile = m_SongList[s].Open( TRUE );

	if(m_hSongFile == NULL) //dprintf("SOng handle is null\n");

    stm_pStream = new CWMAFileStream();
    if(FAILED(stm_pStream->Initialize( m_hSongFile )))
		//dprintf("Failed to init song\n");

	stm_pStream->Pause( DSSTREAMPAUSE_RESUME );
	
    m_bPlaying = TRUE;
}


//-----------------------------------------------------------------------------
// Name: Stop()
// Desc: Stop the song that's playing and close the file
//-----------------------------------------------------------------------------
VOID stStop()
{
    if( stm_pStream )
    {
        delete stm_pStream;
        stm_pStream = NULL;
        m_bPlaying = FALSE;
    }

    if( m_hSongFile != INVALID_HANDLE_VALUE )
    {
        CloseHandle( m_hSongFile );
        m_hSongFile = INVALID_HANDLE_VALUE;
    }
}
