// Open SanAndreas
// (c) 2006-2008 Stanislav "listener" Golovin
// 
// input device handling (CInputEvents и CPad)
#include <stdafx.h>
#include "ogMenu.h"
#include "ogInput.h"

#include "ogMath.h"
#include "ogRW.h"
#include "ogGameObjects.h"

CInputEvents * inputEvents = (CInputEvents *)0xB70198;
CPad * pad = (CPad *)0xB73458;

MouseState * activeMouseState = (MouseState *)0xB73404;
MouseState * currMouseState = (MouseState *)0xB73418;
MouseState * prevMouseState = (MouseState *)0xB7342C;

BYTE * mouseInvertX =  (BYTE *)0xBA6744;
BYTE * mouseInvertY =  (BYTE *)0xBA6745;

//==============================================================================
// CInputEvents
void CInputEvents::initialize() {	// >> 530500
	for (int j = 0; j < 4; j++)
		for (int i = 0; i < EVENT_COUNT; i++)
			initEvent ((InputEvent)i, j);
}

/*	TODO: отложено до момнта описания CCamera, CPed и CVehicle
void CInputEvents::processKeyboard() {
	bool inMenu = menu->menuActive ? false : true;	// TODO: doubtful name
	for (int i = 0; i < EVENT_COUNT; i++) {
		if (events[i][0].keycode != rsNULL && inMenu && isKeyPressed (events[i][0].keycode)) {

		}
		// >> 53129E
	}
}
*/

void CInputEvents::mapAllButtons() {	// >> 531F20 (3)
	initialize ();
	mapKeyboard ();
	mapMouseButtons ();
	if (padConfig->present) {
		DIDEVCAPS	caps;
		caps.dwSize = sizeof (DIDEVCAPS);
		ps->diDevice1->GetCapabilities (&caps);
		mapPadButtons (caps.dwButtons);
	}
}

void CInputEvents::mapKeyboard() {	// >> 530640
	mapKey (evGO_FORWARD, rsUP, 0);
	mapKey (evGO_BACK, rsDOWN, 0);
	mapKey (evGO_LEFT, rsLEFT, 0);
	mapKey (evGO_RIGHT, rsRIGHT, 0);
	if (menu->textLanguage == 2) {
		mapKey (evCONVERSATION_YES, (RsKeyCode)'Z', 0);
		mapKey (evPED_SNIPER_ZOOM_IN, (RsKeyCode)'Y', 1);
	} else {
		mapKey (evCONVERSATION_YES, (RsKeyCode)'Y', 0);
		mapKey (evPED_SNIPER_ZOOM_IN, (RsKeyCode)'X', 1);
	}
	if (menu->textLanguage == 1) {
		mapKey (evGO_FORWARD, (RsKeyCode)'Z', 1);
		mapKey (evGO_LEFT, (RsKeyCode)'Q', 1);
		mapKey (evPED_CYCLE_WEAPON_LEFT, (RsKeyCode)'A', 0);
		mapKey (evPED_SNIPER_ZOOM_OUT, (RsKeyCode)'W', 1);
	} else {
		mapKey (evGO_FORWARD, (RsKeyCode)'W', 1);
		mapKey (evGO_LEFT, (RsKeyCode)'A', 1);
		mapKey (evPED_CYCLE_WEAPON_LEFT, (RsKeyCode)'Q', 0);
		mapKey (evPED_SNIPER_ZOOM_OUT, (RsKeyCode)'Z', 1);
	}		
	mapKey (evGO_BACK, (RsKeyCode)'S', 1);
	mapKey (evGO_RIGHT, (RsKeyCode)'D', 1);
	mapKey (evPED_CYCLE_WEAPON_RIGHT, (RsKeyCode)'E', 0);
	mapKey (evPED_CYCLE_WEAPON_RIGHT, rsENTER, 1);
	mapKey (evPED_CYCLE_WEAPON_LEFT, rsEXTDEL, 1);
	mapKey (evPED_FIREWEAPON, rsNUM0, 0);
	mapKey (evPED_FIREWEAPON, rsLCTRL, 1);
	mapKey (evPED_SNIPER_ZOOM_IN, rsPGUP, 0);
	mapKey (evPED_SNIPER_ZOOM_OUT, rsPGDN, 0);
	mapKey (evPED_FIREWEAPON_ALT, (RsKeyCode)'\\', 0);
	mapKey (evGROUP_CONTROL_FWD, (RsKeyCode)'G', 0);
	mapKey (evGROUP_CONTROL_BWD, (RsKeyCode)'H', 0);
	mapKey (evCONVERSATION_NO, (RsKeyCode)'N', 0);
	mapKey (evVEHICLE_ENTER_EXIT, (RsKeyCode)'F', 1);
	mapKey (evVEHICLE_ENTER_EXIT, rsEXTENTER, 0);
	mapKey (evCAMERA_CHANGE_VIEW_ALL_SITUATIONS, (RsKeyCode)'V', 0);
	mapKey (evCAMERA_CHANGE_VIEW_ALL_SITUATIONS, rsHOME, 1);
	mapKey (evPED_JUMPING, rsLSHIFT, 0);
	mapKey (evPED_JUMPING, rsRCTRL, 1);
	mapKey (evPED_SPRINT, (RsKeyCode)' ', 0);
	mapKey (evPED_DUCK, (RsKeyCode)'C', 0);
	mapKey (evPED_ANSWER_PHONE, rsTAB, 0);
	mapKey (evSNEAK_ABOUT, rsLMENU, 0);
	mapKey (evPED_LOCK_TARGET, rsDEL, 0);
	mapKey (evPED_LOCK_TARGET, rsCAPSLOCK, 1);
	mapKey (evPED_1RST_PERSON_LOOK_LEFT, rsNUM4, 0);
	mapKey (evPED_1RST_PERSON_LOOK_RIGHT, rsNUM6, 0);
	mapKey (evPED_1RST_PERSON_LOOK_UP, rsNUM2, 0);
	mapKey (evPED_1RST_PERSON_LOOK_DOWN, rsNUM8, 0);
	mapKey (evPED_CENTER_CAMERA_BEHIND_PLAYER, (RsKeyCode)'#', 0);
	mapKey (evPED_LOOKBEHIND, rsEXTEND, 0);
	mapKey (evVEHICLE_STEERUP, rsUP, 0);
	mapKey (evVEHICLE_STEERDOWN, rsDOWN, 0);
	mapKey (evVEHICLE_RADIO_STATION_UP, rsINSERT, 0);
	if (menu->textLanguage == 1) {
		mapKey (evVEHICLE_STEERLEFT, (RsKeyCode)'Q', 0);
		mapKey (evVEHICLE_LOOKLEFT, (RsKeyCode)'A', 0);
		mapKey (evVEHICLE_RADIO_STATION_UP, (RsKeyCode)'`', 1);
		mapKey (evTOGGLE_SUBMISSIONS, (RsKeyCode)0xE9, 0);
		mapKey (evVEHICLE_ACCELERATE, (RsKeyCode)'Z', 0);
	} else {
		mapKey (evVEHICLE_STEERLEFT, (RsKeyCode)'A', 0);
		mapKey (evVEHICLE_LOOKLEFT, (RsKeyCode)'Q', 0);
		mapKey (evVEHICLE_RADIO_STATION_UP, (RsKeyCode)'4', 1);
		mapKey (evTOGGLE_SUBMISSIONS, (RsKeyCode)'2', 0);
		mapKey (evVEHICLE_ACCELERATE, (RsKeyCode)'W', 0);
	}
	mapKey (evTOGGLE_SUBMISSIONS, rsADD, 1);
	mapKey (evVEHICLE_FIREWEAPON, rsRCTRL, 0);
	mapKey (evVEHICLE_FIREWEAPON, rsLMENU, 1);
	mapKey (evVEHICLE_FIREWEAPON_ALT, rsLCTRL, 0);
	mapKey (evVEHICLE_FIREWEAPON_ALT, rsEXTINSERT, 1);
	mapKey (evVEHICLE_BRAKE, (RsKeyCode)'S', 0);
	mapKey (evVEHICLE_STEERRIGHT, (RsKeyCode)'D', 0);
	mapKey (evVEHICLE_STEERLEFT, rsLEFT, 1);
	mapKey (evVEHICLE_STEERRIGHT, rsRIGHT, 1);
	mapKey (evVEHICLE_HORN, rsCAPSLOCK, 0);
	mapKey (evVEHICLE_HORN, (RsKeyCode)'H', 1);
	mapKey (evVEHICLE_HANDBRAKE, (RsKeyCode)' ', 0);
	mapKey (evVEHICLE_HANDBRAKE, rsRCTRL, 1);
	mapKey (evVEHICLE_LOOKRIGHT, (RsKeyCode)'E', 0);
	mapKey (evVEHICLE_TURRETLEFT, rsNUM4, 0);
	mapKey (evVEHICLE_TURRETRIGHT, rsNUM6, 0);
	mapKey (evVEHICLE_TURRETUP, rsNUM2, 0);
	mapKey (evVEHICLE_TURRETDOWN, rsNUM8, 0);
	mapKey (evVEHICLE_TURRETUP, rsEND, 1);
	mapKey (evVEHICLE_TURRETDOWN, rsDEL, 1);
	mapKey ((InputEvent)28, rsF5, 0);
	mapKey (evVEHICLE_RADIO_STATION_DOWN, rsDEL, 0);
	mapKey (evVEHICLE_RADIO_STATION_DOWN, (RsKeyCode)'R', 1);
	mapKey (evPED_CYCLE_TARGET_LEFT, (RsKeyCode)'[', 0);
	mapKey (evPED_CYCLE_TARGET_RIGHT, (RsKeyCode)']', 0);
	memset (_f12D0, 0, 16);
}

// TODO: упростить конструкцию, чтобы убрать switch и лишние if
void CInputEvents::mapMouseButtons () {
	// inlined getMouseButtonMask (>> 53F2D0)
	BYTE buttonMask[8];
	memset (buttonMask, 0, 8);
	if (ps->diMouse == NULL) {	// reinitialize mouse
		bool exclusive = false;
		if (menu->menuActive || isCurrentModeFullscreen ())
			exclusive = true;
		diMouseInit (exclusive);
	}
	if (ps->diMouse != NULL) {
		DIDEVCAPS caps;
		caps.dwSize = sizeof (DIDEVCAPS);
		ps->diMouse->GetCapabilities (&caps);	
		if (caps.dwButtons > 2) 
			buttonMask[2] = 1;
		if (caps.dwButtons > 1)
			buttonMask[1] = 1;
		if (caps.dwButtons > 0) {
			buttonMask[0] = 1;
			buttonMask[3] = 1;
			buttonMask[4] = 1;
		}
	}
	// end of the getMouseButtonMask

	if (buttonMask[0]) {	// LMB present
		_f12E0 = 1;
		mapMouseButton (evPED_FIREWEAPON, 1);
		mapMouseButton (evVEHICLE_FIREWEAPON, 1);
	}
	if (buttonMask[1]) {	// RMB present
		mapMouseButton (evPED_LOCK_TARGET, 3);
		mapMouseButton (evVEHICLE_MOUSELOOK, 3);
	}
	if (buttonMask[2]) {	// MMB present
		mapMouseButton (evPED_LOOKBEHIND, 2);
		mapMouseButton (evVEHICLE_LOOKBEHIND, 2);
	}
	if (buttonMask[3] && buttonMask[4]) {	// wheel present
		mapMouseButton (evPED_CYCLE_WEAPON_LEFT, 4);
		mapMouseButton (evPED_CYCLE_WEAPON_RIGHT, 5);
		mapMouseButton (evVEHICLE_RADIO_STATION_UP, 4);
		mapMouseButton (evVEHICLE_RADIO_STATION_DOWN, 5);
		mapMouseButton (evPED_SNIPER_ZOOM_IN, 4);
		mapMouseButton (evPED_SNIPER_ZOOM_OUT, 5);
	}
}

void CInputEvents::mapPadButtons (int buttonCount) {
	_f0 = 1;
	if (buttonCount > 16)
		buttonCount = 16;
	// NOTE: здесь была проверка на переходник USB=>PS2 pad и соответствующая раскладка. Убрано за неимением девайса в обозримых окрестностях
	switch (buttonCount) {	// big fall-through switch
	case 16:
		mapKey (evCONVERSATION_NO, (RsKeyCode)16, 3);
	case 15:
		mapKey (evGROUP_CONTROL_BWD, (RsKeyCode)15, 3);
		mapKey (evVEHICLE_RADIO_STATION_DOWN, (RsKeyCode)15, 3);
	case 14:
		mapKey (evCONVERSATION_YES, (RsKeyCode)14, 3);
	case 13:
		mapKey (evGROUP_CONTROL_FWD, (RsKeyCode)13, 3);
		mapKey (evVEHICLE_RADIO_STATION_UP, (RsKeyCode)13, 3);
	case 12:
	case 11:
		mapKey (evTOGGLE_SUBMISSIONS, (RsKeyCode)11, 3);
		mapKey (evPED_LOOKBEHIND, (RsKeyCode)11, 3);
	case 10:
		mapKey (evVEHICLE_HORN, (RsKeyCode)10, 3);
		mapKey (evPED_DUCK, (RsKeyCode)10, 3);
	case 9:
		mapKey (evCAMERA_CHANGE_VIEW_ALL_SITUATIONS, (RsKeyCode)9, 3);
	case 8:
		mapKey (evVEHICLE_HANDBRAKE, (RsKeyCode)8, 3);
		mapKey (evPED_LOCK_TARGET, (RsKeyCode)8, 3);
	case 7:
		mapKey (evPED_ANSWER_PHONE, (RsKeyCode)7, 3);
		mapKey (evPED_FIREWEAPON_ALT, (RsKeyCode)7, 3);
		mapKey (evVEHICLE_FIREWEAPON_ALT, (RsKeyCode)7, 3);
	case 6:
		mapKey (evPED_CYCLE_WEAPON_RIGHT, (RsKeyCode)6, 3);
		mapKey (evVEHICLE_LOOKRIGHT, (RsKeyCode)6, 3);
	case 5:
		mapKey (evPED_CYCLE_WEAPON_LEFT, (RsKeyCode)5, 3);
		mapKey (evVEHICLE_LOOKLEFT, (RsKeyCode)5, 3);
	case 4:
		mapKey (evVEHICLE_ENTER_EXIT, (RsKeyCode)4, 3);
	case 3:
		mapKey (evVEHICLE_BRAKE, (RsKeyCode)3, 3);
		mapKey (evPED_JUMPING, (RsKeyCode)3, 3);
		mapKey (evPED_SNIPER_ZOOM_IN, (RsKeyCode)3, 3);
	case 2:
		mapKey (evVEHICLE_ACCELERATE, (RsKeyCode)2, 3);
		mapKey (evPED_SPRINT, (RsKeyCode)2, 3);
		mapKey (evPED_SNIPER_ZOOM_OUT, (RsKeyCode)2, 3);
	case 1:
		mapKey (evPED_FIREWEAPON, (RsKeyCode)1, 3);
		mapKey (evVEHICLE_FIREWEAPON, (RsKeyCode)1, 3);
	}
}

void CInputEvents::mapKey (InputEvent event, RsKeyCode key, int type) {	// >> 530490
	initPriority (event);

	int priority = 0;
	if (events[event][0].keycode != rsNULL) 
		priority = 1;
	if (events[event][1].keycode != rsNULL)
		priority++;
	if (events[event][2].keycode != 0)
		priority++;
	if (events[event][3].keycode != 0)
		priority++;

	events[event][type].keycode = key;
	events[event][type].priority = priority+1;

}

void CInputEvents::mapMouseButton(InputEvent event, int button) {	// >> 52F590
	int priority = 0;
	if (events[event][0].keycode != rsNULL)
		priority++;
	if (events[event][1].keycode != rsNULL)
		priority++;
	if (events[event][2].keycode != 0)
		priority++;
	if (events[event][3].keycode != 0)
		priority++;
	events[event][2].keycode = button;
	events[event][2].priority = priority+1;
}

void CInputEvents::initEvent(InputEvent event, DWORD type) {
	if (type > 3)
		return;
	events[event][type].keycode = type > 1 ? 0 : rsNULL;
	events[event][type].priority = 0;
	initPriority (event);
}

// TODO: optimize it!
void CInputEvents::initPriority(InputEvent event) {
	DWORD	index;

	for (DWORD i = 1; i < 5; i++ ) {			
        if (events[event][0].priority != i &&
            events[event][1].priority != i &&
            events[event][2].priority != i &&
            events[event][3].priority != i)
            continue;

		bool found = false;

        if (events[event][0].priority > i) {
            found = true;
            index = 0;
        }
        if (events[event][1].priority > i) 
            if (!found || events[event][1].priority < events[event][index].priority) {
                found = true;
                index = 1;
            }
        if (events[event][2].priority > i) 
            if (!found || events[event][2].priority < events[event][index].priority) {
                found = true;
                index = 2;
            }
        if (events[event][3].priority > i) 
            if (!found || events[event][3].priority < events[event][index].priority) {
                // found = true; // ????
                index = 3;
            }
            
        if (found) 
            events[event][index].priority = i;
	}	
}
//==============================================================================
// CPad
// TODO: переименовать кнопки (либо сделать альтернативный вариант с циклом)
bool CPad::isAnyPuttonPressed() {	// >> 53EFF0 (2)
	if (padData.keys[0] ||
		padData.keys[1] ||
		padData.keys[2] ||
		padData.keys[3] ||
		padData.keys[4] ||
		padData.keys[5] ||
		padData.keys[6] ||
		padData.keys[7] ||
		padData.keys[8] ||
		padData.keys[9] ||
		padData.keys[10] ||
		padData.keys[11] ||
		padData.keys[12] ||
		padData.keys[13] ||
		padData.keys[14] ||
		padData.keys[15] ||
		padData.keys[16] ||
		padData.keys[17] ||
		padData.keys[18] ||
		padData.keys[19])
		return true;
	return false;
}