#pragma once

#include <SDL2/SDL.h>
#include "asset.h"
#include "input.h"
#include "jail_audio.h"
#include "sprite.h"
#include "text.h"
#include "utils.h"
#include <fstream>
#include <sstream>
#include <vector>

#ifndef MENU_H
#define MENU_H

// Tipos de fondos para el menu
#define MENU_BACKGROUND_TRANSPARENT 0
#define MENU_BACKGROUND_SOLID 1

// Tipos de archivos de audio
#define SOUND_ACCEPT 0
#define SOUND_MOVE 1
#define SOUND_CANCEL 2

// Opciones de menu
#define MENU_NO_OPTION -1

// Clase Menu
class Menu
{
private:
	struct rectangle_t
	{
		SDL_Rect rect; // Rectangulo
		color_t color; // Color
		int a;		   // Transparencia
	};

	struct item_t
	{
		std::string label; // Texto
		SDL_Rect rect;	   // Rectangulo que delimita el elemento
		int hPaddingDown;  // Espaciado bajo el elemento
		bool selectable;   // Indica si se puede seleccionar
		bool greyed;	   // Indica si ha de aparecer con otro color mas oscuro
		bool linkedDown;   // Indica si el elemento actual y el siguiente se tratan como uno solo. Afecta al selector
		bool linkedUp;	   // Indica si el elemento actual y el anterior se tratan como uno solo. Afecta al selector
		bool visible;	   // Indica si el elemento es visible
	};

	struct selector_t
	{
		float originY;	   // Coordenada de origen
		float targetY;	   // Coordenada de destino
		float despY;	   // Cantidad de pixeles que se desplaza el selector en cada salto: (target - origin) / numJumps
		bool moving;	   // Indica si el selector está avanzando hacia el destino
		float originH;	   // Altura de origen
		float targetH;	   // Altura de destino
		float incH;		   // Cantidad de pixels que debe incrementar o decrementar el selector en cada salto
		bool resizing;	   // Indica si el selector está cambiando de tamaño
		float y;		   // Coordenada actual, usado para el desplazamiento
		float h;		   // Altura actual, usado para el cambio de tamaño
		int numJumps;	   // Numero de pasos preestablecido para llegar al destino
		int index;		   // Elemento del menu que tiene el foco
		SDL_Rect rect;	   // Rectangulo del selector
		color_t color;	   // Color del selector
		color_t itemColor; // Color del item
		int a;			   // Cantidad de transparencia para el rectangulo del selector
	};

	// Objetos y punteros
	SDL_Renderer *renderer; // Puntero al renderizador de la ventana
	Asset *asset;			// Objeto para gestionar los ficheros de recursos
	Text *text;				// Texto para poder escribir los items del menu
	Input *input;			// Gestor de eventos de entrada de teclado o gamepad

	// Variables
	std::string name;			 // Nombre del menu
	int x;						 // Posición en el eje X de la primera letra del primer elemento
	int y;						 // Posición en el eje Y de la primera letra del primer elemento
	int h;						 // Altura del menu
	int w;						 // Anchura del menu
	int itemSelected;			 // Índice del item del menu que ha sido seleccionado
	int defaultActionWhenCancel; // Indice del item del menu que se selecciona cuando se cancela el menu
	int backgroundType;			 // Tipo de fondo para el menu
	int centerX;				 // Centro del menu en el eje X
	int centerY;				 // Centro del menu en el eje Y
	bool isCenteredOnX;			 // Variable para saber si el menu debe estar centrado respecto a un punto en el eje X
	bool isCenteredOnY;			 // Variable para saber si el menu debe estar centrado respecto a un punto en el eje Y
	bool areElementsCenteredOnX; // Variable para saber si los elementos van centrados en el eje X
	int widestItem;				 // Anchura del elemento más ancho
	JA_Sound_t *soundAccept;	 // Sonido al aceptar o elegir una opción del menu
	JA_Sound_t *soundCancel;	 // Sonido al cancelar el menu
	JA_Sound_t *soundMove;		 // Sonido al mover el selector
	color_t colorGreyed;		 // Color para los elementos agrisados
	rectangle_t rectBG;			 // Rectangulo de fondo del menu
	std::vector<item_t> item;	 // Estructura para cada elemento del menu
	selector_t selector;		 // Variables para pintar el selector del menu
	std::string font_png;
	std::string font_txt;

	// Carga la configuración del menu desde un archivo de texto
	bool load(std::string file_path);

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

	// Asigna variables a partir de dos cadenas
	bool setItem(item_t *item, std::string var, std::string value);

	// Actualiza el menu para recolocarlo correctamente y establecer el tamaño
	void reorganize();

	// Deja el menu apuntando al siguiente elemento
	bool increaseSelectorIndex();

	// Deja el menu apuntando al elemento anterior
	bool decreaseSelectorIndex();

	// Actualiza la posicion y el estado del selector
	void updateSelector();

	// Obtiene la anchura del elemento más ancho del menu
	int getWidestItem();

	// Gestiona la entrada de teclado y mando durante el menu
	void checkMenuInput(Menu *menu);

	// Calcula el ancho del menu
	int findWidth();

	// Calcula el alto del menu
	int findHeight();

	// Recoloca los elementos del menu en el eje Y
	void replaceElementsOnY();

	// Calcula la altura del selector
	int getSelectorHeight(int value);

public:
	// Constructor
	Menu(SDL_Renderer *renderer, Asset *asset, Input *input, std::string file = "");

	// Destructor
	~Menu();

	// Carga los ficheros de audio
	void loadAudioFile(std::string file, int sound);

	// Obtiene el nombre del menu
	std::string getName();

	// Obtiene el valor de la variable
	int getItemSelected();

	// Deja el menu apuntando al primer elemento
	void reset();

	// Gestiona la entrada de teclado y mando durante el menu
	void checkInput();

	// Actualiza la logica del menu
	void update();

	// Pinta el menu en pantalla
	void render();

	// Establece el color del rectangulo de fondo
	void setBackgroundColor(color_t color, int alpha);

	// Establece el color del rectangulo del selector
	void setSelectorColor(color_t color, int alpha);

	// Establece el color del texto del selector
	void setSelectorTextColor(color_t color);

	// Centra el menu respecto a un punto en el eje X
	void centerMenuOnX(int value = 0);

	// Centra el menu respecto a un punto en el eje Y
	void centerMenuOnY(int value);

	// Centra los elementos del menu en el eje X
	void centerMenuElementsOnX();

	// Añade un item al menu
	void addItem(std::string text, int hPaddingDown = 1, bool selectable = true, bool greyed = false, bool linkedDown = false, bool visible = true);

	// Elimina un item del menu
	void removeItem(int index);

	// Cambia el texto de un item
	void setItemCaption(int index, std::string text);

	// Establece el indice del item que se usará por defecto al cancelar el menu
	void setDefaultActionWhenCancel(int item);

	// Coloca el selector en una posición específica
	void setSelectorPos(int index);

	// Establece el estado seleccionable de un item
	void setSelectable(int index, bool value);

	// Establece el estado agrisado de un item
	void setGreyed(int index, bool value);

	// Establece el estado de enlace de un item
	void setLinkedDown(int index, bool value);

	// Establece el estado de visibilidad de un item
	void setVisible(int index, bool value);

	// Establece el nombre del menu
	void setName(std::string name);

	// Establece la posición del menu
	void setPos(int x, int y);

	// Establece el tipo de fondo del menu
	void setBackgroundType(int value);

	// Establece la fuente de texto que se utilizará
	void setText(std::string font_png, std::string font_txt);

	// Establece el rectangulo de fondo del menu
	void setRectSize(int w = 0, int h = 0);
};

#endif
