/*  ZeroPAD - author: zerofrog(@gmail.com)
 *  Copyright (C) 2006-2007
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
 /*
  * Theoretically, this header is for anything to do with keyboard input.
  * Pragmatically, event handing's going in here too.
  */
  
 #include "keyboard.h"
 
  __forceinline int FindKey(int key, int pad)
{
	for (int p = 0; p < PADSUBKEYS; p++)
		for (int i = 0; i < PADKEYS; i++)
			if (key == conf.keys[(PadEnum[pad][p])][i]) return i;
	return -1;
}

#ifdef _WINDOWS_
WORD toCharTemp;
#endif

char* KeysymToChar(int keysym)
{
#ifdef __LINUX__
	return XKeysymToString(keysym);
#else
	// fixed this to return *valid* results, and not some pointer
	// to the fourth oblivion-- air
	ToAscii((UINT) keysym, NULL, NULL, &toCharTemp, NULL);
	return (char*)(&toCharTemp);
#endif
}

void PollForKeyboardInput(int pad)
{
 #ifdef __LINUX__
	PollForX11KeyboardInput(pad);
#endif
}

void SetAutoRepeat(bool autorep)
{
 #ifdef __LINUX__
	if (autorep)
		XAutoRepeatOn(GSdsp);
	else
		XAutoRepeatOff(GSdsp);
#endif
}

 #ifdef __LINUX__
void PollForX11KeyboardInput(int pad)
{
	XEvent E;
	KeySym key;
	int keyPress = 0, keyRelease = 0;
	int i;
	
	// keyboard input
	while (XPending(GSdsp) > 0)
	{
		XNextEvent(GSdsp, &E);
		switch (E.type)
		{
			case KeyPress:
				key = XLookupKeysym((XKeyEvent *) & E, 0);

				i = FindKey(key, pad);
			
				// Analog controls.
				if ((i > PAD_RY) && (i <= PAD_R_LEFT))
				{
				switch (i)
				{
					case PAD_R_LEFT:
					case PAD_R_UP:
					case PAD_L_LEFT:
					case PAD_L_UP:
						Analog::ConfigurePad(Analog::AnalogToPad(i), pad, DEF_VALUE);
						break;
					case PAD_R_RIGHT:
					case PAD_R_DOWN:
					case PAD_L_RIGHT:
					case PAD_L_DOWN:
						Analog::ConfigurePad(Analog::AnalogToPad(i), pad, -DEF_VALUE);
						break;
				}
				i += 0xff00;
				}
				
				if (i != -1) 
				{
					clear_bit(keyRelease, i); 
					set_bit(keyPress, i);
				}
				//PAD_LOG("Key pressed:%d\n", i);

				event.evt = KEYPRESS;
				event.key = key;
				break;
				
			case KeyRelease:
				key = XLookupKeysym((XKeyEvent *) & E, 0);

				i = FindKey(key, pad);
			
				// Analog Controls.
				if ((i > PAD_RY) && (i <= PAD_R_LEFT))
				{
					Analog::ResetPad(Analog::AnalogToPad(i), pad);
					i += 0xff00;
				}
				
				if (i != -1) 
				{
					clear_bit(keyPress, i); 
					set_bit(keyRelease, i);
				}

				event.evt = KEYRELEASE;
				event.key = key;
				break;

			case FocusIn:
				XAutoRepeatOff(GSdsp);
				break;

			case FocusOut:
				XAutoRepeatOn(GSdsp);
				break;
		}
	}

	UpdateKeys(pad, keyPress, keyRelease);
}

bool PollX11Keyboard(char* &temp, u32 &pkey)
{
	GdkEvent *ev = gdk_event_get();
	
	if (ev != NULL)
	{
		if (ev->type == GDK_KEY_PRESS)
		{
			
			if (ev->key.keyval == GDK_Escape) 
			{
				temp = "Unknown";
				pkey = NULL;
			}
			else
			{
				temp = KeysymToChar(ev->key.keyval);
				pkey = ev->key.keyval;
			}
			
			return true;
		}
	}
	
	return false;
}
#else
LRESULT WINAPI PADwndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	int keyPress[2] = {0}, keyRelease[2] = {0};
	static bool lbutton = false, rbutton = false;

	switch (msg)
	{
		case WM_KEYDOWN:
			if (lParam & 0x40000000) return TRUE;

			for (int pad = 0; pad < 2; ++pad)
			{
				for (int i = 0; i < PADKEYS; i++)
				{
					if (wParam == conf.keys[pad][i])
					{
						set_bit(keyPress[pad], i);
						clear_bit(keyRelease[pad], i);
						break;
					}
				}
			}

			event.evt = KEYPRESS;
			event.key = wParam;
			break;

		case WM_KEYUP:
			for (int pad = 0; pad < 2; ++pad)
			{
				for (int i = 0; i < PADKEYS; i++)
				{
					if (wParam == conf.keys[pad][i])
					{
						set_bit(keyRelease[pad], i);
						clear_bit(keyPress[pad], i);
						break;
					}
				}
			}


			event.evt = KEYRELEASE;
			event.key = wParam;
			break;

		/*case WM_LBUTTONDOWN:
			lbutton = true;
			break;

		case WM_LBUTTONUP:
			g_lanalog[0].x = 0x80;
			g_lanalog[0].y = 0x80;
			g_lanalog[1].x = 0x80;
			g_lanalog[1].y = 0x80;
			lbutton = false;
			break;

		case WM_RBUTTONDOWN:
			rbutton = true;
			break;

		case WM_RBUTTONUP:
			g_ranalog[0].x = 0x80;
			g_ranalog[0].y = 0x80;
			g_ranalog[1].x = 0x80;
			g_ranalog[1].y = 0x80;
			rbutton = false;
			break;

		case WM_MOUSEMOVE:
			if (lbutton)
			{
				g_lanalog[0].x = LOWORD(lParam) & 254;
				g_lanalog[0].y = HIWORD(lParam) & 254;
				g_lanalog[1].x = LOWORD(lParam) & 254;
				g_lanalog[1].y = HIWORD(lParam) & 254;
			}
			if (rbutton)
			{
				g_ranalog[0].x = LOWORD(lParam) & 254;
				g_ranalog[0].y = HIWORD(lParam) & 254;
				g_ranalog[1].x = LOWORD(lParam) & 254;
				g_ranalog[1].y = HIWORD(lParam) & 254;
			}
			break;*/

		case WM_DESTROY:
		case WM_QUIT:
			event.evt = KEYPRESS;
			event.key = VK_ESCAPE;
			return GSwndProc(hWnd, msg, wParam, lParam);

		default:
			return GSwndProc(hWnd, msg, wParam, lParam);
	}

	for (int pad = 0; pad < 2; ++pad)
	{
		UpdateKeys(pad, keyPress[pad], keyRelease[pad]);
	}

	return TRUE;
}
#endif