#ifndef _H_SPRITE_H
#define _H_SPRITE_H

#include <SDL_image.h>
#include <thirdparty/glad/glad.h>

#include <glm/glm.hpp>

#include <vector>
#include <unordered_map>
#include <memory>
#include <algorithm>

#include "utility/direction.h"

enum class TileType;
class Texture;
class EventManager;
class UnitQuad;

class Sprite
{
public:
	virtual ~Sprite() {}

	void bind();
	virtual void draw() = 0;

	bool loaded() const;

	virtual std::shared_ptr<Sprite> clone() const = 0;
protected:
	Texture* texture = nullptr;
	unsigned indices[6] = {
		0, 1, 2,
		3, 2, 0
	};
};

class SpriteStatic : public Sprite
{
public:
	SpriteStatic(const char* texturePath);
	~SpriteStatic();

	void draw() override;

	std::shared_ptr<Sprite> clone() const override {
		return std::make_shared<SpriteStatic>(*this);
	}

private:
	void setupSprite();
	UnitQuad* quad;
};

class SpriteAtlas : public Sprite
{
public:
	struct VertexIDs {
		unsigned VAO, VBO;
	};
	// let's keep texture grids squares, saves everyone time...
	SpriteAtlas(const char* textureAtlasPath, float frameSize, bool isDirectional = false);
	~SpriteAtlas();

	// bind the frame VAO before drawing
	void bindFrame(VertexIDs* f);
	// draw current frame
	void draw() override;

	VertexIDs frame(int index, Direction dir = Direction::None) {
		if (dir == Direction::None) return singleFrame(index);
		return dirFrames(dir, index);
	}

	size_t size() { return (isDirectional) ? directionalIDs.size() : singleIDs.size(); }

	std::shared_ptr<Sprite> clone() const override {
		return std::make_shared<SpriteAtlas>(*this);
	}

private:
	void Setup(float frameSize);
	void SetupDirectional(float frameSize);

	unsigned EBO;
	bool isDirectional;

	VertexIDs singleFrame(int index) const { 
		return (index < 0 || index >= singleIDs.size()) ? singleIDs[0] : singleIDs[index]; 
	}

	// return the frame in the direction at the selected index
	VertexIDs dirFrames(Direction dir, int index) const { 
		return (index < 0 || index >= directionalIDs.at(dir).size()) ? directionalIDs.at(dir)[0] : directionalIDs.at(dir)[index]; 
	}

	// Vertex array buffer IDs, if the sprite atlas is non-directional
	std::vector<VertexIDs> singleIDs;

	// Vertex ids if the sprite atlas is directional
	std::unordered_map<Direction, std::vector<VertexIDs>> directionalIDs;
};

#endif // _H_SPRITE_H
