#include "hiscore_table.h"
#include "common/jscore.h"
#include <iostream>

const Uint8 SELF = 0;

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

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

	text = new Text(asset->get("smb2.png"), asset->get("smb2.txt"), renderer);

	// Crea un backbuffer para el renderizador
	backbuffer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT);
	if (backbuffer == nullptr)
	{
		if (options->console)
		{
			std::cout << "Error: textTexture could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
		}
	}

	// Inicializa variables
	section->name = SELF;
	ticks = 0;
	ticksSpeed = 15;
	manualQuit = false;
	counter = 0;
	counterEnd = 600;
}

// Destructor
HiScoreTable::~HiScoreTable()
{
	delete eventHandler;
	delete text;

	SDL_DestroyTexture(backbuffer);
}

// Actualiza las variables
void HiScoreTable::update()
{
	// Comprueba los eventos
	checkEventHandler();

	// Comprueba las entradas
	checkInput();

	// Actualiza las variables
	if (SDL_GetTicks() - ticks > ticksSpeed)
	{
		// Actualiza el contador de ticks
		ticks = SDL_GetTicks();

		if (mode == mhst_auto)
		{ // Modo automático
			counter++;

			if (counter == counterEnd)
			{
				section->name = SECTION_PROG_TITLE;
				section->subsection = SUBSECTION_TITLE_1;
			}
		}
		else
		{ // Modo manual
			++counter %= 60000;

			if (manualQuit)
			{
				section->name = SECTION_PROG_TITLE;
				section->subsection = SUBSECTION_TITLE_3;
			}
		}
	}
}

// Pinta en pantalla
void HiScoreTable::render()
{
	// Pinta en pantalla
	SDL_Rect window = {0, 0, GAMECANVAS_WIDTH, GAMECANVAS_HEIGHT};

	const color_t orangeColor = {0xFF, 0x7A, 0x00};
	// hay 27 letras - 7 de puntos quedan 20 caracteres 20 - nameLenght 0 numDots
	const int spaceBetweenHeader = 32;
	const int spaceBetweenLines = text->getCharacterSize() * 1.8f;

	// Pinta en el backbuffer el texto y los sprites
	SDL_SetRenderTarget(renderer, backbuffer);
	SDL_SetRenderDrawColor(renderer, bgColor.r, bgColor.g, bgColor.b, 255);
	SDL_RenderClear(renderer);

	// Escribe el texto: Mejores puntuaciones
	text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, 8, lang->getText(42), 1, orangeColor, 1, shdwTxtColor);

	// Escribe la lista de jugadores
	int numUsers = jscore::getNumUsers();
	for (int i = 0; i < numUsers; ++i)
	{
		const std::string userName = jscore::getUserName(i).substr(0, 17);
		const int nameLenght = (int)userName.length();
		const int numDots = 20 - nameLenght;
		std::string dots = "";
		for (int j = 0; j < numDots; ++j)
		{
			dots = dots + ".";
		}
		const std::string line = userName + dots + scoreToString(jscore::getPoints(i));
		text->writeDX(TXT_CENTER | TXT_SHADOW, GAMECANVAS_CENTER_X, (i * spaceBetweenLines) + spaceBetweenHeader, line, 1, orangeColor, 1, shdwTxtColor);
	}

	// Rellena la lista con otros nombres
	if (numUsers < 10)
	{
		std::vector<std::string> names;
		names.insert(names.end(), {"Bry", "Usufondo", "G.Lucas", "P.Delgat", "P.Arrabalera", "Pelechano", "Sahuquillo", "Bacteriol", "Pepe", "Rosita"});

		for (int i = numUsers; i < 10; ++i)
		{
			const int nameLenght = names[i - numUsers].length();
			const int numDots = 20 - nameLenght;
			std::string dots = "";
			for (int j = 0; j < numDots; ++j)
			{
				dots = dots + ".";
			}
			const std::string line = names[i - numUsers] + dots + "0000000";
			text->writeDX(TXT_CENTER | TXT_SHADOW, GAMECANVAS_CENTER_X, (i * spaceBetweenLines) + spaceBetweenHeader, line, 1, orangeColor, 1, shdwTxtColor);
		}
	}

	if ((mode == mhst_manual) && (counter % 50 > 14))
	{
		text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, GAMECANVAS_CENTER_X, GAMECANVAS_HEIGHT - 12, lang->getText(22), 1, orangeColor, 1, shdwTxtColor);
	}

	// Cambia el destino de renderizado
	SDL_SetRenderTarget(renderer, nullptr);

	// Prepara para empezar a dibujar en la textura de juego
	screen->start();

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

	// Establece la ventana del backbuffer
	if (mode == mhst_auto)
	{
		window.y = std::max(8, GAMECANVAS_HEIGHT - counter + 100);
	}
	else
	{
		window.y = 0;
	}

	// Copia el backbuffer al renderizador
	SDL_RenderCopy(renderer, backbuffer, nullptr, &window);

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

// Comprueba los eventos
void HiScoreTable::checkEventHandler()
{
	// 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;
		}
	}
}

// Comprueba las entradas
void HiScoreTable::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();
	}

	else if (input->checkInput(input_pause, REPEAT_FALSE) || input->checkInput(input_accept, REPEAT_FALSE) || input->checkInput(input_fire_left, REPEAT_FALSE) || input->checkInput(input_fire_center, REPEAT_FALSE) || input->checkInput(input_fire_right, REPEAT_FALSE))
	{
		if (mode == mhst_auto)
		{
			JA_StopMusic();
			section->name = SECTION_PROG_TITLE;
			section->subsection = SUBSECTION_TITLE_1;
		}
		else
		{
			if (counter > 30)
			{
				manualQuit = true;
			}
		}
	}
}

// Bucle para la pantalla de instrucciones
void HiScoreTable::run(mode_hiScoreTable_e mode)
{
	this->mode = mode;

	while (section->name == SELF)
	{
		update();
		render();
	}
}

// Transforma un valor numérico en una cadena de 6 cifras
std::string HiScoreTable::scoreToString(Uint32 num)
{
	if ((num >= 0) && (num <= 9))
	{
		return ("000000" + std::to_string(num));
	}

	if ((num >= 10) && (num <= 99))
	{
		return ("00000" + std::to_string(num));
	}

	if ((num >= 100) && (num <= 999))
	{
		return ("0000" + std::to_string(num));
	}

	if ((num >= 1000) && (num <= 9999))
	{
		return ("000" + std::to_string(num));
	}

	if ((num >= 010000) && (num <= 99999))
	{
		return ("00" + std::to_string(num));
	}

	if ((num >= 100000) && (num <= 999999))
	{
		return ("0" + std::to_string(num));
	}

	if ((num >= 1000000) && (num <= 9999999))
	{
		return (std::to_string(num));
	}

	return (std::to_string(num));
}