/*

Ejemplo de uso de las unidades incluídas en jail_engine
Código fuente creado por JailDesigner

*/

#include <SDL2/SDL.h>
#include <iostream>
#include "units/jail_audio.h"
#include "units/text.h"
#include "units/utils.h"
#include "units/asset.h"
#include "units/movingsprite.h"
#include "units/texture.h"
#include "units/screen.h"
#include "units/input.h"

SDL_Event *event;
SDL_Window *window;
SDL_Renderer *renderer;
Uint32 ticks = 0;
Uint32 ticksSpeed = 15;
int counter = 0;
int gradColorMin = 64;		 // Minimo color más alto del degradado
int gradColorMax = 192;		 // Minimo color más alto del degradado
int gradCurrentColor = 192;	 // Color actual más alto del degradado
int gradBreathDirection = 0; // Indica si gradCurrentColor crece o decrece

int main(int argc, char *argv[])
{
	// Inicializa las opciones
	struct options_t *options = new options_t;
	initOptions(options);
	options->screen.nativeWidth = 320;
	options->screen.nativeHeight = 240;
	options->screen.nativeZoom = 2;
	options->screen.windowZoom = 1;
	options->console = true;

	// Inicializa la lista de recursos
	Asset *asset = new Asset(argv[0]);
	asset->add("/data/music.ogg", t_music);
	asset->add("/data/sound.wav", t_sound);
	asset->add("/data/smb2.txt", t_font);
	asset->add("/data/smb2.png", t_bitmap);
	asset->add("/data/debug.txt", t_font);
	asset->add("/data/debug.png", t_bitmap);
	asset->add("/data/z80.png", t_bitmap);
	asset->add("/data/notify.png", t_bitmap);
	asset->add("/data/notify.wav", t_sound);
	asset->add("/data/gamecontrollerdb.txt", t_data);
	asset->setVerbose(options->console);
	if (!asset->check())
	{
		exit(EXIT_FAILURE);
	}

	// Inicializa SDL y la ventana
	SDL_Init(SDL_INIT_EVERYTHING);
	window = SDL_CreateWindow("Jail Engine DEMO", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, options->screen.nativeWidth * options->screen.nativeZoom * options->screen.windowZoom, options->screen.nativeHeight * options->screen.nativeZoom * options->screen.windowZoom, SDL_WINDOW_SHOWN);
	// window = SDL_CreateWindow("jail_engine_demo", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 320, 240, SDL_WINDOW_SHOWN);
	if (window != nullptr)
	{
		renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
		if (renderer != nullptr)
		{
			SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
		}
		else
		{
			exit(EXIT_FAILURE);
		}
	}
	else
	{
		exit(EXIT_FAILURE);
	}
	event = new SDL_Event();

	// Inicializa jail_audio
	JA_Init(48000, AUDIO_S16, 2);
	JA_Music_t *music;
	JA_Sound_t *sound;
	music = JA_LoadMusic(asset->get("music.ogg").c_str());
	sound = JA_LoadSound(asset->get("sound.wav").c_str());

	// Inicializa el objeto screen
	Screen *screen = new Screen(window, renderer, options);
	screen->addNotifier(asset->get("notify.png"), asset->get("smb2.png"), asset->get("smb2.txt"), asset->get("notify.wav"));

	// Inicializa el objeto input
	Input *input = new Input(asset->get("gamecontrollerdb.txt"), options->console);
	string controllerName = input->getNumControllers() > 0 ? input->getControllerName(0) : "No se ha encontrado ningun mando";

	// Inicializa el texto
	Text *text = new Text(asset->get("smb2.txt"), asset->get("smb2.png"), renderer);
	Text *debugText = new Text(asset->get("debug.txt"), asset->get("debug.png"), renderer);

	// Inicializa el sprite
	Texture *texture = new Texture(renderer, asset->get("z80.png"));
	MovingSprite *sprite = new MovingSprite();
	sprite->setRenderer(renderer);
	sprite->setTexture(texture);
	sprite->setPosX(140);
	sprite->setPosY(100);
	sprite->setWidth(16);
	sprite->setHeight(32);
	sprite->setSpriteClip({0, 0, 16, 32});
	sprite->setVelX(1);
	sprite->setVelY(2);

	// Bucle principal
	// JA_PlayMusic(music, true);
	bool should_exit = false;
	while (!should_exit)
	{

		// Comprueba el teclado y los eventos
		while (SDL_PollEvent(event))
		{
			if (event->type == SDL_QUIT)
			{
				should_exit = true;
				break;
			}
			if (event->type == SDL_KEYDOWN)
			{
				switch (event->key.keysym.scancode)
				{

				case SDL_SCANCODE_ESCAPE:
					should_exit = true;
					break;

				case SDL_SCANCODE_F1:
					screen->decWindowSize();
					break;

				case SDL_SCANCODE_F2:
					screen->incWindowSize();
					break;

				case SDL_SCANCODE_N:
					screen->showNotification("Ejemplo de notificacion", "con 2 lineas de texto", 0);
					break;

				default:
					break;
				}
			}
		}
		string inputPressed = "";
		if (input->checkInput(INPUT_LEFT))
		{
			inputPressed = "Izquierda";
		}
		if (input->checkInput(INPUT_RIGHT))
		{
			inputPressed = "Derecha";
		}
		if (input->checkInput(INPUT_UP))
		{
			inputPressed = "Arriba";
		}
		if (input->checkInput(INPUT_DOWN))
		{
			inputPressed = "Abajo";
		}

		// Actualiza la lógica del programa
		if (SDL_GetTicks() - ticks > ticksSpeed)
		{
			// Actualiza la variable
			ticks = SDL_GetTicks();

			// Incrementa el contador
			counter++;

			// Actualiza el objeto screen
			screen->update();

			// Actualiza el sprite
			if (sprite->getPosX() + sprite->getWidth() > options->screen.nativeWidth or sprite->getPosX() < 0)
			{
				sprite->undoMoveX();
				int spr_direction = 1;
				int spr_force = 1;
				if (sprite->getVelX() > 0)
				{
					spr_direction = -1;
				}
				if (SDL_GetTicks() % 2 == 0)
				{
					spr_force = 2;
				}
				sprite->setVelX(spr_force * spr_direction);
				JA_PlaySound(sound);
			}
			if (sprite->getPosY() + sprite->getHeight() > options->screen.nativeHeight or sprite->getPosY() < 0)
			{
				sprite->undoMoveY();
				int spr_direction = 1;
				int spr_force = 1;
				if (sprite->getVelY() > 0)
				{
					spr_direction = -1;
				}
				if (SDL_GetTicks() % 2 == 0)
				{
					spr_force = 2;
				}
				sprite->setVelY(spr_force * spr_direction);
				JA_PlaySound(sound);
			}
			sprite->update();

			// Actualiza el degradado
			if (counter % 1 == 0)
			{
				gradBreathDirection == 0 ? gradCurrentColor-- : gradCurrentColor++;
				if (gradCurrentColor == gradColorMin)
				{
					gradBreathDirection = 1;
				}
				if (gradCurrentColor == gradColorMax)
				{
					gradBreathDirection = 0;
				}
			}
		}

		// Dibuja en pantalla
		screen->start();
		screen->clean();

		// Dibuja un degradado de fondo
		const int gradFirstLine = options->screen.nativeHeight / 3;
		const int gradLastLine = options->screen.nativeHeight;
		const int gradNumLines = gradLastLine - gradFirstLine;
		const int gradColorFrom = 0;

		for (int i = gradFirstLine; i < gradLastLine; ++i)
		{
			float step = ((float)(i - gradFirstLine) / gradNumLines);
			int color = gradColorFrom + ((gradCurrentColor - gradColorFrom) * step);
			SDL_SetRenderDrawColor(renderer, color, 0x00, 0x00, 0xFF);
			SDL_RenderDrawLine(renderer, 0, i, options->screen.nativeWidth, i);
		}

		for (int i = gradLastLine; i > gradFirstLine; --i)
		{
			float step = ((float)(i - gradFirstLine) / gradNumLines);
			int alpha = 0 + ((255 - 0) * step);
			SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0xFF, alpha);
			SDL_RenderDrawLine(renderer, 0, gradLastLine - i, options->screen.nativeWidth, gradLastLine - i);
		}

		// Dibuja el sprite
		sprite->render();

		// Escribe el texto
		text->setZoom(2);
		text->writeDX(TXT_CENTER | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize(), "Jail Engine DEMO", 1, {255, 255, 255}, 1, {0, 0, 192});
		text->disableZoom();
		text->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 4, "2023 JailDesigner", 1, {240, 240, 240}, 1, {0, 0, 192});
		debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 7, "Pulsa 'F1' o 'F2' para disminuir o aumentar la ventana", 1, {240, 240, 240}, 1, {0, 0, 192});
		debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 9, "Pulsa 'N' para mostrar una notificacion", 1, {240, 240, 240}, 1, {0, 0, 192});
		debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 11, controllerName, 1, {240, 240, 240}, 1, {0, 0, 192});
		debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, text->getCharacterSize() * 13, inputPressed, 1, {240, 240, 240}, 1, {0, 0, 192});
		debugText->writeDX(TXT_CENTER | TXT_COLOR | TXT_STROKE, options->screen.nativeWidth / 2, options->screen.nativeHeight - (text->getCharacterSize() * 2), "Pulsa 'ESCAPE' para terminar el programa", 1, {240, 240, 240}, 1, {0, 0, 192});

		// Vuelca el buffer en pantalla
		screen->blit();
	}

	// Finaliza el sprite
	if (sprite != nullptr)
	{
		delete sprite;
	}
	if (texture != nullptr)
	{
		delete texture;
	}

	// Finaliza el texto
	if (text != nullptr)
	{
		delete text;
	}
	if (debugText != nullptr)
	{
		delete debugText;
	}

	// Finaliza el objeto input
	if (input != nullptr)
	{
		delete input;
	}

	// Finaliza el objeto screen
	if (screen != nullptr)
	{
		delete screen;
	}

	// Finaliza jail_audio
	JA_DeleteSound(sound);
	JA_DeleteMusic(music);

	// Finaliza el objeto con la lista de recuros
	if (asset != nullptr)
	{
		delete asset;
	}

	// Finaliza las opciones
	if (options != nullptr)
	{
		delete options;
	}

	// Finaliza SDL y la ventana
	if (event != nullptr)
	{
		delete event;
	}
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	SDL_Quit();

	return 0;
}
