#include "title.h"
#include "common/jscore.h"

// Constructor
Title::Title(SDL_Renderer *renderer, Screen *screen, Input *input, Asset *asset, options_t *options, Lang *lang, section_t *section)
{
	// Copia las direcciones de los punteros
	this->renderer = renderer;
	this->screen = screen;
	this->input = input;
	this->asset = asset;
	this->options = options;
	this->lang = lang;
	this->section = section;

	// Reserva memoria para los punteros
	eventHandler = new SDL_Event();
	fade = new Fade(renderer);

	dustTexture = new Texture(renderer, asset->get("title_dust.png"));
	coffeeTexture = new Texture(renderer, asset->get("title_coffee.png"));
	crisisTexture = new Texture(renderer, asset->get("title_crisis.png"));
	gradientTexture = new Texture(renderer, asset->get("title_gradient.png"));

	coffeeBitmap = new SmartSprite(coffeeTexture, renderer);
	crisisBitmap = new SmartSprite(crisisTexture, renderer);
	dustBitmapL = new AnimatedSprite(dustTexture, renderer, asset->get("title_dust.ani"));
	dustBitmapR = new AnimatedSprite(dustTexture, renderer, asset->get("title_dust.ani"));
	gradient = new Sprite({0, 0, 256, 192}, gradientTexture, renderer);

	text1 = new Text(asset->get("smb2.png"), asset->get("smb2.txt"), renderer);
	text2 = new Text(asset->get("8bithud.png"), asset->get("8bithud.txt"), renderer);

#ifdef GAME_CONSOLE
	menu.title = new Menu(renderer, asset, input, asset->get("title_gc.men"));
	menu.options = new Menu(renderer, asset, input, asset->get("options_gc.men"));
#else
	menu.title = new Menu(renderer, asset, input, asset->get("title.men"));
	menu.options = new Menu(renderer, asset, input, asset->get("options.men"));
#endif
	menu.playerSelect = new Menu(renderer, asset, input, asset->get("player_select.men"));

	// Sonidos
	crashSound = JA_LoadSound(asset->get("title.wav").c_str());

	// Musicas
	titleMusic = JA_LoadMusic(asset->get("title.ogg").c_str());

	// Inicializa los valores
	init();

	// Deshabilita ciertas opciones de los menus
	disableMenuEntries();
}

// Destructor
Title::~Title()
{
	delete eventHandler;
	delete fade;

	dustTexture->unload();
	delete dustTexture;

	coffeeTexture->unload();
	delete coffeeTexture;

	crisisTexture->unload();
	delete crisisTexture;

	gradientTexture->unload();
	delete gradientTexture;

	delete coffeeBitmap;
	delete crisisBitmap;
	delete dustBitmapL;
	delete dustBitmapR;
	delete gradient;

	delete text1;
	delete text2;

	delete menu.title;
	delete menu.options;
	delete menu.playerSelect;

	JA_DeleteSound(crashSound);
	JA_DeleteMusic(titleMusic);

	SDL_DestroyTexture(background);
}

// Inicializa los valores
void Title::init()
{
	// Inicializa variables
	section->subsection = SUBSECTION_TITLE_1;
	counter = TITLE_COUNTER;
	backgroundCounter = 0;
	backgroundMode = rand() % 2;
	menuVisible = false;
	menu.active = menu.title;
	nextSection.name = SECTION_PROG_GAME;
	postFade = 0;
	ticks = 0;
	ticksSpeed = 15;
	fade->init(0x17, 0x17, 0x26);
	demo = true;

	// Pone valores por defecto a las opciones de control
	options->input.clear();

	input_t i;
	i.id = 0;
	i.name = "KEYBOARD";
	i.deviceType = INPUT_USE_KEYBOARD;
	options->input.push_back(i);

	i.id = 0;
	i.name = "GAME CONTROLLER";
	i.deviceType = INPUT_USE_GAMECONTROLLER;
	options->input.push_back(i);

	// Comprueba si hay mandos conectados
	checkInputDevices();

	// Pone valores por defecto. El primer jugador el teclado. El segundo jugador el primer mando
	deviceIndex.clear();
	deviceIndex.push_back(availableInputDevices.size() - 1); // El último dispositivo encontrado es el teclado
	deviceIndex.push_back(0);								 // El primer mando encontrado. Si no ha encontrado ninguno es el teclado

	// Si ha encontrado un mando se lo asigna al segundo jugador
	if (input->gameControllerFound())
	{
		options->input[1].id = availableInputDevices[deviceIndex[1]].id;
		options->input[1].name = availableInputDevices[deviceIndex[1]].name;
		options->input[1].deviceType = availableInputDevices[deviceIndex[1]].deviceType;
	}
	else
	{ // Si no ha encontrado un mando, deshabilita la opción de jugar a 2 jugadores
		menu.title->setSelectable(1, false);
		menu.title->setGreyed(1, true);
	}

	// Inicializa el bitmap de Coffee
	coffeeBitmap->init();
	coffeeBitmap->setPosX(45);
	coffeeBitmap->setPosY(11 - 200);
	coffeeBitmap->setWidth(167);
	coffeeBitmap->setHeight(46);
	coffeeBitmap->setVelX(0.0f);
	coffeeBitmap->setVelY(2.5f);
	coffeeBitmap->setAccelX(0.0f);
	coffeeBitmap->setAccelY(0.1f);
	coffeeBitmap->setSpriteClip(0, 0, 167, 46);
	coffeeBitmap->setEnabled(true);
	coffeeBitmap->setEnabledCounter(0);
	coffeeBitmap->setDestX(45);
	coffeeBitmap->setDestY(11);

	// Inicializa el bitmap de Crisis
	crisisBitmap->init();
	crisisBitmap->setPosX(60);
	crisisBitmap->setPosY(57 + 200);
	crisisBitmap->setWidth(137);
	crisisBitmap->setHeight(46);
	crisisBitmap->setVelX(0.0f);
	crisisBitmap->setVelY(-2.5f);
	crisisBitmap->setAccelX(0.0f);
	crisisBitmap->setAccelY(-0.1f);
	crisisBitmap->setSpriteClip(0, 0, 137, 46);
	crisisBitmap->setEnabled(true);
	crisisBitmap->setEnabledCounter(0);
	crisisBitmap->setDestX(60);
	crisisBitmap->setDestY(57);

	// Inicializa el bitmap de DustRight
	dustBitmapR->resetAnimation();
	dustBitmapR->setPosX(218);
	dustBitmapR->setPosY(47);
	dustBitmapR->setWidth(16);
	dustBitmapR->setHeight(16);
	dustBitmapR->setFlip(SDL_FLIP_HORIZONTAL);

	// Inicializa el bitmap de DustLeft
	dustBitmapL->resetAnimation();
	dustBitmapL->setPosX(33);
	dustBitmapL->setPosY(47);
	dustBitmapL->setWidth(16);
	dustBitmapL->setHeight(16);

	// Inicializa el sprite con el degradado
	gradient->setSpriteClip(0, 96, 256, 192);

	// Crea el mosaico de fondo del titulo
	createTiledBackground();

	// Coloca la ventana que recorre el mosaico de fondo de manera que coincida con el mosaico que hay pintado en el titulo al iniciar
	backgroundWindow.x = 128;
	backgroundWindow.y = 96;
	backgroundWindow.w = GAMECANVAS_WIDTH;
	backgroundWindow.h = GAMECANVAS_HEIGHT;

	// Inicializa los valores del vector con los valores del seno
	for (int i = 0; i < 360; ++i)
	{
		sin[i] = SDL_sinf((float)i * 3.14f / 180.0f);
	}

	// Actualiza los textos de los menus
	updateMenuLabels();
}

// Actualiza las variables del objeto
void Title::update()
{
	// Comprueba las entradas
	checkInput();

	// Calcula la lógica de los objetos
	if (SDL_GetTicks() - ticks > ticksSpeed)
	{
		// Actualiza el contador de ticks
		ticks = SDL_GetTicks();

		// Actualiza las notificaciones
		screen->updateNotifier();

		switch (section->subsection)
		{
		// Sección 1 - Titulo desplazandose
		case SUBSECTION_TITLE_1:
		{
			// Actualiza los objetos
			coffeeBitmap->update();
			crisisBitmap->update();

			// Si los objetos han llegado a su destino, cambiamos de Sección
			if (coffeeBitmap->hasFinished() && crisisBitmap->hasFinished())
			{
				section->subsection = SUBSECTION_TITLE_2;

				// Pantallazo blanco
				SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
				SDL_RenderClear(renderer);
				SDL_RenderPresent(renderer);

				// Reproduce el efecto sonoro
				JA_PlaySound(crashSound);
			}
		}
		break;

		// Sección 2 - Titulo vibrando
		case SUBSECTION_TITLE_2:
		{
			// Agita la pantalla
			static const int v[] = {-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 0};
			static const int a = coffeeBitmap->getPosX();
			static const int b = crisisBitmap->getPosX();
			static int step = 0;

			coffeeBitmap->setPosX(a + v[step / 3]);
			crisisBitmap->setPosX(b + v[step / 3]);
			dustBitmapR->update();
			dustBitmapL->update();

			step++;

			if (step == 33)
			{
				section->subsection = SUBSECTION_TITLE_3;
			}
		}
		break;

		// Sección 3 - La pantalla de titulo con el menú y la música
		case SUBSECTION_TITLE_3:
		{
			if (counter > 0)
			{ // Reproduce la música
				if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
				{
					JA_PlayMusic(titleMusic);
				}

				dustBitmapR->update();
				dustBitmapL->update();

				// Actualiza la lógica del titulo
				fade->update();

				if (fade->hasEnded())
				{
					switch (postFade)
					{
					case 0: // 1 PLAYER
						section->name = SECTION_PROG_GAME;
						section->subsection = SUBSECTION_GAME_PLAY_1P;
						JA_StopMusic();
						break;

					case 1: // 2 PLAYERS
						section->name = SECTION_PROG_GAME;
						section->subsection = SUBSECTION_GAME_PLAY_2P;
						JA_StopMusic();
						break;

					case 2: // QUIT
						section->name = SECTION_PROG_QUIT;
						JA_StopMusic();
						break;

					case 3: // TIME OUT
						counter = TITLE_COUNTER;
						menu.active->reset();
						if (demo)
						{
							runDemoGame();
							if (section->name != SECTION_PROG_QUIT)
							{
								runInstructions(m_auto);
							}
							if (section->name != SECTION_PROG_QUIT)
							{
								runHiScoreTable(mhst_auto);
							}
						}
						else
							section->name = SECTION_PROG_LOGO;
						break;

					default:
						break;
					}
				}

				// Actualiza el tileado de fondo
				updateBG();

				// Comprueba las entradas para el menu
				if (menuVisible == true)
				{
					menu.active->update();
				}

				// Comprueba si se ha seleccionado algún item del menú de titulo
				if (menu.active->getName() == "TITLE")
				{
					switch (menu.active->getItemSelected())
					{
					case 0: // 1 PLAYER -> Cambia al manu de selección de jugador
						menu.active = menu.playerSelect;
						break;

					case 1: // 2 PLAYERS
						postFade = 1;
						fade->activateFade();
						break;

					case 2: // OPTIONS
						menu.active = menu.options;
						optionsPrevious = *options;
						break;

					case 3: // QUIT
						postFade = 2;
						fade->activateFade();
						break;

					default:
						break;
					}
				}

				// Comprueba si se ha seleccionado algún item del menú de selección de jugador
				if (menu.active->getName() == "PLAYER_SELECT")
				{
					switch (menu.active->getItemSelected())
					{
					case 0:
						// Este item no se puede seleccionar y actua de titulo
						break;

					case 1: // BAL1
						postFade = 0;
						options->playerSelected = 0;
						fade->activateFade();
						break;

					case 2: // AROUNDER
						postFade = 0;
						options->playerSelected = 1;
						fade->activateFade();
						break;

					case 3: // BACK
						menu.active = menu.title;
						menu.playerSelect->reset();
						break;

					default:
						break;
					}
				}

				// Comprueba si se ha seleccionado algún item de opciones
				if (menu.active->getName() == "OPTIONS")
				{
					switch (menu.active->getItemSelected())
					{
					case 0: // Difficulty
						if (options->difficulty == DIFFICULTY_EASY)
							options->difficulty = DIFFICULTY_NORMAL;
						else if (options->difficulty == DIFFICULTY_NORMAL)
							options->difficulty = DIFFICULTY_HARD;
						else
							options->difficulty = DIFFICULTY_EASY;
						updateMenuLabels();
						break;

					case 1: // PLAYER 1 CONTROLS
						updatePlayerInputs(0);
						updateMenuLabels();
						break;

					case 3: // PLAYER 2 CONTROLS
						updatePlayerInputs(1);
						updateMenuLabels();
						break;

					case 5: // Language
						options->language++;
						if (options->language == 3)
							options->language = 0;
						updateMenuLabels();
						break;

					case 6: // Display mode
						switchFullScreenModeVar();
						if (options->videoMode != 0)
						{
							menu.options->setSelectable(8, false);
							menu.options->setGreyed(8, true);
						}
						else
						{
							menu.options->setSelectable(8, true);
							menu.options->setGreyed(8, false);
						}
						updateMenuLabels();
						break;

					case 8: // Windows size
						options->windowSize++;
						if (options->windowSize == 5)
							options->windowSize = 1;
						updateMenuLabels();
						break;

					case 9: // FILTER
						if (options->filter == FILTER_LINEAL)
							options->filter = FILTER_NEAREST;
						else
							options->filter = FILTER_LINEAL;
						updateMenuLabels();
						break;

					case 10: // VSYNC
						if (options->vSync)
							options->vSync = false;
						else
							options->vSync = true;
						updateMenuLabels();
						break;

					case 11: // HOW TO PLAY
						runInstructions(m_manual);
						break;

					case 12: // ACCEPT
						applyOptions();
						menu.active->reset();
						menu.active = menu.title;
						break;

					case 13: // CANCEL
						options = &optionsPrevious;
						updateMenuLabels();
						menu.active->reset();
						menu.active = menu.title;
						break;

					default:
						break;
					}
				}

				if (menu.active->getName() == "TITLE")
				{
					counter--;
				}
			}
			else if (counter == 0)
			{
				if (demo)
				{
					runDemoGame();
					if (section->name != SECTION_PROG_QUIT)
					{
						runInstructions(m_auto);
					}
					if (section->name != SECTION_PROG_QUIT)
					{
						runHiScoreTable(mhst_auto);
					}
					init();
					demo = false;
					counter = TITLE_COUNTER;
				}
				else
				{
					section->name = SECTION_PROG_LOGO;
				}
			}

			// Sección Instrucciones
			if (section->subsection == SUBSECTION_TITLE_INSTRUCTIONS)
			{
				runInstructions(m_auto);
				counter = TITLE_COUNTER;
				demo = true;
			}
		}

		break;

		default:
			break;
		}
	}
}

// Dibuja el objeto en pantalla
void Title::render()
{
	switch (section->subsection)
	{
	// Sección 1 - Titulo desplazandose
	case SUBSECTION_TITLE_1:
	{
		// Prepara para empezar a dibujar en la textura de juego
		screen->start();

		// Limpia la pantalla
		screen->clean(bgColor);

		// Dibuja el tileado de fondo
		SDL_RenderCopy(renderer, background, &backgroundWindow, nullptr);

		// Dibuja el degradado
		gradient->render();

		// Dibuja los objetos
		coffeeBitmap->render();
		crisisBitmap->render();

		// Vuelca el contenido del renderizador en pantalla
		screen->blit();
	}
	break;

	// Sección 2 - Titulo vibrando
	case SUBSECTION_TITLE_2:
	{ // Reproduce el efecto sonoro
		JA_PlaySound(crashSound);

		// Agita la pantalla
		const int v[] = {-1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 0};
		const int a = coffeeBitmap->getPosX();
		const int b = crisisBitmap->getPosX();
		for (int n = 0; n < 11 * 3; ++n)
		{
			// Prepara para empezar a dibujar en la textura de juego
			screen->start();

			// Limpia la pantalla
			screen->clean(bgColor);

			// Dibuja el tileado de fondo
			SDL_RenderCopy(renderer, background, &backgroundWindow, nullptr);

			// Dibuja el degradado
			gradient->render();

			// Dibuja los objetos
			coffeeBitmap->setPosX(a + v[n / 3]);
			crisisBitmap->setPosX(b + v[n / 3]);
			coffeeBitmap->render();
			crisisBitmap->render();

			dustBitmapR->update();
			dustBitmapL->update();
			dustBitmapR->render();
			dustBitmapL->render();

			// Vuelca el contenido del renderizador en pantalla
			screen->blit();
		}

		section->subsection = SUBSECTION_TITLE_3;
	}

	break;

	// Sección 3 - La pantalla de titulo con el menú y la música
	case SUBSECTION_TITLE_3:
	{ // Prepara para empezar a dibujar en la textura de juego
		screen->start();

		// Limpia la pantalla
		screen->clean(bgColor);

		// Dibuja el tileado de fondo
		SDL_RenderCopy(renderer, background, &backgroundWindow, nullptr);

		// Dibuja el degradado
		gradient->render();

		// Dibuja los objetos
		if (menu.active->getName() != "OPTIONS")
		{
			// Bitmaps con el logo/titulo del juego
			coffeeBitmap->render();
			crisisBitmap->render();

			// Texto con el copyright y versión
			text2->writeDX(TXT_CENTER | TXT_SHADOW, GAMECANVAS_CENTER_X, GAMECANVAS_HEIGHT - (BLOCK * 2), TEXT_COPYRIGHT, 1, noColor, 1, shdwTxtColor);
		}

		if (menuVisible == true)
		{
			menu.active->render();
		}

		dustBitmapR->render();
		dustBitmapL->render();

		// PRESS ANY KEY!
		if ((counter % 50 > 14) && (menuVisible == false))
		{
			text1->writeDX(TXT_CENTER | TXT_SHADOW, GAMECANVAS_CENTER_X, PLAY_AREA_THIRD_QUARTER_Y + BLOCK, lang->getText(23), 1, noColor, 1, shdwTxtColor);
		}

		// Fade
		fade->render();

		// Vuelca el contenido del renderizador en pantalla
		screen->blit();
	}
	break;

	default:
		break;
	}
}

// Comprueba los eventos
void Title::checkEvents()
{
	// Comprueba los eventos que hay en la cola
	while (SDL_PollEvent(eventHandler) != 0)
	{
		// Evento de salida de la aplicación
		if (eventHandler->type == SDL_QUIT)
		{
			section->name = SECTION_PROG_QUIT;
			break;
		}

		else if (eventHandler->type == SDL_RENDER_DEVICE_RESET || eventHandler->type == SDL_RENDER_TARGETS_RESET)
		{
			reLoadTextures();
		}

		if (section->subsection == SUBSECTION_TITLE_3)
		{ // Si se pulsa alguna tecla durante la tercera sección del titulo
			if ((eventHandler->type == SDL_KEYUP) || (eventHandler->type == SDL_JOYBUTTONUP))
			{
				// Muestra el menu
				menuVisible = true;

				// Reinicia el contador
				counter = TITLE_COUNTER;
			}

			if (eventHandler->type == SDL_KEYDOWN)
			{
				switch (eventHandler->key.keysym.scancode)
				{
				case SDL_SCANCODE_A:
					runEnterID();
					break;

				default:
					break;
				}
			}
		}
	}
}

// Comprueba las entradas
void Title::checkInput()
{
	if (input->checkInput(input_exit, REPEAT_FALSE))
	{
		section->name = SECTION_PROG_QUIT;
	}

	else if (input->checkInput(input_window_fullscreen, REPEAT_FALSE))
	{
		screen->switchVideoMode();
	}

	else if (input->checkInput(input_window_dec_size, REPEAT_FALSE))
	{
		screen->decWindowSize();
	}

	else if (input->checkInput(input_window_inc_size, REPEAT_FALSE))
	{
		screen->incWindowSize();
	}
}

// Actualiza el tileado de fondo
void Title::updateBG()
{
	if (backgroundMode == 0)
	{ // El tileado de fondo se desplaza en diagonal
		++backgroundWindow.x %= 64;
		++backgroundWindow.y %= 64;
	}
	else
	{ // El tileado de fondo se desplaza en circulo
		++backgroundCounter %= 360;
		backgroundWindow.x = 128 + (int(sin[(backgroundCounter + 270) % 360] * 128));
		backgroundWindow.y = 96 + (int(sin[(360 - backgroundCounter) % 360] * 96));
	}
}

// Cambia el valor de la variable de modo de pantalla completa
void Title::switchFullScreenModeVar()
{
	switch (options->videoMode)
	{
	case 0:
		options->videoMode = SDL_WINDOW_FULLSCREEN;
		break;
	case SDL_WINDOW_FULLSCREEN:
		options->videoMode = SDL_WINDOW_FULLSCREEN_DESKTOP;
		break;
	case SDL_WINDOW_FULLSCREEN_DESKTOP:
		options->videoMode = 0;
		break;

	default:
		options->videoMode = 0;
		break;
	}
}

// Actualiza los elementos de los menus
void Title::updateMenuLabels()
{
	int i = 0;
	// DIFFICULTY
	switch (options->difficulty)
	{
	case DIFFICULTY_EASY:
		menu.options->setItemCaption(i, lang->getText(59) + ": " + lang->getText(66)); // EASY
		break;

	case DIFFICULTY_NORMAL:
		menu.options->setItemCaption(i, lang->getText(59) + ": " + lang->getText(67)); // NORMAL
		break;

	case DIFFICULTY_HARD:
		menu.options->setItemCaption(i, lang->getText(59) + ": " + lang->getText(68)); // HARD
		break;

	default:
		menu.options->setItemCaption(i, lang->getText(59) + ": " + lang->getText(67)); // NORMAL
		break;
	}

	i++;
	// PLAYER 1 CONTROLS
	menu.options->setItemCaption(i, lang->getText(62));

	i++;
	// PLAYER 1 CONTROLS - OPTIONS
	switch (options->input[0].deviceType)
	{
	case INPUT_USE_KEYBOARD:
		menu.options->setItemCaption(i, lang->getText(69)); // KEYBOARD
		menu.options->setGreyed(i, false);
		break;

	case INPUT_USE_GAMECONTROLLER:
		menu.options->setItemCaption(i, lang->getText(70)); // GAME CONTROLLER
		if (!input->gameControllerFound())
			menu.options->setGreyed(i, true);
		else
		{
			menu.options->setGreyed(i, false);
			menu.options->setItemCaption(i, options->input[0].name);
		}
		break;

	default:
		menu.options->setItemCaption(i, lang->getText(69)); // KEYBOARD
		break;
	}

	i++;
	// PLAYER 2 CONTROLS
	menu.options->setItemCaption(i, lang->getText(63));

	i++;
	// PLAYER 2 CONTROLS - OPTIONS
	switch (options->input[1].deviceType)
	{
	case INPUT_USE_KEYBOARD:
		menu.options->setItemCaption(i, lang->getText(69)); // KEYBOARD
		menu.options->setGreyed(i, false);
		break;

	case INPUT_USE_GAMECONTROLLER:
		menu.options->setItemCaption(i, lang->getText(70)); // GAME CONTROLLER
		if (!input->gameControllerFound())
			menu.options->setGreyed(i, true);
		else
		{
			menu.options->setGreyed(i, false);
			menu.options->setItemCaption(i, options->input[1].name);
		}
		break;

	default:
		menu.options->setItemCaption(i, lang->getText(69)); // KEYBOARD
		break;
	}

	i++;
	// LANGUAGE
	switch (options->language)
	{
	case es_ES:
		menu.options->setItemCaption(i, lang->getText(8) + ": " + lang->getText(24)); // SPANISH
		break;

	case ba_BA:
		menu.options->setItemCaption(i, lang->getText(8) + ": " + lang->getText(25)); // VALENCIAN
		break;

	case en_UK:
		menu.options->setItemCaption(i, lang->getText(8) + ": " + lang->getText(26)); // ENGLISH
		break;

	default:
		menu.options->setItemCaption(i, lang->getText(8) + ": " + lang->getText(26)); // ENGLISH
		break;
	}

	i++;
	// DISPLAY MODE
	menu.options->setItemCaption(i, lang->getText(58));

	i++;
	// DISPLAY MODE - OPTIONS
	switch (options->videoMode)
	{
	case 0:
		menu.options->setItemCaption(i, lang->getText(4)); // WINDOW
		break;

	case SDL_WINDOW_FULLSCREEN:
		menu.options->setItemCaption(i, lang->getText(5)); // FULLSCREEN
		break;

	case SDL_WINDOW_FULLSCREEN_DESKTOP:
		menu.options->setItemCaption(i, lang->getText(6)); // FAKE FULLSCREEN
		break;

	default:
		menu.options->setItemCaption(i, lang->getText(4)); // WINDOW
		break;
	}

	i++;
	// WINDOW SIZE
	menu.options->setItemCaption(i, lang->getText(7) + " x" + std::to_string(options->windowSize)); // WINDOW SIZE

	i++;
	// FILTER
	if (options->filter == FILTER_LINEAL)
		menu.options->setItemCaption(i, lang->getText(60) + ": " + lang->getText(71)); // BILINEAL
	else
		menu.options->setItemCaption(i, lang->getText(60) + ": " + lang->getText(72)); // LINEAL

	i++;
	// VSYNC
	if (options->vSync)
		menu.options->setItemCaption(i, lang->getText(61) + ": " + lang->getText(73)); // ON
	else
		menu.options->setItemCaption(i, lang->getText(61) + ": " + lang->getText(74)); // OFF

	i++;
	// HOW TO PLAY
	menu.options->setItemCaption(i, lang->getText(2));

	i++;
	// ACCEPT
	menu.options->setItemCaption(i, lang->getText(9)); // ACCEPT

	i++;
	// CANCEL
	menu.options->setItemCaption(i, lang->getText(10)); // CANCEL

	// Recoloca el menu de opciones
	menu.options->centerMenuOnX(GAMECANVAS_CENTER_X);
	menu.options->centerMenuOnY(GAMECANVAS_CENTER_Y);
	menu.options->centerMenuElementsOnX();

// Establece las etiquetas del menu de titulo
#ifdef GAME_CONSOLE
	menu.title->setItemCaption(0, lang->getText(0)); // PLAY
#else
	menu.title->setItemCaption(0, lang->getText(51)); // 1 PLAYER
#endif
	menu.title->setItemCaption(1, lang->getText(52)); // 2 PLAYERS
	menu.title->setItemCaption(2, lang->getText(1));  // OPTIONS
	menu.title->setItemCaption(3, lang->getText(3));  // QUIT

	// Recoloca el menu de titulo
	menu.title->centerMenuOnX(GAMECANVAS_CENTER_X);
	menu.title->centerMenuElementsOnX();

	// Establece las etiquetas del menu de seleccion de jugador
	menu.playerSelect->setItemCaption(0, lang->getText(39)); // SELECT PLAYER
	menu.playerSelect->setItemCaption(3, lang->getText(40)); // BACK

	// Recoloca el menu de selección de jugador
	menu.playerSelect->centerMenuOnX(GAMECANVAS_CENTER_X);
	menu.playerSelect->centerMenuElementsOnX();

#ifdef GAME_CONSOLE
	menu.options->setGreyed(1, true);
	menu.options->setSelectable(1, false);
	menu.options->setGreyed(2, true);
	menu.options->setSelectable(2, false);
	menu.options->setGreyed(3, true);
	menu.options->setSelectable(3, false);
	menu.options->setGreyed(4, true);
	menu.options->setSelectable(4, false);
#endif
}

// Aplica las opciones de menu seleccionadas
void Title::applyOptions()
{
	screen->setVideoMode(options->videoMode);

	lang->setLang(options->language);

	updateMenuLabels();
	createTiledBackground();
}

// Bucle para el titulo del juego
void Title::run()
{
	while (section->name == SECTION_PROG_TITLE)
	{
		update();
		checkEvents();
		render();
	}
}

// Ejecuta la parte donde se muestran las instrucciones
void Title::runInstructions(mode_e mode)
{
	instructions = new Instructions(renderer, screen, asset, input, lang, section);
	instructions->run(mode);
	delete instructions;
}

// Ejecuta la parte donde se muestra la tabla de puntuaciones
void Title::runHiScoreTable(mode_hiScoreTable_e mode)
{
	if (!options->online.enabled)
	{
		section->name = SECTION_PROG_TITLE;
		section->subsection = SUBSECTION_TITLE_1;

		return;
	}

	hiScoreTable = new HiScoreTable(renderer, screen, asset, input, lang, options, section);
	hiScoreTable->run(mode);
	delete hiScoreTable;
}

// Ejecuta el juego en modo demo
void Title::runDemoGame()
{
	demoGame = new Game(1, 0, renderer, screen, asset, lang, input, true, options, section);
	demoGame->run();
	delete demoGame;
}

// Introduce el JailerID
void Title::runEnterID()
{
	enterID = new EnterID(renderer, screen, asset, options, section);
	enterID->run();
	delete enterID;
}

// Modifica las opciones para los controles de los jugadores
bool Title::updatePlayerInputs(int numPlayer)
{
	const int numDevices = availableInputDevices.size();

	if (!input->gameControllerFound())
	{ // Si no hay mandos se deja todo de manera prefijada
		deviceIndex[0] = 0;
		deviceIndex[1] = 0;

		options->input[0].id = -1;
		options->input[0].name = "KEYBOARD";
		options->input[0].deviceType = INPUT_USE_KEYBOARD;

		options->input[1].id = 0;
		options->input[1].name = "GAME CONTROLLER";
		options->input[1].deviceType = INPUT_USE_GAMECONTROLLER;

		return true;
	}
	else
	{ // Si hay mas de un dispositivo, se recorre el vector
		if (options->console)
		{
			std::cout << "numplayer:" << numPlayer << std::endl;
			std::cout << "deviceindex:" << deviceIndex[numPlayer] << std::endl;
		}

		// Incrementa el indice
		if (deviceIndex[numPlayer] < numDevices - 1)
		{
			deviceIndex[numPlayer]++;
		}
		else
		{
			deviceIndex[numPlayer] = 0;
		}
		if (options->console)
		{
			std::cout << "deviceindex:" << deviceIndex[numPlayer] << std::endl;
		}

		// Si coincide con el del otro jugador, se lo intercambian
		if (deviceIndex[0] == deviceIndex[1])
		{
			const int theOtherPlayer = (numPlayer + 1) % 2;
			deviceIndex[theOtherPlayer]--;
			if (deviceIndex[theOtherPlayer] < 0)
			{
				deviceIndex[theOtherPlayer] = numDevices - 1;
			}
		}

		// Copia el dispositivo marcado por el indice a la variable de opciones de cada jugador
		options->input[0] = availableInputDevices[deviceIndex[0]];
		options->input[1] = availableInputDevices[deviceIndex[1]];

		return true;
	}
}

// Crea el mosaico de fondo del titulo
void Title::createTiledBackground()
{
	// Crea la textura para el mosaico de fondo
	background = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, GAMECANVAS_WIDTH * 2, GAMECANVAS_HEIGHT * 2);
	if (background == nullptr)
	{
		if (options->console)
		{
			std::cout << "TitleSurface could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
		}
	}

	// Crea los objetos para pintar en la textura de fondo
	Texture *bgTileTexture = new Texture(renderer, asset->get("title_bg_tile.png"));
	Sprite *tile = new Sprite({0, 0, 64, 64}, bgTileTexture, renderer);

	// Prepara para dibujar sobre la textura
	SDL_SetRenderTarget(renderer, background);
	SDL_SetRenderDrawColor(renderer, 0x43, 0x43, 0x4F, 0xFF);
	SDL_RenderClear(renderer);

	// Rellena la textura con el tile
	tile->setSpriteClip(0, 0, 64, 64);
	for (int i = 0; i < 8; ++i)
	{
		for (int j = 0; j < 6; ++j)
		{
			tile->setPosX(i * 64);
			tile->setPosY(j * 64);
			tile->render();
		}
	}

	// Vuelve a colocar el renderizador apuntando a la pantalla
	SDL_SetRenderTarget(renderer, nullptr);

	// Libera la memoria utilizada por los objetos
	bgTileTexture->unload();
	delete bgTileTexture;
	delete tile;
}

// Comprueba cuantos mandos hay conectados para gestionar el menu de opciones
void Title::checkInputDevices()
{
	if (options->console)
	{
		std::cout << "Filling devices for options menu..." << std::endl;
	}
	input->discoverGameController();
	const int numControllers = input->getNumControllers();
	availableInputDevices.clear();
	input_t temp;

	// Añade todos los mandos
	if (numControllers > 0)
		for (int i = 0; i < numControllers; ++i)
		{
			temp.id = i;
			temp.name = input->getControllerName(i);
			temp.deviceType = INPUT_USE_GAMECONTROLLER;
			availableInputDevices.push_back(temp);
			if (options->console)
			{
				std::cout << "Device " << (int)availableInputDevices.size() << " - " << temp.name.c_str() << std::endl;
			}
		}

	// Añade el teclado al final
	temp.id = -1;
	temp.name = "KEYBOARD";
	temp.deviceType = INPUT_USE_KEYBOARD;
	availableInputDevices.push_back(temp);
	if (options->console)
	{
		std::cout << "Device " << (int)availableInputDevices.size() << " - " << temp.name.c_str() << std::endl;
		std::cout << std::endl;
	}
}

// Recarga las texturas
void Title::reLoadTextures()
{
	dustTexture->reLoad();
	coffeeTexture->reLoad();
	crisisTexture->reLoad();
	gradientTexture->reLoad();
	createTiledBackground();
}

// Deshabilita ciertas opciones de los menus
void Title::disableMenuEntries()
{
	// Quita opciones no válidas para jugar en una consola portatil
}