//-----------------------------------------------------------------------------
// File: HEvt.cpp
//-----------------------------------------------------------------------------
#include "../Basic/ZooScene.h"


//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
extern mmachine	mm ;
extern int ObjSound ;
extern int SoundPlay ;
extern int SND_TIME ;
extern HWND hwnd ;


//-----------------------------------------------------------------------------
// Name: HEvt::HEvt()
// Constructor
//-----------------------------------------------------------------------------
HEvt::HEvt( HSound* pHSound, int handler )
	 :HThread()	
{
	Evts.resize(0) ;
	this->pHSound = pHSound ;
	this->handler = handler ;
}




//-----------------------------------------------------------------------------
// Name: HEvt::~HEvt()
// Destructor
//-----------------------------------------------------------------------------
HEvt::~HEvt()
{
	Stop() ;

    // Iterator is used to loop through the vector.
    EVTVECT::iterator evt ;   
    for( evt = Evts.begin() ; evt != Evts.end() ; evt++ )
    {
        SAFE_CLOSE_HANDLE( evt->event ) ;                                             
    }
}




//-----------------------------------------------------------------------------
// Name: HEvt::~HEvt()
// Thread routine
//-----------------------------------------------------------------------------
DWORD HEvt::ThreadProc()
{
	MSG msg ;
    DWORD	dwResult ;
    bool	active = true ;
	unsigned int nbEvt = Evts.size() ;
	int i ;

	HANDLE* evts = new HANDLE[nbEvt] ;
	for( i=0 ; i<Evts.size() ; i++ ) evts[i] = Evts[i].event ;

    while( active ) 
    {
		dwResult = MsgWaitForMultipleObjects( nbEvt, evts, FALSE, INFINITE, QS_ALLEVENTS );

		if( (WAIT_OBJECT_0 <= dwResult) && (dwResult < WAIT_OBJECT_0 + nbEvt) )
		{
			EvtSoundHappened( dwResult ) ;
		}
		else if( dwResult == (WAIT_OBJECT_0 + nbEvt )  )
		{
			// Terminate the thread process
			while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) 
            { 
                if( msg.message == WM_QUIT ) active = false ;
            }
		}
    }

	SAFE_DELETE_ARRAY( evts ) ;

    return 0;
}




//-----------------------------------------------------------------------------
// Name: HEvt::AddSoundEvt()
// Add a struct EvtStruct to the vector of Events
//-----------------------------------------------------------------------------
void HEvt::AddSoundEvt( unsigned long pos )
{
	EvtStruct evt ;
	evt.pos = pos ;
	//evt.modulopos  = pos % pHSound->m_dwDSBufferSize ;
	evt.event = CreateEvent( NULL, FALSE, FALSE, NULL ) ;

	EVTVECT::iterator it = Evts.end() ;
	while( it != Evts.begin() ) 
	{
		if( pos > (it-1)->pos )  break ;
		it-- ;
	}
	Evts.push_back( evt ) ; 
}





//-----------------------------------------------------------------------------
// Name: HEvt::AddSoundEvt()
// Add a sound reflex in the Direct Sound buffer
//-----------------------------------------------------------------------------
HRESULT HEvt::SetSoundEvt( LPDIRECTSOUNDBUFFER m_pBuffer, DWORD m_dwDSBufferSize, DSBPOSITIONNOTIFY* aPosNotify )
{
	if( !m_pBuffer )  return ERRMSG("SetSoundEvt") ;

	LPDIRECTSOUNDNOTIFY pDSEvt ;
	DSBPOSITIONNOTIFY* aPosEvt ; 
	int nbEvt = Evts.size() ;
	int i ;

	/*EVTVECT::iterator it = Evts.begin() ;
	while( it != Evts.end() ) 
	{
		MMechostr(1,"%d \n", it->modulopos ) ;
		it++ ;
	}*/


	// Create a thread to handle DSound notifications
	Start() ;	

	if( FAILED( m_pBuffer->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSEvt ) ) ) return ERRMSG( "QueryInterface" ) ;

	if( !pHSound->m_streaming )
	{
		aPosEvt = new DSBPOSITIONNOTIFY[ nbEvt ];
		if( aPosEvt == NULL ) return S_FALSE ;
		
		for( i = 0 ; i < nbEvt ; i++ )
		{
			aPosEvt[i].dwOffset     = (Evts[i].pos) % m_dwDSBufferSize ;
			aPosEvt[i].hEventNotify = Evts[i].event ;
		}
	}
	else
	{
		nbEvt += NB_PLAY_NOTIFICATIONS ;
		aPosEvt = new DSBPOSITIONNOTIFY[ nbEvt ];
		for( i = 0 ; i<NB_PLAY_NOTIFICATIONS ; i++ )
		{
			aPosEvt[i].dwOffset		= aPosNotify[i].dwOffset ;
			aPosEvt[i].hEventNotify = aPosNotify[i].hEventNotify ;
		}
		
		for( i = NB_PLAY_NOTIFICATIONS ; i < nbEvt ; i++ )
		{
			/*int b = Evts[i-NB_PLAY_NOTIFICATIONS].pos ;
			int a = (Evts[i-NB_PLAY_NOTIFICATIONS].pos) % m_dwDSBufferSize ;
			_asm { int 3 }*/
			//MMechostr(1,"%d\n", Evts[i].pos ) ;
			aPosEvt[i].dwOffset     = (Evts[i-NB_PLAY_NOTIFICATIONS].pos) % m_dwDSBufferSize ;
			aPosEvt[i].hEventNotify = Evts[i-NB_PLAY_NOTIFICATIONS].event ;
		}
	}

	MMechostr(1,"%d\n",nbEvt ) ;
	if( FAILED( pDSEvt->SetNotificationPositions( nbEvt, aPosEvt ) ) )
	{
		SAFE_DELETE( aPosEvt );
		SAFE_RELEASE( pDSEvt ) ;
		return ERRMSG( "SetNotificationPositions" );
	}

	SAFE_DELETE( aPosEvt );
	SAFE_RELEASE( pDSEvt ) ;

	return S_OK ;
}




//-----------------------------------------------------------------------------
// Name: HEvt::EvtSoundHappened()
// Desc: Filter events from the buffer
//-----------------------------------------------------------------------------
void HEvt::EvtSoundHappened( int numEvt )
{
	DWORD   currentPlayPos ;

	if( FAILED( pHSound->m_pBuffer->GetCurrentPosition( &currentPlayPos, NULL ) ) ) ERRMSG( "GetCurrentPosition" ) ;

	DWORD down = pHSound->m_dwReadOffset + ( ( currentPlayPos < pHSound->m_dwNextWriteOffset) ? pHSound->m_dwDSBufferSize : 0 ) ;
	DWORD up   = down + pHSound->m_dwDSBufferSize ;

	if( down <= Evts[numEvt].pos && Evts[numEvt].pos <= up ) EvtSoundReflex() ;

}



//-----------------------------------------------------------------------------
// Name: HEvt::EvtSoundReflex()
// Desc: When an event of a sound is reached
//-----------------------------------------------------------------------------
void HEvt::EvtSoundReflex()
{
	PostMessage( hwnd, SND_TIME, handler, NULL );	
}