// IdentifyQueue.cpp : Implementation of CIdentifyQueue

#include "stdafx.h"
#include "IdentifyQueue.h"

// Timeout in millisec to re-request ID
#define TIMEOUT				700



enum AcMessages
{
	msgGameEvent			= 0xF7B0,
	msgUnknown				= 0
};

enum AcGameEvents
{
	gevIDItem				= 0x00C9,
	gevUnknown				= 0
};

// CIdentifyQueue
HRESULT			CIdentifyQueue::onInitialize()
{
	if( m_pService->get_Decal( &m_pDecal ) == S_OK )
	{
		if( m_pDecal->get_Hooks( &m_pHooks ) == S_OK )
		{
			m_pHooks->SetIDFilter( this );

			long lRequestIDMemloc;
			if( m_pHooks->QueryMemLoc( _bstr_t( "ItemEventAppraise" ), &lRequestIDMemloc ) == S_OK )
			{
				if( lRequestIDMemloc != 0 )
				{
					m_pfRequestFunc = reinterpret_cast< RequestPtr >( lRequestIDMemloc );
					return S_OK;
				}
			}
		}

	}

	m_pfRequestFunc = NULL;
	m_pService.Release();
	return E_FAIL;
}

HRESULT			CIdentifyQueue::onTerminate()
{
	m_pDecal.Release();
	m_pHooks.Release();

	m_pfRequestFunc = NULL;

	return S_OK;
}

STDMETHODIMP	CIdentifyQueue::DispatchServer( IMessage2 *pMsg )
{
	long lType;
	pMsg->get_Type( &lType );

	CComPtr< IMessageIterator > pMembers;
	pMsg->get_Begin( &pMembers );

	switch( lType )
	{
		case msgGameEvent:			MsgGameEvent( pMembers );				break;
	}

	if( m_Queue.empty() )
		return S_OK;

	// Check for timeout...
	if( m_bWaiting )
	{
		if( abs( m_Queue[0]->lTime - timeGetTime() ) > TIMEOUT )
		{
			if( ++m_lAttempts >= 3 )
			{
				m_lAttempts = 0;
				m_Queue.erase( m_Queue.begin() );
				m_bWaiting = false;
				Request();
			}

			else
			{
				m_Queue[0]->lTime = timeGetTime();
				m_bWaiting = false;
				Request();
			}
		}
	}

	return S_OK;
}

STDMETHODIMP	CIdentifyQueue::AddToQueue( long lObjectID )
{
	if( lObjectID == 0 )
		return S_OK;

	if( !m_Queue.empty() )
	{
		for( IDContainer::iterator pDeque = m_Queue.begin(); pDeque != m_Queue.end(); ++pDeque )
		{
			if( (*pDeque)->lObjectID == lObjectID )
				return S_OK;
		}
	}

	IDStruct *QueueObj = new IDStruct();
	QueueObj->lObjectID = lObjectID;
	QueueObj->lTime = timeGetTime();
	m_Queue.push_back( QueueObj );

	if( !m_bWaiting )
		Request();

	return S_OK;
}

STDMETHODIMP	CIdentifyQueue::ShortcircuitID( long lObjectID )
{
	m_lLastManualAttempt = lObjectID;

	if( !m_Queue.empty() )
	{
		for( IDContainer::iterator pDeque = m_Queue.begin(); pDeque != m_Queue.end(); ++pDeque )
		{
			if ( (*pDeque)->lObjectID == lObjectID )
			{
				m_Queue.erase( pDeque );
				break;
			}
		}
	}    

	IDStruct *QueueObj = new IDStruct();
	QueueObj->lObjectID = lObjectID;
	QueueObj->lTime = timeGetTime();
	m_Queue.push_front( QueueObj );

	if( !m_bWaiting )
		Request();

	return S_OK;
}

void			CIdentifyQueue::MsgGameEvent( IMessageIterator *pMembers ) 
{
	long lEvent;
	pMembers->get_NextInt( _bstr_t( "event" ), &lEvent );

	switch( lEvent ) 
	{
		case gevIDItem:				MsgIDItem( pMembers );				break;
	}
}

void			CIdentifyQueue::MsgIDItem( IMessageIterator *pMembers ) 
{
	if( m_Queue.empty() )
		return;

	long lObjectID;
	pMembers->get_NextInt( _bstr_t( "object" ), &lObjectID );


	for( IDContainer::iterator pDeque = m_Queue.begin(); pDeque != m_Queue.end(); pDeque++ )
	{
		if ( (*pDeque)->lObjectID == lObjectID )
		{
			m_lAttempts = 0;
			pDeque = m_Queue.erase( pDeque );
			break;
		}
	}

	if( m_bWaiting )
	{
		m_bWaiting = false;
		Request();
	}
}

void			CIdentifyQueue::Request()
{
	if( !m_bWaiting )
	{
		if( m_Queue.empty() )
		{
			m_pfRequestFunc( 0 );
			return;
		}

		IDStruct *pQueueBegin = *m_Queue.begin();

		m_pfRequestFunc( pQueueBegin->lObjectID );
		m_bWaiting = true;

		if( pQueueBegin->lObjectID == 0 )
		{
			m_bWaiting = false;
			m_Queue.erase( m_Queue.begin() );
			Request();
		}
	}
}
