#include"CSoundObject.h"

#include"CSound.h"

#include"../auxiliary/Debug/CTrace.h"


namespace Maid
{


//! コンストラクタ
/*!
 */
CSoundObject::CSoundObject()
	:m_IsLoad(false),m_IsFileLoad(false)
{
	GlobalPointer<CSound>::Get()->AddSoundObject(this);
}

//! コピーコンストラクタ
/*!
 */
CSoundObject::CSoundObject( const CSoundObject& rha )
	:m_IsLoad(false),m_IsFileLoad(false)
{
	GlobalPointer<CSound>::Get()->AddSoundObject(this);

	if( rha.m_IsLoad )
	{
		mstring name;
		if( rha.m_IsStream ) { name = rha.m_Stream.GetFileName(); }
		else				 { name = rha.m_Static.GetFileName(); }
		Load( rha.m_Type, name, rha.m_IsStream );
	}
}

//! デストラクタ
/*!
 */
CSoundObject::~CSoundObject()
{
	GlobalPointer<CSound>::Get()->DelSoundObject(this);
	Delete();
}


//! ファイルから読み込む
/*!
	@param	type		[i ]	オブジェクトのグループ
	@param	FileName	[i ]	読み込むファイル名
	@param	IsStream	[i ]	ストリーム再生するか？(true でストリーム)
 */
void CSoundObject::Load( TYPE type, const mstring& FileName, bool IsStream )
{
//	MAID_TRACE( MAIDTEXT("CSoundObject::Load") << this <<  MAIDTEXT("  ") << FileName );
	Delete();

	if( IsStream )	{ m_Stream.Load( FileName ); }
	else			{ m_Static.Load( FileName ); }

	m_Type     = type;
	m_IsStream = IsStream;
	m_IsLoad   = true;
	m_Volume = VOLUME_MAX;
	m_IsLoopPlay = false;
	m_IsFileLoad = false;
	m_IsPrevPlay = false;
}

CSoundObject& CSoundObject::operator = ( const CSoundObject& rha )
{
	Delete();

	if( rha.m_IsLoad )
	{
		mstring name;
		if( rha.m_IsStream ) { name = rha.m_Stream.GetFileName(); }
		else				 { name = rha.m_Static.GetFileName(); }
		Load( rha.m_Type, name, rha.m_IsStream );
	}

	return *this;
}

void CSoundObject::Delete()
{
	if( !m_IsLoad ) { return ; }

	if( m_IsStream )	{ m_Stream.Delete(); }
	else				{ m_Static.Delete(); }

	m_IsLoad = false;
}

//! バッファの先頭から再生する
/*!
	@param	count		[i ]	再生回数(デフォルトで１)
\n								ただし、継ぎ目なしの連続で再生されることはないので注意
 */
void CSoundObject::Play( int count )
{
	if( !m_IsLoad ) { return; }
	if( IsNowLoading() ) { return ; }
	SPSOUNDOBJECTCORE pObj = GetObject();

	pObj->SetPlayCount( count );
	pObj->SetPosition(0);
	pObj->SetVolume(CalcVolume(),0);

	pObj->Play();

	m_IsPrevPlay = true;
	m_IsLoopPlay = count==-1;
}


//! バッファを停止させる
/*!
 */
void CSoundObject::Stop()
{
	if( !m_IsLoad ) { return; }
	if( IsNowLoading() ) { return ; }
	SPSOUNDOBJECTCORE pObj = GetObject();

	pObj->Stop();
	m_IsLoopPlay = false;
	m_IsPrevPlay = false;
}

void CSoundObject::Pause()
{
	if( !m_IsLoad ) { return; }
	if( IsNowLoading() ) { return ; }
	SPSOUNDOBJECTCORE pObj = GetObject();

	pObj->Stop();
}


//! 再生途中のところから再生する
/*!
 */
void CSoundObject::Resume()
{
	if( !m_IsLoad ) { return; }
	if( IsNowLoading() ) { return ; }
	if( !m_IsPrevPlay ) { return ; }
	SPSOUNDOBJECTCORE pObj = GetObject();
	pObj->Play();
}


//! 再生位置の変更
/*!
	@param	time		[i ]	設定する位置（単位はミリ秒）
 */
void CSoundObject::SetPosition( int time )
{
	if( !m_IsLoad ) { return; }
	if( IsNowLoading() ) { return ; }
	SPSOUNDOBJECTCORE pObj = GetObject();
	pObj->SetPosition(time);
}

//! ボリュームの変更
/*!
	@param	vol		[i ]	設定するボリューム( 最小0 - 10000 最大)
	@param	time	[i ]	設定までにかかる時間（単位はミリ秒）
 */
void CSoundObject::SetVolume( int vol, int time )
{
	if( !m_IsLoad ) { return ; }
	if( vol < VOLUME_MIN ) { vol = VOLUME_MIN; }
	if( VOLUME_MAX < vol ) { vol = VOLUME_MAX; }

	m_Volume = vol;
	UpdateVolume( time );
}

//! 再生が末端まで進んだときに戻ってくる位置の設定
/*!
	@param	time	[i ]	設定する位置（単位はミリ秒）
 */
void CSoundObject::SetLoopPosition( int time )
{
	if( !m_IsLoad ) { return; }
	if( IsNowLoading() ) { return ; }
	SPSOUNDOBJECTCORE pObj = GetObject();
	pObj->SetLoopPosition(time);
}

void CSoundObject::FadeIn( int time )
{
	SetVolume( VOLUME_MAX, time );
}

void CSoundObject::FadeOut( int time )
{
	SetVolume( VOLUME_MIN, time );
}

//! 再生中か？
/*!
	@return	再生中なら true
 */
bool CSoundObject::IsPlay()
{
	if( !m_IsLoad ) { return false; }
	if( IsNowLoading() ) { return false; }

	SPSOUNDOBJECTCORE pObj = GetObject();

	return pObj->IsPlay();
}


//! 読み込み中か？
/*!
	@return	読み込み中なら true
 */
bool CSoundObject::IsNowLoading()
{
	bool ret = _IsNowLoading();

	//	ファイルの読み込みが完了した瞬間
	if( !m_IsFileLoad && !ret )
	{
		UpdateVolume(0);
		m_IsFileLoad = true;
	}

	return ret;
}

bool CSoundObject::_IsNowLoading()
{
	if( !m_IsLoad ) { return false; }
	bool ret;

	if( m_IsStream )	{ ret = m_Stream.IsNowLoading(); }
	else				{ ret = m_Static.IsNowLoading(); }

	return ret;
}

int CSoundObject::GetPosition()
{
	if( !m_IsLoad ) { return 0; }

	SPSOUNDOBJECTCORE pObj = GetObject();

	return pObj->GetPosition();
}

int CSoundObject::GetVolume()
{
	return m_Volume;
}


void CSoundObject::UpdateVolume( int time )
{
//	MAID_TRACE( MAIDTEXT("CSoundObject::UpdateVolume0") << this <<  MAIDTEXT("  ") << time);
	if( !m_IsLoad ) { return ; }
	if( _IsNowLoading() ) { return ; }

	SPSOUNDOBJECTCORE pObj = GetObject();

	const bool type_mute = GlobalPointer<CSound>::Get()->IsMute( m_Type );
	const bool global_mute = GlobalPointer<CSound>::Get()->GetGlobalMute();

	if( type_mute || global_mute )
	{
		pObj->SetVolume( 0, 0 );
		return ;
	}

	pObj->SetVolume( CalcVolume(), time );
}

int  CSoundObject::CalcVolume()
{
	const bool type_mute = GlobalPointer<CSound>::Get()->IsMute( m_Type );
	const bool global_mute = GlobalPointer<CSound>::Get()->GetGlobalMute();

	if( type_mute || global_mute )
	{
		return 0;
	}

	const int obj = m_Volume;
	const int type  = GlobalPointer<CSound>::Get()->GetVolume( m_Type );
	const int global = GlobalPointer<CSound>::Get()->GetGlobalVolume();

	const int vol = obj * type / 10000 * global / 10000;

	return vol;
}



SPSOUNDOBJECTCORE	CSoundObject::GetObject()
{
	MAID_ASSERT( !m_IsLoad, "まだ読み込んでいません" );
	SPSOUNDOBJECTCORE pObj;

	if( m_IsStream )	{ pObj = m_Stream.GetSoundObjectCore(); }
	else				{ pObj = m_Static.GetSoundObjectCore(); }

	return pObj;
}

bool CSoundObject::IsLoopPlay()
{
	return m_IsLoopPlay;
}

bool CSoundObject::IsStream()
{
	return m_IsStream;
}


}

