#pragma once

#include <SDL2/SDL.h>
#include "common/asset.h"
#include "common/debug.h"
#include "common/jail_audio.h"
#include "common/screen.h"
#include "common/sprite.h"
#include "common/utils.h"
#include "const.h"
#include "enemy.h"
#include "item_tracker.h"
#include "item.h"
#include <string>
#include <vector>

#ifndef ROOM_H
#define ROOM_H

enum tile_e
{
	t_empty,
	t_wall,
	t_passable,
	t_slope_l,
	t_slope_r,
	t_kill,
	t_animated
};

struct aTile_t
{
	Sprite *sprite; // Sprite para dibujar el tile
	int xcOrig;		// Poicion X donde se encuentra el primer tile de la animacion en la tilesheet
};

struct room_t
{
	std::string number;			  // Numero de la habitación
	std::string name;			  // Nombre de la habitación
	std::string bgColor;		  // Color de fondo de la habitación
	std::string borderColor;	  // Color del borde de la pantalla
	std::string itemColor1;		  // Color 1 para los items de la habitación
	std::string itemColor2;		  // Color 2 para los items de la habitación
	std::string roomUp;			  // Identificador de la habitación que se encuentra arriba
	std::string roomDown;		  // Identificador de la habitación que se encuentra abajp
	std::string roomLeft;		  // Identificador de la habitación que se encuentra a la izquierda
	std::string roomRight;		  // Identificador de la habitación que se encuentra a la derecha
	std::string tileSetFile;	  // Imagen con los graficos para la habitación
	std::string tileMapFile;	  // Fichero con el mapa de indices de tile
	std::vector<int> *tileMap;	  // Indice de los tiles a dibujar en la habitación
	int autoSurfaceDirection;	  // Sentido en el que arrastran las superficies automáticas de la habitación
	std::vector<enemy_t> enemies; // Listado con los enemigos de la habitación
	std::vector<item_t> items;	  // Listado con los items que hay en la habitación
	Texture *textureA;			  // Textura con los graficos de la habitación
	Texture *textureB;			  // Textura con los graficos de la habitación
};

// Carga las variables desde un fichero de mapa
room_t loadRoomFile(std::string file, bool verbose = false);

// Carga las variables y texturas desde un fichero de mapa de tiles
std::vector<int> loadRoomTileFile(std::string file_path, bool verbose = false);

// Asigna variables a partir de dos cadenas
bool setVars(room_t *room, std::string var, std::string value);

// Asigna variables a una estructura enemy_t
bool setEnemy(enemy_t *enemy, std::string var, std::string value);

// Asigna variables a una estructura item_t
bool setItem(item_t *item, std::string var, std::string value);

class Room
{
private:
	// Objetos y punteros
	std::vector<Enemy *> enemies; // Listado con los enemigos de la habitación
	std::vector<Item *> items;	  // Listado con los items que hay en la habitación
	Texture *texture;			  // Textura con los graficos de la habitación
	Texture *textureA;			  // Textura con los graficos de la habitación
	Texture *textureB;			  // Textura con los graficos de la habitación
	Asset *asset;				  // Objeto con la ruta a todos los ficheros de recursos
	Screen *screen;				  // Objeto encargado de dibujar en pantalla
	ItemTracker *itemTracker;	  // Lleva el control de los objetos recogidos
	SDL_Renderer *renderer;		  // El renderizador de la ventana
	SDL_Texture *mapTexture;	  // Textura para dibujar el mapa de la habitación
	int *itemsPicked;			  // Puntero a la cantidad de items recogidos que lleva el juego
	Debug *debug;				  // Objeto para gestionar la información de debug
	options_t *options;			  // Puntero a las opciones del juego

	// Variables
	std::string number;					  // Numero de la habitación
	std::string name;					  // Nombre de la habitación
	std::string bgColor;				  // Color de fondo de la habitación
	std::string borderColor;			  // Color del borde de la pantalla
	std::string itemColor1;				  // Color 1 para los items de la habitación
	std::string itemColor2;				  // Color 2 para los items de la habitación
	std::string roomUp;					  // Identificador de la habitación que se encuentra arriba
	std::string roomDown;				  // Identificador de la habitación que se encuentra abajp
	std::string roomLeft;				  // Identificador de la habitación que se encuentra a la izquierda
	std::string roomRight;				  // Identificador de la habitación que se encuentra a la derecha
	std::string tileSetFile;			  // Imagen con los graficos para la habitación
	std::string tileMapFile;			  // Fichero con el mapa de indices de tile
	std::vector<int> tileMap;			  // Indice de los tiles a dibujar en la habitación
	int autoSurfaceDirection;			  // Sentido en el que arrastran las superficies automáticas de la habitación
	JA_Sound_t *itemSound;				  // Sonido producido al coger un objeto
	std::vector<h_line_t> bottomSurfaces; // Lista con las superficies inferiores de la habitación
	std::vector<h_line_t> topSurfaces;	  // Lista con las superficies superiores de la habitación
	std::vector<v_line_t> leftSurfaces;	  // Lista con las superficies laterales de la parte izquierda de la habitación
	std::vector<v_line_t> rightSurfaces;  // Lista con las superficies laterales de la parte derecha de la habitación
	std::vector<d_line_t> leftSlopes;	  // Lista con todas las rampas que suben hacia la izquierda
	std::vector<d_line_t> rightSlopes;	  // Lista con todas las rampas que suben hacia la derecha
	int counter;						  // Contador para lo que haga falta
	bool paused;						  // Indica si el mapa esta en modo pausa
	std::vector<aTile_t> aTile;			  // Vector con los indices de tiles animados
	std::vector<h_line_t> autoSurfaces;	  // Lista con las superficies automaticas de la habitación
	int tileSize;						  // Ancho del tile en pixels
	int mapWidth;						  // Ancho del mapa en tiles
	int mapHeight;						  // Alto del mapa en tiles
	int tileSetWidth;					  // Ancho del tileset en tiles
	bool jailEnabled;					  // Indica si hay acceso a la Jail

	// Pinta el mapa de la habitación en la textura
	void fillMapTexture();

	// Calcula las superficies inferiores
	void setBottomSurfaces();

	// Calcula las superficies superiores
	void setTopSurfaces();

	// Calcula las superficies laterales izquierdas
	void setLeftSurfaces();

	// Calcula las superficies laterales derechas
	void setRightSurfaces();

	// Encuentra todas las rampas que suben hacia la izquierda
	void setLeftSlopes();

	// Encuentra todas las rampas que suben hacia la derecha
	void setRightSlopes();

	// Calcula las superficies automaticas
	void setAutoSurfaces();

	// Localiza todos los tiles animados de la habitación
	void setAnimatedTiles();

	// Actualiza los tiles animados
	void updateAnimatedTiles();

	// Pinta los tiles animados en pantalla
	void renderAnimatedTiles();

	// Devuelve el tipo de tile que hay en ese indice
	tile_e getTile(int index);

	// Abre la jail para poder entrar
	void openTheJail();

public:
	// Constructor
	Room(room_t *room, SDL_Renderer *renderer, Screen *screen, Asset *asset, options_t *options, ItemTracker *itemTracker, int *itemsPicked, bool jailEnabled, Debug *debug);

	// Destructor
	~Room();

	// Devuelve el nombre de la habitación
	std::string getName();

	// Devuelve el color de la habitación
	color_t getBGColor();

	// Devuelve el color del borde
	color_t getBorderColor();

	// Dibuja el mapa en pantalla
	void renderMap();

	// Dibuja los enemigos en pantalla
	void renderEnemies();

	// Dibuja los objetos en pantalla
	void renderItems();

	// Actualiza las variables y objetos de la habitación
	void update();

	// Devuelve la cadena del fichero de la habitación contigua segun el borde
	std::string getRoom(int border);

	// Devuelve el tipo de tile que hay en ese pixel
	tile_e getTile(SDL_Point point);

	// Indica si hay colision con un enemigo a partir de un rectangulo
	bool enemyCollision(SDL_Rect &rect);

	// Indica si hay colision con un objeto a partir de un rectangulo
	bool itemCollision(SDL_Rect &rect);

	// Recarga la textura
	void reLoadTexture();

	// Recarga la paleta
	void reLoadPalette();

	// Obten el tamaño del tile
	int getTileSize();

	// Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile
	int getSlopeHeight(SDL_Point p, tile_e slope);

	// Comprueba las colisiones
	int checkRightSurfaces(SDL_Rect *rect);

	// Comprueba las colisiones
	int checkLeftSurfaces(SDL_Rect *rect);

	// Comprueba las colisiones
	int checkTopSurfaces(SDL_Rect *rect);

	// Comprueba las colisiones
	int checkBottomSurfaces(SDL_Rect *rect);

	// Comprueba las colisiones
	int checkAutoSurfaces(SDL_Rect *rect);

	// Comprueba las colisiones
	bool checkTopSurfaces(SDL_Point *p);

	// Comprueba las colisiones
	bool checkAutoSurfaces(SDL_Point *p);

	// Comprueba las colisiones
	int checkLeftSlopes(v_line_t *line);

	// Comprueba las colisiones
	bool checkLeftSlopes(SDL_Point *p);

	// Comprueba las colisiones
	int checkRightSlopes(v_line_t *line);

	// Comprueba las colisiones
	bool checkRightSlopes(SDL_Point *p);

	// Pone el mapa en modo pausa
	void pause();

	// Quita el modo pausa del mapa
	void resume();

	// Obten la direccion de las superficies automaticas
	int getAutoSurfaceDirection();
};

#endif
