#include "Utility/UI/Manager.h"
#include "Utility/UI/Dialog.h"

#include "Mix/HID/IMouse.h"
#include "Mix/Graphics/Utility/ICanvasRenderer.h"
#include "Mix/Graphics/Utility/IFont.h"

namespace Utility{ namespace UI {

Manager::Manager( void ) :
m_pMouse( NULL ),
m_pCanvasRenderer( NULL ),
m_pFont( NULL ),
m_pActiveDialog( NULL )
{
	m_ColorList[Manager::C_BORDER]                    = Mix::Vector4( 0.4f, 0.4f, 0.5f, 1.0f );
	m_ColorList[Manager::C_BACKGROUND]                = Mix::Vector4( 0.24f, 0.24f, 0.34f, 1.0f );
	m_ColorList[Manager::C_TEXT]                      = Mix::Vector4( 0.8f, 0.8f, 0.9f, 1.0f );
	m_ColorList[Manager::C_SELECTED_BACKGROUND]       = Mix::Vector4( 0.7f, 0.7f, 0.8f, 1.0f );
	m_ColorList[Manager::C_SELECTED_TEXT]             = Mix::Vector4( 0.1f, 0.1f, 0.2f, 1.0f );
	m_ColorList[Manager::C_DLG_CAPTION_BACKGROUND]    = Mix::Vector4( 0.1f, 0.1f, 0.2f, 1.0f );
	m_ColorList[Manager::C_DLG_CAPTION_TEXT]          = Mix::Vector4( 0.7f, 0.7f, 0.8f, 1.0f );
	m_ColorList[Manager::C_CTRL_BACKGROUND]           = Mix::Vector4( 0.3f, 0.3f, 0.4f, 1.0f );
	m_ColorList[Manager::C_CTRL_DARK_BACKGROUND]      = Mix::Vector4( 0.25f, 0.25f, 0.35f, 1.0f );
	m_ColorList[Manager::C_CTRL_DARK_DARK_BACKGROUND] = Mix::Vector4( 0.2f, 0.2f, 0.3f, 1.0f );
}

Manager::~Manager( void )
{
}

void Manager::Initialize( Mix::HID::IMouse* pMouse, Mix::Graphics::Utility::ICanvasRenderer* pCanvasRenderer, Mix::Graphics::Utility::IFont* pFont )
{
	MIX_ASSERT( pMouse != NULL );
	MIX_ASSERT( pCanvasRenderer != NULL );
	MIX_ASSERT( pFont != NULL );

	MIX_ADD_REF( pMouse );
	m_pMouse = pMouse;

	MIX_ADD_REF( pCanvasRenderer );
	m_pCanvasRenderer = pCanvasRenderer;

	MIX_ADD_REF( pFont );
	m_pFont = pFont;
}

void Manager::Dispose( void )
{
	for( Manager::DialogList::iterator it = m_DialogUpdateList.begin(); it != m_DialogUpdateList.end(); ++it )
	{
		( *it )->Dispose();
	}

	m_DialogDrawList.clear();
	m_DialogUpdateList.clear();
	m_DialogMap.clear();

	MIX_RELEASE( m_pCanvasRenderer );
	MIX_RELEASE( m_pFont );
	MIX_RELEASE( m_pMouse );
}

void Manager::Update( void )
{
	if( ( m_pMouse == NULL ) ||
		( m_pCanvasRenderer == NULL ) ||
		( m_pFont == NULL ) )
	{
		return;
	}

	Manager::DialogList::iterator it_update_begin;
	Manager::DialogList::iterator it_update_end;
	Manager::DialogList::iterator it_update;

	Mix::Vector2 mouseVel = m_pMouse->GetVelocity();
	Mix::Vector2 mousePos = m_pMouse->GetPos();

	Manager::DialogList::iterator it_draw_begin;
	Manager::DialogList::iterator it_draw_end;
	Manager::DialogList::iterator it_draw;

	Mix::Vector4 oldColor;
	Mix::Graphics::Utility::IFont* pOldFont;

	UI::Dialog::UPDATE_EVENT_ARGS updateArgs;
	UI::Dialog::DRAW_EVENT_ARGS drawArgs;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	it_update_begin = m_DialogUpdateList.begin();
	it_update_end = m_DialogUpdateList.end();

	updateArgs.pFont = m_pFont;
	updateArgs.pMouse = m_pMouse;

	for( it_update = it_update_begin; it_update != it_update_end; ++it_update )
	{
		( *it_update )->Update( updateArgs );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイアログの活性化処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( m_pMouse->GetButtonState( 0 ) & Mix::HID::PRESSED ) == Mix::HID::PRESSED )
	{
		UI::Dialog* pNextMouseDialog = NULL;

		it_update_begin = m_DialogUpdateList.begin();
		it_update_end = m_DialogUpdateList.end();

		for( it_update = it_update_begin; ( it_update != it_update_end ) && ( pNextMouseDialog == NULL ); ++it_update )
		{
			UI::Dialog* pDialog = ( *it_update );

			if( pDialog->Contains( mousePos ) == True )
			{
				pNextMouseDialog = pDialog;
			}
		}

		if( pNextMouseDialog != NULL )
		{
			if( m_pActiveDialog != NULL )
			{
				m_pActiveDialog->SetActive( False, m_pMouse );
			}

			m_pActiveDialog = pNextMouseDialog;

			if( m_pActiveDialog != NULL )
			{
				m_DialogUpdateList.remove( m_pActiveDialog );
				m_DialogDrawList.remove( m_pActiveDialog );

				m_DialogUpdateList.push_front( m_pActiveDialog );
				m_DialogDrawList.push_back( m_pActiveDialog );

				m_pActiveDialog->SetActive( True, m_pMouse );
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 活性化されているダイアログの処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pActiveDialog != NULL )
	{
		if( ( m_pMouse->GetButtonState( 0 ) & Mix::HID::PRESSED ) == Mix::HID::PRESSED )
		{
			m_pActiveDialog->MouseDown( m_pMouse );
		}
		else if( ( m_pMouse->GetButtonState( 0 ) & Mix::HID::RELEASED ) == Mix::HID::RELEASED )
		{
			m_pActiveDialog->MouseUp( m_pMouse );
		}

		if( MIX_FLOAT_IS_ZERO( mouseVel.GetLength() ) == False )
		{
			m_pActiveDialog->MouseMove( m_pMouse );
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 描画
	////////////////////////////////////////////////////////////////////////////////////////////////////


	it_draw_begin = m_DialogDrawList.begin();
	it_draw_end = m_DialogDrawList.end();

	drawArgs.pCanvasRenderer             = m_pCanvasRenderer;
	drawArgs.borderColor                 = m_ColorList[Manager::C_BORDER];
	drawArgs.backgroundColor             = m_ColorList[Manager::C_BACKGROUND];
	drawArgs.textColor                   = m_ColorList[Manager::C_TEXT];
	drawArgs.selectedBackgroundColor     = m_ColorList[Manager::C_SELECTED_BACKGROUND];
	drawArgs.selectedTextColor           = m_ColorList[Manager::C_SELECTED_TEXT];
	drawArgs.dlgCaptionBackgroundColor   = m_ColorList[Manager::C_DLG_CAPTION_BACKGROUND];
	drawArgs.dlgCaptionTextColor         = m_ColorList[Manager::C_DLG_CAPTION_TEXT];
	drawArgs.ctrlBackgroundColor         = m_ColorList[Manager::C_CTRL_BACKGROUND];
	drawArgs.ctrlDarkBackgroundColor     = m_ColorList[Manager::C_CTRL_DARK_BACKGROUND];
	drawArgs.ctrlDarkDarkBackgroundColor = m_ColorList[Manager::C_CTRL_DARK_DARK_BACKGROUND];

	if( m_pCanvasRenderer->GetFont( &pOldFont ) == False )
	{
		pOldFont = NULL;
	}

	oldColor = m_pCanvasRenderer->GetColor();

	m_pCanvasRenderer->SetFont( m_pFont );
	m_pCanvasRenderer->PushClip();

	for( it_draw = it_draw_begin; it_draw != it_draw_end; ++it_draw )
	{
		UI::Dialog* pDialog = ( *it_draw );

		m_pCanvasRenderer->SetClip( pDialog->GetRectangle() );
		m_pCanvasRenderer->PushClip();

		pDialog->Draw( drawArgs );

		m_pCanvasRenderer->PopClip();
	}

	m_pCanvasRenderer->PopClip();
	m_pCanvasRenderer->SetFont( pOldFont );
	m_pCanvasRenderer->SetColor( oldColor );

	MIX_RELEASE( pOldFont );
}

void Manager::SetColor( Manager::COLOR_TYPE type, const Mix::Vector4& color )
{
	MIX_ASSERT( type < Manager::COLOR_TYPE_MAX );

	m_ColorList[type] = color;
}

const Mix::Vector4& Manager::GetColor( Manager::COLOR_TYPE type ) const
{
	MIX_ASSERT( type < Manager::COLOR_TYPE_MAX );

	return m_ColorList[type];
}

void Manager::AddDialog( UI::Dialog* pDialog )
{
	MIX_ASSERT( pDialog != NULL );

	Manager::DialogMap::iterator it = m_DialogMap.find( pDialog );
	if( it == m_DialogMap.end() )
	{
		m_DialogMap.insert( pDialog );
		m_DialogUpdateList.push_front( pDialog );
		m_DialogDrawList.push_back( pDialog );

		if( m_pActiveDialog != NULL )
		{
			m_pActiveDialog->SetActive( False, m_pMouse );
		}

		m_pActiveDialog = m_DialogUpdateList.front();
	}
}

void Manager::RemoveDialog( UI::Dialog* pDialog )
{
	MIX_ASSERT( pDialog != NULL );

	Manager::DialogMap::iterator it = m_DialogMap.find( pDialog );
	if( it != m_DialogMap.end() )
	{
		m_DialogUpdateList.remove( pDialog );
		m_DialogDrawList.remove( pDialog );
		m_DialogMap.erase( it );

		if( m_pActiveDialog == pDialog )
		{
			if( m_DialogUpdateList.size() > 0 )
			{
				m_pActiveDialog = m_DialogUpdateList.front();
			}
			else
			{
				m_pActiveDialog = NULL;
			}
		}
	}
}

}}
