#include "Mix/Private/Sound/BaseMediator.h"

namespace Mix{ namespace Sound{

////////////////////////////////////////////////////////////////////////////////////////////////////
// BaseMediator::EVENT_QUEUE
////////////////////////////////////////////////////////////////////////////////////////////////////

BaseMediator::EVENT_QUEUE::EVENT_QUEUE( void ) :
emptySema( BaseMediator::MAX_EVENT_QUEUE, BaseMediator::MAX_EVENT_QUEUE ),
countSema( 0, BaseMediator::MAX_EVENT_QUEUE ),
read( 0 ),
write( 0 )
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// BaseMediator
// 共通
////////////////////////////////////////////////////////////////////////////////////////////////////

BaseMediator::BaseMediator( void ) :
m_hTerm( INVALID_HANDLE_VALUE )
{
	m_hTerm = ::CreateEvent( NULL, TRUE, FALSE, NULL );
	MIX_ASSERT( m_hTerm != NULL );
}

BaseMediator::~BaseMediator( void )
{
	if( m_hTerm != NULL )
	{
		::CloseHandle( m_hTerm );
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// BaseMediator
// カレントスレッドから呼び出されるメソッド
////////////////////////////////////////////////////////////////////////////////////////////////////

void BaseMediator::PushEvent( Int16 type, Int16 opt )
{
	m_EventQueue.emptySema.Reduce();
	m_EventQueue.sync.Enter();

	m_EventQueue.data[m_EventQueue.write] = ( ( type << 16 ) | opt );

	m_EventQueue.write++;
	if( m_EventQueue.write == BaseMediator::MAX_EVENT_QUEUE )
	{
		m_EventQueue.write = 0;
	}

	m_EventQueue.sync.Leave();
	m_EventQueue.countSema.Increase();
}

Boolean BaseMediator::IsPlaying( void )
{
	return ( m_State.Get() == BaseMediator::STATE_PLAY );
}

Boolean BaseMediator::Join( UInt32 timeOut )
{
	return ( ::WaitForSingleObject( m_hTerm, timeOut ) == WAIT_OBJECT_0 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// BaseMediator
// サウンドスレッドから呼び出されるメソッド
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean BaseMediator::PopEvent( Int16& type, Int16& opt )
{
	if( m_EventQueue.countSema.Reduce( 0 ) == False )
	{
		return False;
	}

	m_EventQueue.sync.Enter();

	Int32 temp = m_EventQueue.data[m_EventQueue.read];

	type = static_cast<Int16>( ( temp >> 16 ) & 0x0000FFFF );
	opt = static_cast<Int16>( temp & 0x0000FFFF );

	m_EventQueue.read++;
	if( m_EventQueue.read == BaseMediator::MAX_EVENT_QUEUE )
	{
		m_EventQueue.read = 0;
	}

	m_EventQueue.sync.Leave();
	m_EventQueue.emptySema.Increase();

	return True;
}

void BaseMediator::SetState( Long32 value )
{
	m_State.Set( value );
}

void BaseMediator::Terminated( void )
{
	::SetEvent( m_hTerm );
}

}}
