
#include "stdafx.h"
#include "ogFile.h"
#include "ogText.h"
#include "ogColor.h"
#include "ogTexture.h"
#include "ogInput.h"
#include "ogMenu.h"
#include "ogUtil.h"
#include "ogEngine.h"

#include "gtasaQueue.h"

// TODO: make static object
CMenuItem * menuItems = (CMenuItem *)0x8CE008;
CMenu * menu = (CMenu *)0xBA6748;

extern FILE * log;

extern void injectFunction (DWORD address, DWORD function);

void __stdcall menu__loadTextures () { menu->loadTextures (); }
void __stdcall menu__showMessage (char * key) { menu->showMessage (key); }
void __stdcall menu__prepareTextRectangle (float * coords, BYTE * text, BYTE a8, DWORD rgba, int a10, BYTE drawBackground) 
{ menu->prepareTextRectangle (coords, text, a8, rgba, a10, drawBackground); }
void __stdcall menu__centerMouse () { menu->centerMouse (); }
void __stdcall menu__quitGame () { menu->quitGame (); }

void __stdcall menu__writeSettingsFile () { menu->writeSettingsFile(); } 

void __stdcall menu__drawBottomMessage (char * key) { menu->drawBottomMessage (key); }

void menuInject () {
	injectFunction (0x572EC0, (DWORD)menu__loadTextures);
	injectFunction (0x573EE0, (DWORD)menu__prepareTextRectangle);
	injectFunction (0x574010, (DWORD)menu__showMessage);
	injectFunction (0x57C520, (DWORD)menu__centerMouse);
	injectFunction (0x57D860, (DWORD)menu__quitGame);
	injectFunction (0x57C660, (DWORD)menu__writeSettingsFile);
	injectFunction (0x57E240, (DWORD)menu__drawBottomMessage);
}

/* DEBUG
extern FILE * log;
void printMenu () {
	for (DWORD	i = 0; i < 44; i++) {
		CMenuItem * item = menuItems+i;
		fprintf (log, "%-8s %02x %02x // %s\n", item->name, item->_f8, item->_f9, gxt.locate (item->name));
		for (DWORD j = 0; j < 12; j++) {
			CMenuItemData * data = item->items+j;
			fprintf (log, "\t%-8s %02x %02x %04x %04x %04x %04x // %s \n", data->description, data->action, data->_f9, 
				data->targetMenu, data->_fC, data->_fE, data->_f10, gxt.locate (data->description));
		}
	}
}
*/
//=============================================================================
// TODO: SA-specific!
//		чтобы сделать возможность запуска всех GTA3 игр, должен быть конфиг с описанием радиостанций
static char * fe1TexNames[] = {
	"arrow", "arrowA", "radio_playback", "", "radio_krose", "", "radio_KDST", "", 
	"radio_bounce", "", "radio_SFUR", "", "radio_RLS", "", "radio_RADIOX", "", 
	"radio_csr", "", "radio_kjah", "", "radio_mastersounds", "", "radio_WCTR", "", "radio_TPLAYER", ""
};

static char * fe2TexNames[] = {
	"back2", "", "back3", "", "back4", "", "back5", "", 
	"back6", "", "back7", "", "back8", "", "map", ""
};

static char * fepcTexNames[] = {
	"mouse", "mousea", "crosshair", "crosshaira"
};

void CMenu::loadTextures() {
	if (texturesLoaded)
		return;

	resetTimers ();
	_40E120 (0x21000);	
	_53C500 (0, 1);
	saveTexDictionary ();

	DWORD txd = txdIndexByNameAlways ("frontend1");
	txdLoad (txd, "models/fronten1.txd");
	txdAddRef (txd);
	txdSetCurrent (txd);

	int textureIndex = 0;
	for (int i = 0; i < 13; i++, textureIndex++)  {
		textures[textureIndex].read (fe1TexNames[i*2], fe1TexNames[i*2+1]);
		textures[textureIndex].setAddressing (3);
	}
	restoreTexDictionary ();

	_40E120 (0x3000);
	_53C500 (0, 1);
	saveTexDictionary ();

	txd = txdIndexByNameAlways ("frontend_pc");
	txdLoad (txd, "models/fronten_pc.txd");
	txdAddRef (txd);
	txdSetCurrent (txd);

	textureIndex = 23;
	for (int i = 0; i < 2; i++, textureIndex++)  {
		textures[textureIndex].read (fepcTexNames[i*2], fepcTexNames[i*2+1]);
		textures[textureIndex].setAddressing (3);
	}
	restoreTexDictionary ();

	_40E120 (0x4C000);
	saveTexDictionary ();
	txd = txdIndexByNameAlways ("frontend2");
	txdLoad (txd, "models/fronten2.txd");
	txdAddRef (txd);
	txdSetCurrent (txd);

	textureIndex = 13;
	for (int i = 0; i < 8; i++, textureIndex++)  {
		textures[textureIndex].read (fe2TexNames[i*2], fe2TexNames[i*2+1]);
		textures[textureIndex].setAddressing (3);
	}
	restoreTexDictionary ();
	texturesLoaded = true;

	_561B10(); 
}

#define MENUSCALEX(x) ((float)rsGlobal->maximumWidth*(float)(x)/640.0f)
#define MENUSCALEY(y) ((float)rsGlobal->maximumHeight*(float)(y)/448.0f)

void CMenu::prepareTextRectangle (float * coords, BYTE * text, BYTE a8, DWORD rgba, int a10, char drawBackground) {
	if (drawBackground) {
		RGBA color (rgba);
		drawRect (coords, &color);
	}
	if (!text || !*text)
		return;

	_7194D0 (coords[2]);	// setTextboxRight
	BYTE col = 0xE1-a8;
	RGBA textCol (col, col, col, 0xFF);
	_719430 (textCol.color);	// setTextColor
	textCol.set (0, 0, 0, 0xFF);
	_719510 (textCol.color);	// setTextBackgroundColor
	_719590 (2);
	_719610 (1);
	_719490 (0);
	_7193A0 (MENUSCALEX (1.0), MENUSCALEY (1.4));
	
	_71A700 (MENUSCALEX (10.0)+coords[0], MENUSCALEY (160)-(coords[3] > coords[1] ? coords[3] : coords[1]),  // TODO: > or < ?
		(char *)gxt.locate ((char *)text)); 
}

void CMenu::showMessage(char *key) {
	_7195C0 (0, 0);
	_7195B0 (1);
	_719490 (1);

	_7194E0 ((float)rsGlobal->maximumWidth/640.0f*430.0f);	
	
	RGBA color;
	baseColors.get (&color, 4);
	_719430 (color.color);	// set text background color? or text foreground?
	_719570 (0);

	_719380 (MENUSCALEX (0.56f), MENUSCALEY (1.0f));	// set text scale?
	float coords[4]; // text block bounds (lower left, upper right)
	coords[1] = (float)rsGlobal->maximumHeight - MENUSCALEY (165.0f);
	coords[2] = (float)rsGlobal->maximumWidth - MENUSCALEX (95.0f);
	coords[3] = MENUSCALEY (125.0f);	
	coords[0] = MENUSCALEX (95);	

	color.set (0xFF000000);
	menu->prepareTextRectangle (coords, 0, 0, color.color, 0, 1);
	char * text = (char *)gxt.locate (key);
	int lines = getTextLineCount (MENUSCALEX (322.0f), MENUSCALEY (135.0f), text);
	float height = (lines > 1 ? (MENUSCALEY (200.0f)-(float)lines*MENUSCALEY (9.0f)) : MENUSCALEY(190.0));
	// NOTE: здесь была проверка на то, что выводится одно из сообщений об ошибке чтения CD. Убрано.
	debug ("CMenu::showMessage (%s => %s)\n", key, text);
	_71A700 (MENUSCALEX (322.0), height, text);	// textDraw
}

void CMenu::centerMouse () {
	POINT p;
	p.x = rsGlobal->maximumWidth/2;
	p.y = rsGlobal->maximumHeight/2;
	ClientToScreen (rsGlobal->ps->window, &p);
	SetCursorPos (p.x, p.y);
	rsGlobal->ps->lastMousePosX = (float)p.x;
	rsGlobal->ps->lastMousePosY = (float)p.y;
}

void CMenu::quitGame () {
	debug ("CMenu::quitGame\n");
	_fB8 = 0;
	RGBA color (0, 0, 0, 0xFF);
	float coords[4] = { 0.0f, (float)rsGlobal->maximumHeight, (float)rsGlobal->maximumWidth, 0.0f };
	drawRect (coords, &color);
	writeSettingsFile ();
	RsEventHandler (rsQUITAPP, 0);
}

void CMenu::drawBottomMessage(char *key) {
	_719380 (MENUSCALEX (0.4f), MENUSCALEY (currentMenuItem == 5 ? 0.5f : 0.6f));
	_719490 (2);
	_719610 (2);
	_719590 (0);
	
	float left = 10.0f;
	RGBA color;
	if (key) {
		color.set (0xFFFFFFFF);
		_719430 (color.color);
	} else {
		BYTE alpha = 0xFF;
		if (_f1B18 != 0 && _f1B18 != 1) {
			DWORD t = *(DWORD *)0xB7CB7C;	// TODO: make variable!
			if ((t - _f1B58) > 10) {
				_f1B58 = t;
				_f1AEC -= 2;
			}
			if (_f1AEC < 1) {
				_f1B18 = 0;
				_f1AEC = 300;
			}
			alpha = _f1AEC;
			if (alpha > 255)
				alpha = 255;
		}
		color.set (0xFF, 0xFF, 0xFF, alpha);
		_719430 (color.color);
		switch (_f1B18) {
		case 1:
			key = "FET_APP";
			break;
		case 2:
			key = "FET_HRD";
			break;
		case 3:
			key = "FET_RSO";
			break;
		case 4:
			key = "FEA_SCF";
			break;
		case 5:
			key = "FEA_SCS";
			break;
		case 6:
			key = "FET_STS";
			break;
		default:
			BYTE action = menuItems[currentMenuItem].items[_f54].action;
			switch (action) {
			case 2:
				key = "FEH_BPO";
				break;
			case 5:
			case 7:
			case 8:
			case 9:
				key = "FEH_JMP";
				break;
			case 6:
				key = "FEH_SNC";
				break;
			case 0x38:
				key = "FET_MIG";
				break;
			default:
				key = currentMenuItem == 0 ? "FEH_SSA" : "FET_MIG";
				if (currentMenuItem == 5)
					left = 2.0;

			}
		}
	} 
	_71A820 (MENUSCALEX (610), (float)rsGlobal->maximumHeight-MENUSCALEY(left), gxt.locate(key));
}

void CMenu::drawMap () {
}

void CMenu::draw () {
	if (_f32)
		return;

	_719500 (255.0);	// set??Alpha
	_727350 ();	// reset2D
	_719800 ();
	_734750 ();

	// NOTE: inlined 0x573A60 (CMenu::setRenderState)
	// TODO: remove states, already prepared in _734750 
	RENDERSTATESET (rwRENDERSTATEZTESTENABLE, 0);
	RENDERSTATESET (rwRENDERSTATEZWRITEENABLE, 0);
	RENDERSTATESET (rwRENDERSTATEFOGENABLE, 0);	// remove
	RENDERSTATESET (rwRENDERSTATESRCBLEND, 5);	// remove
	RENDERSTATESET (rwRENDERSTATEDESTBLEND, 6);	// remove
	RENDERSTATESET (rwRENDERSTATEVERTEXALPHAENABLE, 1);
	RENDERSTATESET (rwRENDERSTATETEXTUREFILTER, 2);	// remove
	RENDERSTATESET (rwRENDERSTATETEXTUREADDRESS, 3);
	RENDERSTATESET (rwRENDERSTATETEXTURERASTER, 0);
	// inline end

	_f1AE9 = 1;
	// TODO: if (audioEvent->_506FF0 ()) _f1AE9 = 0;
	if (currentMenuItem == 0x2A) 	// TODO: use enum
		currentMenuItem = _fE9 == 0 ? 0x29 : 0x22;
		
	if (!_f54 && menuItems[currentMenuItem].items[0].action != 1) 
		_f54 = 1;

	// NOTE: inlined 0x57B750 (CMenu::drawPage)
	// TODO: optimize!
	if (!texturesLoaded)
		return;

	BYTE t;
	switch (currentMenuItem) {
	case 0:
	case 28:
	case 35:
		t = 0x0F;
		break;
	case 1:
	case 26:
	case 33:
		t = 0x0E;
		break;
	case 2:
	case 9:
	case 10:
	case 16:
		t = 0x0D;
		break;
	case 3:
		t = 0x10;
		break;
	case 4:
	case 27:
		t = 0x12;
		break;
	case 5:
	case 38:
		t = 0;
		break;
	case 36:
	case 39:
		t = 0x11;
		break;
	default:
		t = 0x13;
	}
	
	_f1B50 = t;
	float coords2[4] = { 1e6f, -1e6f, -1e6f, 1e6f };
	float coords[4];

	switch (t) {
	case 0x0D:
	case 0x12:
		coords2[0] = coords[0] = (float)rsGlobal->maximumWidth - MENUSCALEX (256.0f);
		coords2[1] = coords[1] = MENUSCALEY (256.0f);
		coords2[2] = coords[2] = (float)rsGlobal->maximumWidth;
		coords2[3] = coords[3] = 0.0f;
		break;

	case 0x0E:
		coords2[0] = coords[0] = (float)rsGlobal->maximumWidth - MENUSCALEX (256.0f);
		coords2[1] = coords[1] = MENUSCALEY (256.0f);
		coords2[2] = coords[2] = (float)rsGlobal->maximumWidth;
		coords2[3] = coords[3] = 0.0f;
		break;

	case 0x0F:
	case 0x11:
		coords2[0] = coords[0] = (float)rsGlobal->maximumWidth - MENUSCALEX (256.0f);
		coords2[1] = coords[1] = MENUSCALEY (256.0f);
		coords2[2] = coords[2] = (float)rsGlobal->maximumWidth;
		coords2[3] = coords[3] = 0.0f;
		break;

	case 0x10:
		coords2[0] = coords[0] = (float)(rsGlobal->maximumWidth/2) - MENUSCALEX (128.0f);
		coords2[1] = coords[1] = MENUSCALEY (256.0f);
		coords2[2] = coords[2] = (float)(rsGlobal->maximumWidth/2) + MENUSCALEX (128.0f);
		coords2[3] = coords[3] = 0.0f;
		break;

	case 0x13:
		coords2[0] = coords[0] = (float)rsGlobal->maximumWidth - MENUSCALEX (300.0f);
		coords2[1] = coords[1] = MENUSCALEY (200.0f);
		coords2[2] = coords[2] = (float)rsGlobal->maximumWidth;
		coords2[3] = coords[3] = 0.0f;
		break;
	}

	coords[0] = coords[3] = -5.0f;
	coords[1] = (float)(rsGlobal->maximumHeight+5);
	coords[2] = (float)(rsGlobal->maximumWidth+5);
	RGBA color (0xFF000000);
	drawRect (coords, &color);

	if (_f1B50) {
		color.set (0xFFFFFFFF);
		textures[_f1B50].drawTexturedRect (coords2, &color);
	}

	if (currentMenuItem == 5) {	// Map
		DWORD saved6C = _f6C;
		DWORD saved68 = _f68;
		DWORD saved64 = _f64;
		// CMenu::drawMap() // >> 575130
		_f64 = saved64;
		_f68 = saved68;
		_f6C = saved6C;
	}
	if (currentMenuItem == 38)		// controller setup
		; // >> TODO: 57F300
	else if (currentMenuItem == 43)
		quitGame ();
	else 
		; // >> TODO: 5794A0

	if (_f1AEA) {
		DWORD t1 = *(DWORD *)0xB7CB7C;	// TODO:
		if (!(_f1B4C & 1)) {
			_f1B4C = 1;
			_f1B48 = t1;
		}
		if (_f1B44) {
			_f1B44 = 0;
			_f1B48 = t1;
		}

		// .................
		
		return;
	} // 57BC19
		
}

void CMenu::writeSettingsFile () {
	Settings s;

	s.version = 6;
	inputEvents->writeToSettings (s.events);
	s._f01 = *(float *)0xB6EC1C;
	s._f02 = *(BYTE *)0xBA6745;
	s._f03 = *(BYTE *)0xC1CC02;
	s._f04 = *(BYTE *)0xC1CC03;
	s.sfxVolume		= sfxVolume;
	s.radioVolume	= radioVolume; 
	s.radioStation	= radioStation;
	s._m4D			= _f4D;
	s.radioEq		= radioEq;
	s.brightness	= brightness;
	s._mC4			= _fC4;
	s._mC5			= _fC5;
	s.multisamplingLevel = multisamplingLevel;
	s._f05 = *(DWORD *)(0xA9AE00+0x54);	// A9AE00+54, particles related
	s._f06 = 0x54;
	s.drawDistance	= drawDistance;
	s.subtitlesOn	= subtitlesOn;
	s.widescreenOn	= widescreenOn;
	s.frameLimiterOn= frameLimiterOn;
	s.videoMode		= videoMode;
	s.useKeyboardAndMouse = useKeyboardAndMouse;
	s.language		= language;
	s._m21			= _f21;
	s.drawRadar		= drawRadar;
	s._mB0			= _fB0;
	s._mE8			= _fE8;
	s._f07			= 0x1D;
	s.invertPadX1	= invertPadX1;
	s.invertPadY1	= invertPadY1;
	s.invertPadX2	= invertPadX2;
	s.invertPadY2	= invertPadY2;
	s.swapPadAxis1	= swapPadAxis1;
	s.swapPadAxis2	= swapPadAxis2;
	s.legend		= legend;
	s._mAC			= _fAC;
	s.rwSubsystem	= RwEngineGetCurrentSubSystem ();
	s._f08			= 0x5F;

	// TODO: use CreateFile
	chdirUserDir ();
	FILE * f;
	fopen_s(&f, "gta_sa.set", "wb");
	if (f) {
		fwrite (&s, sizeof (Settings), 1, f);
		fclose (f);
	}
	chdirProgramDir (""); 
}