
#include "animatedsprite.h"

// Constructor
AnimatedSprite::AnimatedSprite(LTexture *texture, SDL_Renderer *renderer, std::string file)
{
	// Copia los punteros
	setTexture(texture);
	setRenderer(renderer);

	// Carga las animaciones
	load(file);

	// Inicializa variables
	currentAnimation = 0;
}

// Destructor
AnimatedSprite::~AnimatedSprite()
{
	for (auto &a : animation)
	{
		a.frames.clear();
	}
	animation.clear();
}

// Obtiene el indice de la animación a partir del nombre
int AnimatedSprite::getIndex(std::string name)
{
	int index = -1;
	/*for (int i = 0; i < (int)animation.size(); i++)
	{
		if (animation[i].name == name)
		{
			index = i;
		}
	}*/
	for (auto a : animation)
	{
		index++;
		if (a.name == name)
		{
			return index;
		}
	}

	printf("** Warning: could not find \"%s\" animation\n", name.c_str());
	index = 0;

	return -1;
}

// Calcula el frame correspondiente a la animación
void AnimatedSprite::animate()
{
	if (!enabled || animation[currentAnimation].speed == 0)
	{
		return;
	}

	// Calcula el frame actual a partir del contador
	animation[currentAnimation].currentFrame = animation[currentAnimation].counter / animation[currentAnimation].speed;

	// Si alcanza el final de la animación, reinicia el contador de la animación
	// en función de la variable loop y coloca el nuevo frame
	if (animation[currentAnimation].currentFrame >= animation[currentAnimation].frames.size())
	{
		if (animation[currentAnimation].loop == -1)
		{ // Si no hay loop, deja el último frame
			animation[currentAnimation].currentFrame = animation[currentAnimation].frames.size();
			animation[currentAnimation].completed = true;
		}
		else
		{ // Si hay loop, vuelve al frame indicado
			animation[currentAnimation].counter = 0;
			animation[currentAnimation].currentFrame = animation[currentAnimation].loop;
		}
	}
	// En caso contrario
	else
	{
		// Escoge el frame correspondiente de la animación
		setSpriteClip(animation[currentAnimation].frames[animation[currentAnimation].currentFrame]);

		// Incrementa el contador de la animacion
		animation[currentAnimation].counter++;
	}
}

// Establece el frame actual de la animación
void AnimatedSprite::setCurrentFrame(int num)
{
	animation[currentAnimation].currentFrame = num;

	// Escoge el frame correspondiente de la animación
	setSpriteClip(animation[currentAnimation].frames[animation[currentAnimation].currentFrame]);
}

// Establece el valor del contador
void AnimatedSprite::setAnimationCounter(std::string name, int num)
{
	animation[getIndex(name)].counter = num;
}

// Establece la velocidad de una animación
void AnimatedSprite::setAnimationSpeed(std::string name, int speed)
{
	animation[getIndex(name)].counter = speed;
}

// Establece si la animación se reproduce en bucle
void AnimatedSprite::setAnimationLoop(std::string name, int loop)
{
	animation[getIndex(name)].loop = loop;
}

// Establece el valor de la variable
void AnimatedSprite::setAnimationCompleted(std::string name, bool value)
{
	animation[getIndex(name)].completed = value;
}

// Comprueba si ha terminado la animación
bool AnimatedSprite::animationIsCompleted()
{
	return animation[currentAnimation].completed;
}

// Devuelve el rectangulo de una animación y frame concreto
SDL_Rect AnimatedSprite::getAnimationClip(std::string name, Uint8 index)
{
	return animation[getIndex(name)].frames[index];
}

// Carga la animación desde un fichero
bool AnimatedSprite::load(std::string filePath)
{
	int frames_per_row = 0;
	int frame_width = 0;
	int frame_height = 0;

	// Indicador de éxito en la carga
	bool success = true;

	const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1);
	std::ifstream file(filePath);
	std::string line;

	// El fichero se puede abrir
	if (file.good())
	{
		// Procesa el fichero linea a linea
		printf("Reading file %s\n", filename.c_str());
		while (std::getline(file, line))
		{
			// Si la linea contiene el texto [enemy] se realiza el proceso de carga de un enemigo
			if (line == "[animation]")
			{
				t_animation buffer;
				buffer.counter = 0;
				buffer.currentFrame = 0;
				buffer.completed = false;

				do
				{
					std::getline(file, line);

					// Encuentra la posición del caracter '='
					int pos = line.find("=");

					// Procesa las dos subcadenas
					if (pos != line.npos)
					{
						if (line.substr(0, pos) == "name")
						{
							buffer.name = line.substr(pos + 1, line.length());
						}
						else if (line.substr(0, pos) == "speed")
						{
							buffer.speed = std::stoi(line.substr(pos + 1, line.length()));
						}
						else if (line.substr(0, pos) == "loop")
						{
							buffer.loop = std::stoi(line.substr(pos + 1, line.length()));
						}
						else if (line.substr(0, pos) == "frames")
						{
							// Se introducen los valores separados por comas en un vector
							std::stringstream ss(line.substr(pos + 1, line.length()));
							std::string tmp;
							SDL_Rect rect = {0, 0, frame_width, frame_height};
							while (getline(ss, tmp, ','))
							{
								int num_tile = std::stoi(tmp);
								rect.x = (num_tile % frames_per_row) * frame_width;
								rect.y = (num_tile / frames_per_row) * frame_height;
								buffer.frames.push_back(rect);
							}
						}
						else
						{
							printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str());
							success = false;
						}
					}
				} while (line != "[/animation]");

				// Añade el enemigo al vector de enemigos
				animation.push_back(buffer);
			}

			// En caso contrario se parsea el fichero para buscar las variables y los valores
			else
			{
				// Encuentra la posición del caracter '='
				int pos = line.find("=");

				// Procesa las dos subcadenas
				if (pos != line.npos)
				{
					if (line.substr(0, pos) == "frames_per_row")
					{
						frames_per_row = std::stoi(line.substr(pos + 1, line.length()));
					}
					else if (line.substr(0, pos) == "frame_width")
					{
						frame_width = std::stoi(line.substr(pos + 1, line.length()));
					}
					else if (line.substr(0, pos) == "frame_height")
					{
						frame_height = std::stoi(line.substr(pos + 1, line.length()));
					}
					else
					{
						printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str());
						success = false;
					}
				}
			}
		}

		// Cierra el fichero
		printf("Closing file %s\n\n", filename.c_str());
		file.close();
	}
	// El fichero no se puede abrir
	else
	{
		printf("Warning: Unable to open %s file\n", filename.c_str());
		success = false;
	}

	// Pone un valor por defecto
	setPos({0, 0, frame_width, frame_height});

	return success;
}

// Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(std::string name)
{
	const int newAnimation = getIndex(name);
	if (currentAnimation != newAnimation)
	{
		currentAnimation = newAnimation;
		animation[currentAnimation].currentFrame = 0;
		animation[currentAnimation].counter = 0;
		animation[currentAnimation].completed = false;
	}
}

// Actualiza las variables del objeto
void AnimatedSprite::update()
{
	animate();
	MovingSprite::update();
}