#include "item.h"
#include <stdlib.h>			 // for rand
#include "animated_sprite.h" // for AnimatedSprite
#include "param.h"			 // for param
class Texture;

// Constructor
Item::Item(int kind, float x, float y, SDL_Rect *playArea, std::shared_ptr<Texture> texture, std::vector<std::string> *animation)
	: kind(kind), playArea(playArea)
{
	sprite = std::make_unique<AnimatedSprite>(texture, "", animation);

	enabled = true;
	timeToLive = 600;
	accelX = 0.0f;
	floorCollision = false;

	if (kind == ITEM_COFFEE_MACHINE)
	{
		width = 28;
		height = 37;
		posX = (((int)x + (playArea->w / 2)) % (playArea->w - width - 5)) + 2;
		posY = -height;
		velX = 0.0f;
		velY = -0.1f;
		accelY = 0.1f;
		collider.r = 10;
	}
	else
	{
		width = 20;
		height = 20;
		posX = x;
		posY = y;
		velX = -1.0f + ((rand() % 5) * 0.5f);
		velY = -4.0f;
		accelY = 0.2f;
		collider.r = width / 2;
	}

	sprite->setPosX(posX);
	sprite->setPosY(posY);
	shiftColliders();
}

// Centra el objeto en la posición X
void Item::allignTo(int x)
{
	posX = float(x - (width / 2));

	if (posX < param.game.play_area.rect.x)
	{
		posX = param.game.play_area.rect.x + 1;
	}
	else if ((posX + width) > playArea->w)
	{
		posX = float(playArea->w - width - 1);
	}

	// Posición X,Y del sprite
	sprite->setPosX(int(posX));
	sprite->setPosY(int(posY));

	// Alinea el circulo de colisión con el objeto
	shiftColliders();
}

// Pinta el objeto en la pantalla
void Item::render()
{
	if (enabled)
	{
		if (timeToLive > 200)
		{
			sprite->render();
		}
		else if (timeToLive % 20 > 10)
		{
			sprite->render();
		}
	}
}

// Actualiza la posición y estados del objeto
void Item::move()
{
	floorCollision = false;

	// Calcula la nueva posición
	posX += velX;
	posY += velY;

	// Aplica las aceleraciones a la velocidad
	velX += accelX;
	velY += accelY;

	// Si queda fuera de pantalla, corregimos su posición y cambiamos su sentido
	if ((posX < param.game.play_area.rect.x) || (posX + width > playArea->w))
	{
		// Corregir posición
		posX -= velX;

		// Invertir sentido
		velX = -velX;
	}

	// Si se sale por arriba rebota (excepto la maquina de café)
	if ((posY < param.game.play_area.rect.y) && !(kind == ITEM_COFFEE_MACHINE))
	{
		// Corrige
		posY = param.game.play_area.rect.y;

		// Invierte el sentido
		velY = -velY;
	}

	// Si el objeto se sale por la parte inferior
	if (posY + height > playArea->h)
	{
		// Detiene el objeto
		velY = 0;
		velX = 0;
		accelX = 0;
		accelY = 0;
		posY = playArea->h - height;
		if (kind == ITEM_COFFEE_MACHINE)
		{
			floorCollision = true;
		}
	}

	// Actualiza la posición del sprite
	sprite->setPosX(int(posX));
	sprite->setPosY(int(posY));
	shiftColliders();
}

// Pone a cero todos los valores del objeto
void Item::disable()
{
	enabled = false;
}

// Actualiza el objeto a su posicion, animación y controla los contadores
void Item::update()
{
	move();
	sprite->animate();
	updateTimeToLive();
	checkTimeToLive();
}

// Actualiza el contador
void Item::updateTimeToLive()
{
	if (timeToLive > 0)
	{
		timeToLive--;
	}
}

// Comprueba si el objeto sigue vivo
void Item::checkTimeToLive()
{
	if (timeToLive == 0)
		disable();
}

// Obtiene del valor de la variable
float Item::getPosX()
{
	return posX;
}

// Obtiene del valor de la variable
float Item::getPosY()
{
	return posY;
}

// Obtiene del valor de la variable
int Item::getWidth()
{
	return width;
}

// Obtiene del valor de la variable
int Item::getHeight()
{
	return height;
}

// Obtiene del valor de la variable
int Item::getClass()
{
	return kind;
}

// Obtiene el valor de la variable
bool Item::isEnabled()
{
	return enabled;
}

// Obtiene el circulo de colisión
Circle &Item::getCollider()
{
	return collider;
}

// Alinea el circulo de colisión con la posición del objeto
void Item::shiftColliders()
{
	collider.x = int(posX + (width / 2));
	collider.y = int(posY + (height / 2));
}

// Informa si el objeto ha colisionado con el suelo
bool Item::isOnFloor()
{
	return floorCollision;
}