#pragma once

#include <SDL2/SDL.h>
#include "sprite.h"
#include "text.h"
#include "input.h"
#include "jail_audio.h"

#ifndef MENU_H
#define MENU_H

// Cantidad máxima de items en el menu
#define MENU_MAX_ITEMS 50

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

// Opciones de menu
#define MENU_NO_OPTION -1

// Clase Menu
class Menu
{
private:
	std::string mName;				// Nombre del menu
	int mPosX;						// Posición en el eje X de la primera letra del primer elemento
	int mPosY;						// Posición en el eje Y de la primera letra del primer elemento
	Uint16 mHeight;					// Altura del menu
	Uint16 mWidth;					// Anchura del menu
	Uint8 mTotalItems;				// Numero total de items del menu
	int mItemSelected;				// Índice del item del menu que ha sido seleccionado
	Uint8 mDefaultActionWhenCancel; // Indice del item del menu que se selecciona cuando se cancela el menu
	Uint8 mBackgroundType;			// Tipo de fondo para el menu
	bool mIsCenteredOnX;			// Variable para saber si el menu debe estar centrado respecto a un punto en el eje X
	bool mIsCenteredOnY;			// Variable para saber si el menu debe estar centrado respecto a un punto en el eje Y
	int mCenterX;					// Centro del menu en el eje X
	int mCenterY;					// Centro del menu en el eje Y
	bool mAreElementsCenteredOnX;	// Variable para saber si los elementos van centrados en el eje X
	Uint16 mWidestItem;				// Anchura del elemento más ancho
	JA_Sound mSoundAccept;			// Sonido al aceptar o elegir una opción del menu
	JA_Sound mSoundCancel;			// Sonido al cancelar el menu
	JA_Sound mSoundMove;			// Sonido al mover el selector
	SDL_Renderer *mRenderer;		// Puntero al renderizador de la ventana
	std::string *mFileList;			// Lista de ficheros
	Text *mText;					// Texto para poder escribir los items del menu
	Input *mInput;					// Gestor de eventos de entrada de teclado o gamepad
	color_t mColorGreyed;			// Color para los elementos agrisados

	struct rectangle
	{
		SDL_Rect rect; // Rectangulo
		Uint8 r;	   // Rojo
		Uint8 g;	   // Verde
		Uint8 b;	   // Azul
		Uint8 a;	   // Transparencia
	};
	rectangle mRectBG; // Rectangulo de fondo del menu

	struct item
	{
		std::string label;	// Texto
		SDL_Rect rect;	// Rectangulo que delimita el elemento
		Uint8 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
	};
	item mItem[MENU_MAX_ITEMS]; // Estructura para cada elemento del menu

	struct selector
	{
		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
		Uint8 numJumps; // Numero de pasos preestablecido para llegar al destino
		Uint8 index;	// Elemento del menu que tiene el foco
		SDL_Rect rect;	// Rectangulo del selector
		Uint8 r;		// Cantidad de color rojo para el rectangulo del selector
		Uint8 g;		// Cantidad de color verde para el rectangulo del selector
		Uint8 b;		// Cantidad de color azul para el rectangulo del selector
		Uint8 a;		// Cantidad de transparencia para el rectangulo del selector
		Uint8 itemR;	// Cantidad de color rojo para el texto del elemento seleccionado
		Uint8 itemG;	// Cantidad de color verde para el texto del elemento seleccionado
		Uint8 itemB;	// Cantidad de color azul para el texto del elemento seleccionado
	};
	selector mSelector; // Variables para pintar el selector del menu

	// Carga los recursos necesarios para la sección 'Title'
	bool loadMedia();

	// Establece el valor de la variable
	void setTotalItems(int num);

	// Establece el rectangulo de fondo del menu
	void setRectSize();

	// 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
	Uint16 getWidestItem();

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

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

	// Calcula el alto del menu
	Uint16 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, Text *text, Input *input, std::string *fileList);

	// Destructor
	~Menu();

	// Inicializador
	void init(std::string name, int x, int y, int backgroundType);

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

	// Obtiene el valor de la variable
	Uint8 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(int r, int g, int b, int alpha);

	// Establece el color del rectangulo del selector
	void setSelectorColor(int r, int g, int b, int alpha);

	// Establece el color del texto del selector
	void setSelectorTextColor(int r, int g, int b);

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

	// 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, Uint8 hPaddingDown = 1, bool selectable = true, bool greyed = false, bool linkedDown = false);

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

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

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

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

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

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

#endif
