/*
This source code copyrighted by JailDesigner (2020)
started on Castalla 15-07-2020.
Using some sample source code from Lazy Foo' Productions
*/

/*Descripción del enfoque utilizado para crear el juego.

El programa contine una serie de clases/objetos básicos: la clase sprite
permite dibujar partes de un fichero png en pantalla. La clase spriteanimated
contiene funcionalidad adicional para crear animaciones. La clase text permite
dibujar letras de un png en pantalla a partir de una cadena de texto. La clase
menu permite crear una estructura con diferentes elementos, escribirlos en
pantalla y seleccionar uno de ellos.

A continuación tenemos las clases enfocadas a la lógica del juego, la clase player
contiene la información del jugador, la clase balloon la de los enemigos y la
clase bullet para las balas que dispara el jugador. La clase background es
muy simple y sirve para pintar el fondo de la pantalla. Por ultimo, la clase
gamedirector es la que realiza toda la lógica y se encarga de hacer interactuar
al resto de objetos entre si.

El objeto gamedirector tiene tres estados: titulo, juego y pausa. Segun su estado
el bucle que recorre es distinto. En el bucle juego, el objeto gamedirector
tiene un objeto jugador, un vector con los objetos globo y un vector con los
objetos bala. Se encarga de comprobar las entradas de teclado o gamepad para
cerrar la aplicacion, saltar al estado de pausa y para mover al jugador. Recorre
el vector de globos y de balas y si tienen algun tipo asignado las gestiona.
Comprueba las colisiones entre los globos y el jugador y entre las balas y los
globos. Tiene ademas un nivel de amenaza que calcula en funcion del numero de globos
en pantalla y que se va incrementando conforme aumenta la puntuación del jugador.

Los objetos globo tienen varios contadores para alternar de un estado a otro.

En los vectores que contienen objetos, se considera activos los objetos que tienen
un tipo asociado diferente a NO_KIND
*/
#define TEST_

#include <SDL.h>
#include <SDL_image.h>
#include <SDL_mixer.h>
#include <stdio.h>
#include <string>
#include "const.h"
#include "struct.h"
#include "ltexture.h"
#include "globals.h"
#include "sprite.h"
#include "spriteanimated.h"
#include "player.h"
#include "balloon.h"
#include "bullet.h"
#include "background.h"
#include "text.h"
#include "menu.h"
#include "gamedirector.h"
#include "ltexture.cpp"
#include "sprite.cpp"
#include "spriteanimated.cpp"
#include "player.cpp"
#include "balloon.cpp"
#include "bullet.cpp"
#include "background.cpp"
#include "text.cpp"
#include "menu.cpp"
#include "gamedirector.cpp"

//Arranca SDL y crea la ventana
bool init();

//Carga todos los recursos
bool loadMedia();

//Libera todos los recursos y cierra SDL
void close();

//Arranca SDL y crea la ventana
bool init()
{
	//Indicador de inicialización
	bool success = true;

	//Inicializa SDL
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO) < 0)
	{
		printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
		success = false;
	}
	else
	{
		//Establece el filtro de la textura a nearest
		if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"))
		{
			printf("Warning: Nearest texture filtering not enabled!");
		}

		//Inicializa SDL_mixer
		if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0)
		{
			printf("SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError());
			success = false;
		}

		//Comprueba los mandos
		if (SDL_NumJoysticks() < 1)
		{
			printf("Warning: No joysticks connected!\n");
		}
		else
		{
			//Carga el mando
			gGameController = SDL_JoystickOpen(0);
			if (gGameController == NULL)
			{
				printf("Warning: Unable to open game controller! SDL Error: %s\n", SDL_GetError());
			}
			printf("%i joysticks were found.\n", SDL_NumJoysticks());
			std::cout << SDL_JoystickNumButtons(gGameController) << " buttons\n";
		}

		//Crea la ventana
		gWindow = SDL_CreateWindow("Super Popping (Like Loc) in Jailers World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, VIEW_WIDTH, VIEW_HEIGHT, SDL_WINDOW_SHOWN);
		if (gWindow == NULL)
		{
			printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
			success = false;
		}
		else
		{
			//Crea un renderizador para la ventana con vsync
			gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
			if (gRenderer == NULL)
			{
				printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
				success = false;
			}
			else
			{
				//Inicializa el color de renderizado
				SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0xFF);

				//Establece el tamaño del buffer de renderizado
				SDL_RenderSetLogicalSize(gRenderer, SCREEN_WIDTH, SCREEN_HEIGHT);

				//Inicializa el cargador de PNG
				int imgFlags = IMG_INIT_PNG;
				if (!(IMG_Init(imgFlags) & imgFlags))
				{
					printf("SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError());
					success = false;
				}
			}
		}
	}

	return success;
}

//Carga todos los recursos
bool loadMedia()
{
	//Indicador de éxito en la carga
	bool success = true;

	//Carga los gráficos del jugador
	if (!gPlayerTexture.loadFromFile("media/gfx/player.png"))
	{
		printf("Failed to load player texture!\n");
		success = false;
	}

	//Carga los gráficos de los globos
	if (!gBalloonTexture.loadFromFile("media/gfx/balloon.png"))
	{
		printf("Failed to load balloon texture!\n");
		success = false;
	}

	//Carga los gráficos de las balas
	if (!gBulletTexture.loadFromFile("media/gfx/bullet.png"))
	{
		printf("Failed to load bullet texture!\n");
		success = false;
	}

	//Carga los gráficos del fondo del juego
	if (!gGameBackgroundTexture.loadFromFile("media/gfx/background.png"))
	{
		printf("Failed to load game background texture!\n");
		success = false;
	}

	//Carga los gráficos del fondo de la pantalla de titulo
	if (!gTitleBackgroundTexture.loadFromFile("media/gfx/title.png"))
	{
		printf("Failed to load title texture!\n");
		success = false;
	}

	//Carga varios gráficos para varios propósitos
	if (!gMiscTexture.loadFromFile("media/gfx/misc.png"))
	{
		printf("Failed to load misc texture!\n");
		success = false;
	}

	//Carga los gráficos para el menu
	if (!gMenuTexture.loadFromFile("media/gfx/menu.png"))
	{
		printf("Failed to load menu texture!\n");
		success = false;
	}

	//Carga los gráficos para el texto blanco
	if (!gWhiteFontTexture.loadFromFile("media/gfx/white_font.png"))
	{
		printf("Failed to load white font texture!\n");
		success = false;
	}

	//Carga los gráficos para el texto negro
	if (!gBlackFontTexture.loadFromFile("media/gfx/black_font.png"))
	{
		printf("Failed to load black font texture!\n");
		success = false;
	}

	//Carga la música del titulo
	gTitleMusic = Mix_LoadMUS("media/music/title.ogg");
	if (gTitleMusic == NULL)
	{
		printf("Failed to load title music! SDL_mixer Error: %s\n", Mix_GetError());
		success = false;
	}

	//Carga la música del juego
	gPlayingMusic = Mix_LoadMUS("media/music/playing.ogg");
	if (gPlayingMusic == NULL)
	{
		printf("Failed to load playing music! SDL_mixer Error: %s\n", Mix_GetError());
		success = false;
	}

	//Carga los efectos de sonido para la explosión de los globos
	gPopBalloonFX = Mix_LoadWAV("media/sound/balloon.wav");
	if (gPopBalloonFX == NULL)
	{
		printf("Failed to load balloon sound effect! SDL_mixer Error: %s\n", Mix_GetError());
		success = false;
	}

	//Carga los efectos de sonido para los disparos del jugador
	gBulletFX = Mix_LoadWAV("media/sound/bullet.wav");
	if (gBulletFX == NULL)
	{
		printf("Failed to load bullet sound effect! SDL_mixer Error: %s\n", Mix_GetError());
		success = false;
	}

	return success;
}

//Libera todos los recursos y cierra SDL
void close()
{
	//Libera todas las imagenes
	gPlayerTexture.free();
	gGameBackgroundTexture.free();
	gTitleBackgroundTexture.free();
	gWhiteFontTexture.free();
	gBlackFontTexture.free();
	gMenuTexture.free();
	gBalloonTexture.free();
	gMiscTexture.free();

	//Libera los efectos de sonido
	Mix_FreeChunk(gPopBalloonFX);
	Mix_FreeChunk(gBulletFX);
	gPopBalloonFX = NULL;
	gBulletFX = NULL;

	//Libra la música
	Mix_FreeMusic(gTitleMusic);
	gTitleMusic = NULL;
	Mix_FreeMusic(gPlayingMusic);
	gPlayingMusic = NULL;

	//Libera el mando
	SDL_JoystickClose(gGameController);
	gGameController = NULL;

	//Destruye la ventana
	SDL_DestroyRenderer(gRenderer);
	SDL_DestroyWindow(gWindow);
	gWindow = NULL;
	gRenderer = NULL;

	//Sal del subsistema SDL
	IMG_Quit();
	SDL_Quit();
}

int main(int argc, char *args[])
{
	//Arranca SDL y crea la ventana
	if (!init())
	{
		printf("Failed to initialize!\n");
		return -1;
	}
	else
	{
		//Carga los recursos
		if (!loadMedia())
		{
			printf("Failed to load media!\n");
		}
		else
		{
			//Crea el objeto gameDirector
			GameDirector gameDirector;

			//Inicializa el objeto gameDirector
			gameDirector.init();

#ifdef TEST
			gameDirector.resetBalloons();
#endif

			//Mientras no se quiera salir del juego
			while (!(gameDirector.getGameStatus() == GAME_STATE_QUIT))
			{
				switch (gameDirector.getGameStatus())
				{
				case GAME_STATE_TITLE:
					gameDirector.runTitle();
					break;

				case GAME_STATE_PLAYING:
					gameDirector.runGame();
					break;

				case GAME_STATE_PAUSED:
					gameDirector.runPausedGame();
					break;
				}
			}
		}

		//Libera todos los recursos y cierra SDL
		close();

		return 0;
	}
}