#include "Mix/Tool/Win32/Core/Graphics/DrawObject.h"

#include <shlwapi.h>

#include "Mix/Tool/Win32/Core/Graphics/Manager.h"
#include "Mix/Tool/Win32/Core/Graphics/Scene.h"
#include "Mix/Tool/Win32/Core/Graphics/Camera.h"
#include "Mix/Tool/Win32/Core/Graphics/Material.h"
#include "Mix/Tool/Win32/Core/Graphics/MaterialSlot.h"

namespace Mix{ namespace Tool{ namespace Win32{ namespace Graphics{

const unsigned int DrawObject::MAX_SLOTNAME_NUMBER = 999;

DrawObject::DrawObject( void )
{
/*	m_Scaling = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
	m_Rotation = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
	m_Translation = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
*/
	m_DisableCount = 0;

	::D3DXMatrixIdentity( &m_WorldMatrix );

	m_RotationLightVolume.pos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
	m_RotationLightVolume.radius = 100.0f;
}

DrawObject::~DrawObject( void )
{
	Mix::Tool::Win32::Graphics::Scene* pScene = GetScenePtr();

	if( pScene != NULL )
	{
		pScene->SetDrawObject( NULL );
	}

	for( std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it = m_MaterialSlotList.begin(); it != m_MaterialSlotList.end(); ++it )
	{
		( *it )->Destroy();
		MIX_DELETE( ( *it ) );
	}
}
/*
void DrawObject::SetScaling( const D3DXVECTOR3& scaling )
{
	m_Scaling = scaling;

	UpdateWorldMatrix();
}

const D3DXVECTOR3& DrawObject::GetScaling( void ) const
{
	return m_Scaling;
}

void DrawObject::SetRotation( const D3DXVECTOR3& rot )
{
	m_Rotation = rot;

	UpdateWorldMatrix();
}

const D3DXVECTOR3& DrawObject::GetRotation( void ) const
{
	return m_Rotation;
}

void DrawObject::SetTranslation( const D3DXVECTOR3& translation )
{
	m_Translation = translation;

	UpdateWorldMatrix();
}

const D3DXVECTOR3& DrawObject::GetTranslation( void ) const
{
	return m_Translation;
}
*/

int DrawObject::Enable( void )
{
	int ret = m_DisableCount;

	m_DisableCount--;

	return ret;
}

int DrawObject::Disable( void )
{
	int ret = m_DisableCount;

	m_DisableCount++;

	return m_DisableCount;
}

int DrawObject::GetDisableCount( void ) const
{
	return m_DisableCount;
}

const D3DXMATRIX& DrawObject::GetWorldMatrix( void ) const
{
	return m_WorldMatrix;
}

void DrawObject::SetWorldMatrix( const D3DXMATRIX& worldMat )
{
	m_WorldMatrix = worldMat;
}

void DrawObject::ResetWorldMatrix( void )
{
	D3DXMatrixIdentity( &m_WorldMatrix );
}

const Mix::Tool::Win32::Geometry::SPHERE& DrawObject::GetRotationLightVolume( void ) const
{
	return m_RotationLightVolume;
}

unsigned int DrawObject::GetMaterialSlotCount( void ) const
{
	return m_MaterialSlotList.size();
}

unsigned int DrawObject::GetMaterialSlotIndex( const char* pName ) const
{
	std::wstring temp;

	AnsiToWide( pName, temp );

	return GetMaterialSlotIndex( temp.c_str() );
}

unsigned int DrawObject::GetMaterialSlotIndex( const wchar_t* pName ) const
{
	unsigned int index = 0;

	for( std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::const_iterator it = m_MaterialSlotList.begin(); it != m_MaterialSlotList.end(); ++it )
	{
		if( ::wcscmp( ( *it )->GetName(), pName ) == 0 )
		{
			break;
		}
		else
		{
			index++;
		}
	}

	return index;
}

Mix::Tool::Win32::Graphics::MaterialSlot* DrawObject::GetMaterialSlotByIndex( unsigned int index )
{
	if( m_MaterialSlotList.size() <= index )
	{
		return NULL;
	}

	return m_MaterialSlotList[index];
}

Mix::Tool::Win32::Graphics::MaterialSlot* DrawObject::GetMaterialSlotByName( const char* pName )
{
	MIX_ASSERT( pName != NULL );
	MIX_ASSERT( ::strlen( pName ) != 0 );

	std::wstring temp;

	AnsiToWide( pName, temp );

	return GetMaterialSlotByName( temp.c_str() );
}

Mix::Tool::Win32::Graphics::MaterialSlot* DrawObject::GetMaterialSlotByName( const wchar_t* pName )
{
	MIX_ASSERT( pName != NULL );
	MIX_ASSERT( ::wcslen( pName ) != 0 );

	for( std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it = m_MaterialSlotList.begin(); it != m_MaterialSlotList.end(); ++it )
	{
		if( ::wcscmp( ( *it )->GetName(), pName ) == 0 )
		{
			return ( *it );
		}
	}

	return NULL;
}

Mix::Tool::Win32::Graphics::Material* DrawObject::AddMaterialSlot( const char* pName )
{
	MIX_ASSERT( pName != NULL );
	MIX_ASSERT( ::strlen( pName ) != 0 );

	std::wstring temp;

	AnsiToWide( pName, temp );

	return AddMaterialSlot( temp.c_str() );
}

Mix::Tool::Win32::Graphics::Material* DrawObject::AddMaterialSlot( const wchar_t* pName )
{
	MIX_ASSERT( pName != NULL );
	MIX_ASSERT( ::wcslen( pName ) != 0 );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 同一名のマテリアルスロットが存在しているかどうかをチェック
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it = m_MaterialSlotList.begin(); it != m_MaterialSlotList.end(); ++it )
	{
		if( ::wcscmp( ( *it )->GetName(), pName ) == 0 )
		{
			return NULL;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアルスロットを追加
	////////////////////////////////////////////////////////////////////////////////////////////////////

	unsigned int index = m_MaterialSlotList.size();
	Mix::Tool::Win32::Graphics::MaterialSlot* pMaterialSlot = new Mix::Tool::Win32::Graphics::MaterialSlot( this, index, pName );

	if( pMaterialSlot != NULL )
	{
		m_MaterialSlotList.push_back( pMaterialSlot );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアルを追加
	////////////////////////////////////////////////////////////////////////////////////////////////////

	return pMaterialSlot->Add();
}

Mix::Tool::Win32::Graphics::Material* DrawObject::GetMaterial( unsigned int index ) const
{
	if( m_MaterialSlotList.size() <= index )
	{
		return NULL;
	}

	return m_MaterialSlotList[index]->GetActive();
}

bool DrawObject::SaveMaterials( void )
{
	std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it_begin = m_MaterialSlotList.begin();
	std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it_end = m_MaterialSlotList.end();
	std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it;

	for( it = it_begin; it != it_end; ++it )
	{
		Mix::Tool::Win32::Graphics::MaterialSlot* pMaterialSlot = ( *it );

		if( pMaterialSlot->SaveFile() == false )
		{
			return false;
		}
	}

	return true;
}

void DrawObject::UpdateAllMaterialSlot( void )
{
	for( std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it = m_MaterialSlotList.begin(); it != m_MaterialSlotList.end(); ++it )
	{
		Mix::Tool::Win32::Graphics::MaterialSlot* pMaterialSlot = ( *it );

		for( unsigned int i = 0; i < pMaterialSlot->GetCount(); i++ )
		{
			Mix::Tool::Win32::Graphics::Material* pMaterial = pMaterialSlot->GetByIndex( i );

			pMaterial->SetAutoUpdate( true );

			pMaterial->LoadDiffuseTexture();
			pMaterial->LoadSpecularTexture();
			pMaterial->LoadEmissiveTexture();
			pMaterial->LoadBumpTexture();

			pMaterial->SetAutoUpdate( false );
		}

		pMaterialSlot->Update( NULL, false );
	}
}

bool DrawObject::WriteAllMaterials( const wchar_t* pFilePath, Mix::Tool::Win32::File::OutputStream& output )
{
	std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it_begin = m_MaterialSlotList.begin();
	std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it_end = m_MaterialSlotList.end();
	std::vector<Mix::Tool::Win32::Graphics::MaterialSlot*>::iterator it;

	for( it = it_begin; it != it_end; ++it )
	{
		Mix::Tool::Win32::Graphics::MaterialSlot* pMaterialSlot = ( *it );

		if( pMaterialSlot->WriteDefault( pFilePath, output ) == false )
		{
			return false;
		}
	}

	return true;
}

void DrawObject::SetRotationLightVolume( const Mix::Tool::Win32::Geometry::SPHERE& sphere )
{
	m_RotationLightVolume = sphere;
}

bool DrawObject::CreateMaterialSlotName( Mix::Tool::Win32::Graphics::MaterialSlot* pMaterialSlot, const wchar_t* pRequestName, std::wstring& name )
{
	return CreateUniqueName( pMaterialSlot, m_MaterialSlotList.begin(), m_MaterialSlotList.end(), pRequestName, name );
}
/*
void DrawObject::UpdateWorldMatrix( void )
{
	D3DXMATRIX ms;
	D3DXMATRIX mrx;
	D3DXMATRIX mry;
	D3DXMATRIX mrz;
	D3DXMATRIX mt;

	::D3DXMatrixScaling( &ms, m_Scaling.x, m_Scaling.y, m_Scaling.z );

	::D3DXMatrixRotationX( &mrx, D3DXToRadian( m_Rotation.x ) );
	::D3DXMatrixRotationY( &mry, D3DXToRadian( m_Rotation.y ) );
	::D3DXMatrixRotationZ( &mrz, D3DXToRadian( m_Rotation.z ) );

	::D3DXMatrixTranslation( &mt, m_Translation.x, m_Translation.y, m_Translation.z );

	m_WorldMatrix = ms * mrx * mry * mrz * mt;
}
*/

Mix::Tool::Win32::Object::TYPE DrawObject::GetType( void ) const
{
	return Mix::Tool::Win32::Object::GRAPHICS__DRAW_OBJECT;
}

bool DrawObject::QueryType( Mix::Tool::Win32::Object::TYPE type ) const
{
	if( type == Mix::Tool::Win32::Object::GRAPHICS__DRAW_OBJECT )
	{
		return true;
	}

	return SceneObject::QueryType( type );
}

}}}}
