#include "Utility/Common.h"
#include "Mix/Graphics/Utility/ICanvasRenderer.h"
#include "Mix/Graphics/Utility/IFont.h"

#ifdef _DEBUG
	#include"Mix/Graphics/ITexture.h"
	#include "Mix/Scene/ICamera.h"
#endif //_DEBUG

namespace Utility {

	static const Mix::Vector4 BAR_COLOR_TABLE[] =
	{
		Mix::Vector4( 1.0f, 0.2f, 0.2f ),
		Mix::Vector4( 0.2f, 1.0f, 0.2f ),
		Mix::Vector4( 0.2f, 0.2f, 1.0f ),
		Mix::Vector4( 1.0f, 1.0f, 0.2f ),
		Mix::Vector4( 0.2f, 1.0f, 1.0f ),
		Mix::Vector4( 1.0f, 0.2f, 1.0f ),
		Mix::Vector4( 1.0f, 1.0f, 1.0f ),
	};

	static const UInt32 BAR_COLOR_NUM = sizeof( Utility::BAR_COLOR_TABLE ) / sizeof( Mix::Vector4 );

	const wchar_t* GetRootDirectoryPath( void )
	{
		static wchar_t dirPath[MAX_PATH];
		wchar_t lastChar;
		Int32 lastIndex;
		HANDLE hFind;
		WIN32_FIND_DATA wfd;
		wchar_t searchPath[MAX_PATH];
		Boolean bFind = False;

		GetModuleFileName( NULL, dirPath, MAX_PATH );
		MIX_ASSERT( ::wcslen( dirPath ) < ( MAX_PATH - 3 ) );
		MIX_ASSERT( ( dirPath[::wcslen( dirPath ) - 1] != L'\\' ) && ( dirPath[::wcslen( dirPath ) - 1] != L'/' ) );

		bFind = False;
		for( UIntT i = ( ::wcslen( dirPath ) - 1 ); ( i > 3 ) && ( bFind == False ); --i )
		{
			if( ( dirPath[i] == L'\\' ) || ( dirPath[i] == L'/' ) )
			{
				dirPath[i + 1] = L'\0';
				bFind = True;
			}
		}

		if( bFind == False )
		{
			dirPath[0] = L'\0';
			return dirPath;
		}
		
		lastChar = dirPath[::wcslen( dirPath ) - 1];
		if( ( lastChar != L'\\' ) && ( lastChar != L'/' ) )
		{
			::wcscat_s( dirPath, L"\\" );
		}

		bFind = False;
		while( ( ::wcslen( dirPath ) > 3 ) && ( bFind == False ) )
		{
			lastIndex = static_cast<Int32>( ::wcslen( dirPath ) ) - 1;

			for( Int32 i = lastIndex; i > 0; --i )
			{
				if( ( dirPath[i] == '\\' ) || ( dirPath[i] == '/' ) )
				{
					dirPath[i + 1] = L'\0';
					break;
				}
			}

			lastIndex = static_cast<Int32>( ::wcslen( dirPath ) ) - 1;

			::wsprintf( searchPath, L"%s*.*", dirPath );

			bFind = False;

			hFind = FindFirstFile( searchPath, &wfd );
			if( hFind != INVALID_HANDLE_VALUE )
			{
				do
				{
					if( ( ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == FILE_ATTRIBUTE_DIRECTORY ) &&
						( ::wcscmp( wfd.cFileName, L"Media" ) == 0 ) )
					{
						::wcscat_s( dirPath, wfd.cFileName );
						bFind = True;
					}
				}
				while( ( ::FindNextFile( hFind, &wfd ) == TRUE ) && ( bFind == False ) );

				::FindClose( hFind );
			}

			if( bFind == False )
			{
				dirPath[lastIndex] = L'\0';
			}
		}

		MIX_ASSERT( bFind == True );

		return dirPath;
	}

	const wchar_t* GetPluginsDirectoryPath( void )
	{
		static wchar_t path[MAX_PATH];

#ifdef _WIN64
		::wsprintf( path, L"Plugins\\x64" );
#else //_WIN64
		::wsprintf( path, L"Plugins\\x86" );
#endif /_WIN64

		return path;
	}

	const wchar_t* GetUserDirectoryPath( const wchar_t* pDirPath )
	{
		static wchar_t path[MAX_PATH];

		::wsprintf( path, L"Mix\\Engine\\Examples\\%s", ( pDirPath != NULL )? pDirPath : L"" );

		return path;
	}

	Mix::Quaternion ComputeObjectRotation( const Mix::Quaternion& camRot, const Mix::Vector2& vel, Float32 coiffe )
	{
		Mix::Matrix4x4 camMat = camRot;
		Mix::Vector3 xAxis( 1.0f, 0.0f, 0.0f );
		Mix::Vector3 yAxis( 0.0f, -1.0f, 0.0f );
		Mix::Quaternion objRot;

		xAxis = camMat * xAxis;
		yAxis = camMat * yAxis;

		objRot.SetRotationAxis( yAxis, vel.x * coiffe );
		objRot.RotationAxis( xAxis, vel.y * coiffe );
		objRot.Normalize();

		return objRot;
	}

	void FillBarColor( Utility::BAR_ELEMENT* elements, UInt32 numElement )
	{
		for( UInt32 i = 0; i < numElement; i++ )
		{
			elements[i].color = Utility::BAR_COLOR_TABLE[i % BAR_COLOR_NUM];
		}
	}

	void FillBarColorEx( Utility::BAR_ELEMENT_EX* elements, UInt32 numElement )
	{
		for( UInt32 i = 0; i < numElement; i++ )
		{
			elements[i].color = Utility::BAR_COLOR_TABLE[i % BAR_COLOR_NUM];
		}
	}

	void DrawBar(	Mix::Graphics::Utility::ICanvasRenderer* pCanvasRenderer,
					const Mix::Rectangle& rect,
					const Utility::BAR_ELEMENT* elements,
					UInt32 numElement,
					Float32 totalValue )
	{
		Mix::Vector4 oldColor = pCanvasRenderer->GetColor();

		Float32 baseY = static_cast<Float32>( rect.y );
		Float32 baseWidth = static_cast<Float32>( rect.width );
		Float32 baseHeight = static_cast<Float32>( rect.height );
		Float32 invTotalValue = MIX_FLOAT_RECIPROCAL( totalValue );
		Float32 x = static_cast<Float32>( rect.x );

		for( UInt32 i = 0; i < numElement; i++ )
		{
			const Utility::BAR_ELEMENT& elm = elements[i];

			Float32 width = baseWidth * ( elm.value * invTotalValue );

			pCanvasRenderer->SetColor( elm.color );
			pCanvasRenderer->AddFillRectangle( Mix::RectangleF( x, baseY, width, baseHeight ) );

			x += width;
		}
	}

	void DrawBarEx(	Mix::Graphics::Utility::ICanvasRenderer* pCanvasRenderer,
					const Mix::Rectangle& rect,
					const Utility::BAR_ELEMENT_EX* elements,
					UInt32 numElement,
					Float32 length )
	{
		Mix::Vector4 oldColor = pCanvasRenderer->GetColor();
		Mix::RectangleF oldClip = pCanvasRenderer->GetClip();
		Mix::Graphics::Utility::IFont* pFont = NULL;
		Float32 tox = 0.0f;
		Float32 toy = 0.0f;

		Float32 baseY = static_cast<Float32>( rect.y );
		Float32 baseWidth = static_cast<Float32>( rect.width );
		Float32 baseHeight = static_cast<Float32>( rect.height );
		Float32 invLength = MIX_FLOAT_RECIPROCAL( length );
		Float32 x = static_cast<Float32>( rect.x );

		if( pCanvasRenderer->GetFont( &pFont ) == True )
		{
			tox = toy = baseHeight - static_cast<Float32>( pFont->GetHeight() );
			tox = max( 4.0f, tox );
			MIX_RELEASE( pFont );
		}

		for( UInt32 i = 0; i < numElement; i++ )
		{
			const Utility::BAR_ELEMENT_EX& elm = elements[i];

			Float32 offset = baseWidth * ( elm.start * invLength );
			Float32 width = baseWidth * ( elm.length * invLength );

			Mix::RectangleF blockRect( x + offset, baseY, width, baseHeight );

			pCanvasRenderer->SetClip( blockRect );

			pCanvasRenderer->SetColor( elm.color );
			pCanvasRenderer->AddFillRectangle( blockRect );

			if( elm.pTitle != NULL )
			{
				pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
				pCanvasRenderer->AddString( blockRect.x + tox, blockRect.y + toy, elm.pTitle );
			}
		}

		pCanvasRenderer->SetColor( oldColor );
		pCanvasRenderer->SetClip( oldClip );
	}

	void DrawMouseCursor( Mix::Graphics::Utility::ICanvasRenderer* pCanvasRenderer, const Mix::Vector2& pos, const Mix::Vector4& color )
	{
		Mix::Vector2 points[3];
		Mix::Vector4 borderColor;

		points[0] = Mix::Vector2( pos.x,         pos.y );
		points[1] = Mix::Vector2( pos.x + 16.0f, pos.y + 8.0f );
		points[2] = Mix::Vector2( pos.x + 8.0f,  pos.y + 16.0f );

		borderColor.r = color.r * 0.1f;
		borderColor.g = color.g * 0.1f;
		borderColor.b = color.b * 0.1f;
		borderColor.a = color.a;

		pCanvasRenderer->SetColor( color );
		pCanvasRenderer->AddFillPolygon( points, 3 );

		pCanvasRenderer->SetColor( borderColor );
		pCanvasRenderer->AddPolygon( points, 3 );
	}

#ifdef _DEBUG
	Mix::Rectangle Debug_DrawCameraImage(	Mix::Scene::ICamera* pCamera, UInt32 type, UInt32 index,
											Mix::Graphics::Utility::ICanvasRenderer* pCanvasRenderer, const Mix::Rectangle& rect,
											const Mix::Vector4& borderColor,
											const Mix::Vector4& backColor )
	{
		MIX_ASSERT( pCamera != NULL );

		Mix::Graphics::ITexture* pTex = NULL;

		if( pCamera->Debug_GetImage( type, index, &pTex ) == False )
		{
			return Mix::Rectangle( 0, 0, 0, 0 );
		}

		Mix::Rectangle srcRect( 0, 0, pTex->GetWidth(), pTex->GetHeight() );
		Float32 tw = static_cast<Float32>( srcRect.width );
		Float32 th = static_cast<Float32>( srcRect.height );
		Float32 aspect;

		if( th <= tw )
		{
			aspect = static_cast<Float32>( rect.width ) / tw;
		}
		else
		{
			aspect = static_cast<Float32>( rect.height ) / th;
		}

		Mix::RectangleF dstRect;

		dstRect.width = tw * aspect;
		dstRect.height = th * aspect;
		dstRect.x = static_cast<Float32>( rect.x );
		dstRect.y = static_cast<Float32>( rect.y );
//		dstRect.x = static_cast<Float32>( rect.x ) + ( static_cast<Float32>( rect.width ) - dstRect.width ) * 0.5f;
//		dstRect.y = static_cast<Float32>( rect.y ) + ( static_cast<Float32>( rect.height ) - dstRect.height ) * 0.5f;

		pCanvasRenderer->SetColor( backColor );
		pCanvasRenderer->SetBlendType( Mix::Graphics::BLEND_NORMAL );
		pCanvasRenderer->AddFillRectangle( dstRect );

		pCanvasRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
		pCanvasRenderer->SetBlendType( Mix::Graphics::BLEND_NORMAL );
		pCanvasRenderer->AddImage( pTex, dstRect, srcRect );

		if( MIX_FLOAT_IS_ZERO( borderColor.a ) == False )
		{
			pCanvasRenderer->SetColor( borderColor );
			pCanvasRenderer->SetBlendType( Mix::Graphics::BLEND_NORMAL );
			pCanvasRenderer->AddRectangle( dstRect );
		}

		MIX_RELEASE( pTex );

		return dstRect;
	}
#endif //_DEBUG

}
