#pragma once

#include <SDL2/SDL.h>
#include "utils.h"
#include "animatedsprite.h"
#include <vector>
#include <sstream>

#ifndef BALLOON_H
#define BALLOON_H

// Cantidad de elementos del vector con los valores de la deformación del globo al rebotar
#define MAX_BOUNCE 10

// Tipos de globo
#define BALLOON_1 1
#define BALLOON_2 2
#define BALLOON_3 3
#define BALLOON_4 4
#define HEXAGON_1 5
#define HEXAGON_2 6
#define HEXAGON_3 7
#define HEXAGON_4 8
#define POWER_BALL 9

// Puntos de globo
#define BALLOON_SCORE_1 50
#define BALLOON_SCORE_2 100
#define BALLOON_SCORE_3 200
#define BALLOON_SCORE_4 400

// Tamaños de globo
#define BALLOON_SIZE_1 1
#define BALLOON_SIZE_2 2
#define BALLOON_SIZE_3 3
#define BALLOON_SIZE_4 4

// Clases de globo
#define BALLOON_CLASS 0
#define HEXAGON_CLASS 1

// Velocidad del globo
#define BALLOON_VELX_POSITIVE 0.7f
#define BALLOON_VELX_NEGATIVE -0.7f

// Indice para las animaciones de los globos
#define BALLOON_MOVING_ANIMATION 0
#define BALLOON_POP_ANIMATION 1
#define BALLOON_BORN_ANIMATION 2

// Cantidad posible de globos
#define MAX_BALLOONS 100

// Velocidades a las que se mueven los globos
#define BALLOON_SPEED_1 0.60f
#define BALLOON_SPEED_2 0.70f
#define BALLOON_SPEED_3 0.80f
#define BALLOON_SPEED_4 0.90f
#define BALLOON_SPEED_5 1.00f

// Tamaño de los globos
#define BALLOON_WIDTH_1 8
#define BALLOON_WIDTH_2 13
#define BALLOON_WIDTH_3 21
#define BALLOON_WIDTH_4 37

// PowerBall
#define POWERBALL_SCREENPOWER_MINIMUM 10
#define POWERBALL_COUNTER 8

// Clase Balloon
class Balloon
{
private:
	// Estructura para las variables para el efecto de los rebotes
	struct bouncing
	{
		bool enabled;		  // Si el efecto está activo
		Uint8 counter;		  // Countador para el efecto
		Uint8 speed;		  // Velocidad a la que transcurre el efecto
		float zoomW;		  // Zoom aplicado a la anchura
		float zoomH;		  // Zoom aplicado a la altura
		float despX;		  // Desplazamiento de pixeles en el eje X antes de pintar el objeto con zoom
		float despY;		  // Desplazamiento de pixeles en el eje Y antes de pintar el objeto con zoom
		std::vector<float> w; // Vector con los valores de zoom para el ancho del globo
		std::vector<float> h; // Vector con los valores de zoom para el alto del globo
	};

	// Objetos
	AnimatedSprite *sprite; // Sprite del objeto globo

	// Variables
	float posX;				   // Posición en el eje X
	float posY;				   // Posición en el eje Y
	Uint8 width;			   // Ancho
	Uint8 height;			   // Alto
	float velX;				   // Velocidad en el eje X. Cantidad de pixeles a desplazarse
	float velY;				   // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
	float gravity;			   // Aceleración en el eje Y. Modifica la velocidad
	float defaultVelY;		   // Velocidad inicial que tienen al rebotar contra el suelo
	float maxVelY;			   // Máxima velocidad que puede alcanzar el objeto en el eje Y
	bool beingCreated;		   // Indica si el globo se está creando
	bool blinking;			   // Indica si el globo está intermitente
	bool enabled;			   // Indica si el globo esta activo
	bool invulnerable;		   // Indica si el globo es invulnerable
	bool popping;			   // Indica si el globo está explotando
	bool stopped;			   // Indica si el globo está parado
	bool visible;			   // Indica si el globo es visible
	circle_t collider;		   // Circulo de colisión del objeto
	Uint16 creationCounter;	   // Temporizador para controlar el estado "creandose"
	Uint16 creationCounterIni; // Valor inicial para el temporizador para controlar el estado "creandose"
	Uint16 score;			   // Puntos que da el globo al ser destruido
	Uint16 stoppedCounter;	   // Contador para controlar el estado "parado"
	Uint8 kind;				   // Tipo de globo
	Uint8 menace;			   // Cantidad de amenaza que genera el globo
	Uint32 counter;			   // Contador interno
	float travelY;			   // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad
	float speed;			   // Velocidad a la que se mueven los globos
	Uint8 size;				   // Tamaño del globo
	Uint8 power;			   // Cantidad de poder que alberga el globo
	bouncing bouncing;		   // Contiene las variables para el efecto de rebote

	// Alinea el circulo de colisión con la posición del objeto globo
	void updateColliders();

	// Activa el efecto
	void bounceStart();

	// Detiene el efecto
	void bounceStop();

	// Aplica el efecto
	void updateBounce();

	// Actualiza los estados del globo
	void updateState();

	// Establece la animación correspondiente
	void updateAnimation();

	// Establece el valor de la variable
	void setBeingCreated(bool value);

public:
	// Constructor
	Balloon(float x, float y, Uint8 kind, float velx, float speed, Uint16 creationtimer, LTexture *texture, std::vector<std::string> *animation, SDL_Renderer *renderer);

	// Destructor
	~Balloon();

	// Centra el globo en la posición X
	void allignTo(int x);

	// Pinta el globo en la pantalla
	void render();

	// Actualiza la posición y estados del globo
	void move();

	// Deshabilita el globo y pone a cero todos los valores
	void disable();

	// Explosiona el globo
	void pop();

	// Actualiza al globo a su posicion, animación y controla los contadores
	void update();

	// Comprueba si el globo está habilitado
	bool isEnabled();

	// Obtiene del valor de la variable
	float getPosX();

	// Obtiene del valor de la variable
	float getPosY();

	// Obtiene del valor de la variable
	float getVelY();

	// Obtiene del valor de la variable
	int getWidth();

	// Obtiene del valor de la variable
	int getHeight();

	// Establece el valor de la variable
	void setVelY(float velY);

	// Establece el valor de la variable
	void setSpeed(float speed);

	// Obtiene del valor de la variable
	int getKind();

	// Obtiene del valor de la variable
	Uint8 getSize();

	// Obtiene la clase a la que pertenece el globo
	Uint8 getClass();

	// Establece el valor de la variable
	void setStop(bool value);

	// Obtiene del valor de la variable
	bool isStopped();

	// Establece el valor de la variable
	void setBlink(bool value);

	// Obtiene del valor de la variable
	bool isBlinking();

	// Establece el valor de la variable
	void setVisible(bool value);

	// Obtiene del valor de la variable
	bool isVisible();

	// Establece el valor de la variable
	void setInvulnerable(bool value);

	// Obtiene del valor de la variable
	bool isInvulnerable();

	// Obtiene del valor de la variable
	bool isBeingCreated();

	// Establece el valor de la variable
	void setPopping(bool value);

	// Obtiene del valor de la variable
	bool isPopping();

	// Establece el valor de la variable
	void setStoppedTimer(Uint16 time);

	// Obtiene del valor de la variable
	Uint16 getStoppedTimer();

	// Obtiene del valor de la variable
	Uint16 getScore();

	// Obtiene el circulo de colisión
	circle_t &getCollider();

	// Obtiene le valor de la variable
	Uint8 getMenace();

	// Obtiene le valor de la variable
	Uint8 getPower();
};

#endif
