#include "Mix/Private/HID/Keyboard.h"

using namespace Mix::HID;

Keyboard* Keyboard::CreateInstance( HWND hWnd )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_GENERAL, Keyboard, hWnd );
}

Keyboard::Keyboard( HWND hWnd ) :
m_hWnd( hWnd ),
m_bEnableUpdate( True )
{
	m_VKConvTable[VK_F1]		= KEY_F1;
	m_VKConvTable[VK_F2]		= KEY_F2;
	m_VKConvTable[VK_F3]		= KEY_F3;
	m_VKConvTable[VK_F4]		= KEY_F4;
	m_VKConvTable[VK_F5]		= KEY_F5;
	m_VKConvTable[VK_F6]		= KEY_F6;
	m_VKConvTable[VK_F7]		= KEY_F7;
	m_VKConvTable[VK_F8]		= KEY_F8;
	m_VKConvTable[VK_F9]		= KEY_F9;
	m_VKConvTable[VK_F10]		= KEY_F10;
	m_VKConvTable[VK_F11]		= KEY_F11;
	m_VKConvTable[VK_F12]		= KEY_F12;

	m_VKConvTable[0x30]			= KEY_0;
	m_VKConvTable[0x31]			= KEY_1;
	m_VKConvTable[0x32]			= KEY_2;
	m_VKConvTable[0x33]			= KEY_3;
	m_VKConvTable[0x34]			= KEY_4;
	m_VKConvTable[0x35]			= KEY_5;
	m_VKConvTable[0x36]			= KEY_6;
	m_VKConvTable[0x37]			= KEY_7;
	m_VKConvTable[0x38]			= KEY_8;
	m_VKConvTable[0x39]			= KEY_9;

	m_VKConvTable[VK_NUMPAD0]	= KEY_NP0;
	m_VKConvTable[VK_NUMPAD1]	= KEY_NP1;
	m_VKConvTable[VK_NUMPAD2]	= KEY_NP2;
	m_VKConvTable[VK_NUMPAD3]	= KEY_NP3;
	m_VKConvTable[VK_NUMPAD4]	= KEY_NP4;
	m_VKConvTable[VK_NUMPAD5]	= KEY_NP5;
	m_VKConvTable[VK_NUMPAD6]	= KEY_NP6;
	m_VKConvTable[VK_NUMPAD7]	= KEY_NP7;
	m_VKConvTable[VK_NUMPAD8]	= KEY_NP8;
	m_VKConvTable[VK_NUMPAD9]	= KEY_NP9;

	m_VKConvTable[0x41]			= KEY_A;
	m_VKConvTable[0x42]			= KEY_B;
	m_VKConvTable[0x43]			= KEY_C;
	m_VKConvTable[0x44]			= KEY_D;
	m_VKConvTable[0x45]			= KEY_E;
	m_VKConvTable[0x46]			= KEY_F;
	m_VKConvTable[0x47]			= KEY_G;
	m_VKConvTable[0x48]			= KEY_H;
	m_VKConvTable[0x49]			= KEY_I;
	m_VKConvTable[0x4A]			= KEY_J;
	m_VKConvTable[0x4B]			= KEY_K;
	m_VKConvTable[0x4C]			= KEY_L;
	m_VKConvTable[0x4D]			= KEY_M;
	m_VKConvTable[0x4E]			= KEY_N;
	m_VKConvTable[0x4F]			= KEY_O;
	m_VKConvTable[0x50]			= KEY_P;
	m_VKConvTable[0x51]			= KEY_Q;
	m_VKConvTable[0x52]			= KEY_R;
	m_VKConvTable[0x53]			= KEY_S;
	m_VKConvTable[0x54]			= KEY_T;
	m_VKConvTable[0x55]			= KEY_U;
	m_VKConvTable[0x56]			= KEY_V;
	m_VKConvTable[0x57]			= KEY_W;
	m_VKConvTable[0x58]			= KEY_X;
	m_VKConvTable[0x59]			= KEY_Y;
	m_VKConvTable[0x5A]			= KEY_Z;

	m_VKConvTable[VK_UP]		= KEY_UP;
	m_VKConvTable[VK_DOWN]		= KEY_DOWN;
	m_VKConvTable[VK_LEFT]		= KEY_LEFT;
	m_VKConvTable[VK_RIGHT]		= KEY_RIGHT;

	m_VKConvTable[VK_ESCAPE]	= KEY_ESCAPE;
	m_VKConvTable[VK_TAB]		= KEY_TAB;
	m_VKConvTable[VK_BACK]		= KEY_BACKSPACE;
	m_VKConvTable[VK_DELETE]	= KEY_DELETE;
	m_VKConvTable[VK_SPACE]		= KEY_SPACE;
	m_VKConvTable[VK_RETURN]	= KEY_RETURN;
	m_VKConvTable[VK_SHIFT]		= KEY_SHIFT;
	m_VKConvTable[VK_LSHIFT]	= KEY_LSHIFT;
	m_VKConvTable[VK_RSHIFT]	= KEY_RSHIFT;
	m_VKConvTable[VK_CONTROL]	= KEY_CTRL;
	m_VKConvTable[VK_LCONTROL]	= KEY_LCTRL;
	m_VKConvTable[VK_RCONTROL]	= KEY_RCTRL;
	m_VKConvTable[VK_MENU]		= KEY_ALT;
	m_VKConvTable[VK_LMENU]		= KEY_LALT;
	m_VKConvTable[VK_RMENU]		= KEY_RALT;

	::ZeroMemory( m_KeyStateArray, sizeof( m_KeyStateArray ) );

	Mix::Memory::Zero( m_KeyInfoList, sizeof( m_KeyInfoList ) );
	Mix::Memory::Zero( m_UpdateKeyList, sizeof( m_UpdateKeyList ) );
	m_UpdateKeyCount = 0;

	Mix::Memory::Zero( m_LastUpdateKeyList, sizeof( m_UpdateKeyList ) );
	m_LastUpdateKeyCount = 0;
}

Keyboard::~Keyboard( void )
{
}

void Keyboard::ProcessInput( const RAWINPUT* pInput )
{
	const RAWKEYBOARD* pk = &( pInput->data.keyboard );

	if( pk->Message == WM_KEYDOWN )
	{
		MIX_ASSERT( pk->VKey < 256 );

		UInt8 key = m_VKConvTable[pk->VKey];
		
		if( Mix::HID::KEY_MAX > key )
		{
			if( m_KeyInfoList[key] == 0x00 )
			{
				MIX_ASSERT( Mix::HID::KEY_MAX > m_UpdateKeyCount );
				m_UpdateKeyList[m_UpdateKeyCount++] = key;
			}

			m_KeyInfoList[key] = 0xFF;
		}
	}
	else if( pk->Message == WM_KEYUP )
	{
		MIX_ASSERT( pk->VKey < 256 );

		UInt8 key = m_VKConvTable[pk->VKey];

		if( Mix::HID::KEY_MAX > key )
		{
			if( m_KeyInfoList[key] == 0xFF )
			{
				MIX_ASSERT( Mix::HID::KEY_MAX > m_UpdateKeyCount );
				m_UpdateKeyList[m_UpdateKeyCount++] = key;
			}
		
			m_KeyInfoList[key] = 0x00;
		}
	}
}

void Keyboard::MessageProc( UInt32 msg, WPARAM wParam, LPARAM lParam )
{
	if( msg == WM_INITMENU )
	{
		//メニュー選択を開始した
		m_bEnableUpdate = False;
	}
	else if( msg == WM_EXITMENULOOP )
	{
		//メニュー選択を終了した
		m_bEnableUpdate = True;
	}
	else if( msg == WM_ACTIVATEAPP )
	{
		//ウィンドウが非アクティブになった場合は、キーを全てリリース状態にする
		if( wParam == FALSE )
		{
			for( UInt8 i = 0; i < Mix::HID::KEY_MAX; i++ )
			{
				if( m_KeyInfoList[i] == 0xFF )
				{
					MIX_ASSERT( Mix::HID::KEY_MAX > m_UpdateKeyCount );
					m_UpdateKeyList[m_UpdateKeyCount++] = i;
					m_KeyInfoList[i] = 0x00;
				}
			}
		}
	}
}

void Keyboard::Update( void )
{
	UInt8 i;
	UInt16 key;
	UInt16 state;

	for( i = 0; i < m_LastUpdateKeyCount; i++ )
	{
		key = ( ( m_LastUpdateKeyList[i] >> 8 ) & 0x00FF );
		state = ( m_LastUpdateKeyList[i] & 0x00FF );

		if( state == 0x00 )
		{
			MIX_RESETBIT( m_KeyStateArray[key], Mix::HID::RELEASED );
//			TraceLine( _T( "ClearReleased : %d" ), key );
		}
		else
		{
			MIX_RESETBIT( m_KeyStateArray[key], Mix::HID::PRESSED );
//			TraceLine( _T( "ClearPressed : %d" ), key );
		}
	}

	for( i = 0; i < m_UpdateKeyCount; i++ )
	{
		key = m_UpdateKeyList[i];
		state = m_KeyInfoList[key];

		if( state == 0x00 )
		{
			//アップ
			if( MIX_TESTBIT( m_KeyStateArray[key], Mix::HID::DOWN ) == Mix::HID::DOWN )
			{
				MIX_SETBIT( m_KeyStateArray[key], Mix::HID::RELEASED );
				MIX_RESETBIT( m_KeyStateArray[key], Mix::HID::DOWN );
//				TraceLine( _T( "Released : %d %d" ), key, m_UpdateKeyCount );
			}
		}
		else
		{
			//ダウン
			if( MIX_TESTBIT( m_KeyStateArray[key], Mix::HID::DOWN ) == 0 )
			{
				MIX_SETBIT( m_KeyStateArray[key], Mix::HID::PRESSED );
				MIX_SETBIT( m_KeyStateArray[key], Mix::HID::DOWN );
//				TraceLine( _T( "Pressed : %d" ), key );
			}
		}

		m_LastUpdateKeyList[i] = ( ( key << 8 ) | state );
	}

	m_LastUpdateKeyCount = m_UpdateKeyCount;
	m_UpdateKeyCount = 0;
}

UInt32 Keyboard::GetKeyState( Mix::HID::KEY key ) const
{
	MIX_ASSERT( Mix::HID::KEY_MAX > key );

	return m_KeyStateArray[key];
}
