#ifndef _H_ANIMATION_H
#define _H_ANIMATION_H

#include <memory>
#include <SDL_timer.h>
#include <string>
#include <unordered_map>

#include "utility/direction.h"

class SpriteAtlas;
class ResourceManager;
class EventManager;

// Each entity will contain animation data,
// this data will hold:
// name of the animation,
// type of animation ie. idle animation, directional, etc.
// directory of the animation atlas containing the frames
struct AnimationData;

class Animation
{
public:
	Animation(const std::shared_ptr<AnimationData>& animData, ResourceManager* resourceManager);

	std::string getName() const { return animName; }
	std::string getType() const { return animType; }

	void bind();
	void draw();
	void draw(Direction dir);

	void play() { isPlaying = true; }
	void stop() { isPlaying = false; }
	void reset() { currentFrame = 0; }

	const bool getPlaying() const		{ return isPlaying; }
	const bool getDirectional() const	{ return isDirectional; }
	const int  getCycles()	const		{ return cycles; }

	void setFPS(const float fps) { FPS = fps; }

private:
	std::string animName;
	std::string animType;

	SpriteAtlas* spriteAtlas;

	Uint32 elapsedTime = 0;
	Uint32 lastFrameTick = 0;
	float FPS;
	int currentFrame;
	int cycles;

	bool isDirectional;
	bool isPlaying;

	// this ticks our frame forward according to ticks passed
	void frameTick();

	void singleDraw();
	void directionalDraw(Direction dir);
};

// We will load our animation component with every loaded animation, 
// this will be the handler for every animation an entity uses
class AnimationSet : public std::enable_shared_from_this<AnimationSet>
{
public:
	AnimationSet(const int& entityid);
	AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<std::shared_ptr<AnimationData>> animSet);
	AnimationSet(const int& entityid, std::unordered_map<std::string, std::unique_ptr<Animation>> animations);

	Animation* operator [](std::string animType) { return anims[animType].get(); }

	void addAnimation(std::unique_ptr<Animation> anim) { std::string type = anim->getType(); anims.try_emplace(type, std::move(anim)); }
	void setAnimation(const std::string& animType) { curAnim = anims[animType].get(); }

	const int getEntityID() const { return entityid; }
	const bool getDirectional() const { return isDirectional; }

	void bind();
	void draw();

	void play() { curAnim->play(); }
	void stop() { curAnim->stop(); }

	void setFacingDir(Direction& dir) { facing = dir; }

	void attachEventManager(std::weak_ptr<EventManager> e);

private:
	int entityid;
	bool isDirectional;

	Direction facing = Direction::Down;

	std::unordered_map<std::string, std::unique_ptr<Animation>> anims;
	Animation* curAnim;

	std::weak_ptr<EventManager> eventManager;
};

#endif // _H_ANIMATION_H