#ifndef _H_COMPONENT_H
#define _H_COMPONENT_H

#include "graphics/mesh.h"
#include "graphics/sprite.h"
#include "graphics/shader.h"
#include "graphics/animation.h"
#include "gameplay/ai.h"
#include "events.h"

#include <glm/gtc/type_ptr.hpp>

class Component 
{
public:
	enum class TYPE { MESH, SPRITE, ANIMATION, SHADER, AI };
	Component(const std::shared_ptr<EventManager>& eventManager) : eventManager(eventManager) {}
	virtual ~Component() {};
	virtual void bind() = 0;
	virtual void update() = 0;
	virtual void render() = 0;
	virtual void play() = 0;
	virtual void idle() = 0;
	virtual TYPE getType() const = 0;

	int ownerid = 0;
private:
	std::shared_ptr<EventManager> eventManager;
};

class MeshComponent : public Component
{
public:
	MeshComponent(Mesh* mesh, const std::shared_ptr<EventManager>& eventManager) : Component(eventManager), mesh(mesh) {};

	void bind() override {}
	void update() override {}
	void render() override {
		if (mesh) mesh->draw();
	}
	void play() override { /*unused*/ }
	void idle() override { /*unused*/ }
	
	TYPE getType() const override { return TYPE::MESH; }

	~MeshComponent() { mesh->~Mesh(); }

private:
	Mesh* mesh;

};

class SpriteComponent : public Component
{
public:
	SpriteComponent(Sprite* sprite) : Component(nullptr), sprite(sprite) {}

	void bind() override {
		if (sprite) sprite->bind();
	}
	void update() override { /*unused*/ }
	void render() override {
		if (sprite) sprite->draw();
	}
	void play() override { /*unused*/ }
	void idle() override { /*unused*/ }
	TYPE getType() const override { return TYPE::SPRITE; }

	Sprite* getSprite() { return sprite; }

	~SpriteComponent() { /*sprite->~Sprite();*/ }

private:
	Sprite* sprite;
};

class AnimationComponent : public Component
{
public:
	AnimationComponent(std::shared_ptr<AnimationSet> animSet) : Component(nullptr), animSet(animSet) {};
	AnimationComponent(std::shared_ptr<AnimationSet> animSet, const std::shared_ptr<EventManager>& eventManager) :
		Component(nullptr), animSet(animSet)
	{
		this->animSet->attachEventManager(eventManager);
	}

	void bind() override {
		if (animSet)
			animSet->bind();
	}
	void update() override {/*unused*/}
	void render() override { 
		if (animSet)
			animSet->draw(); 
	}
	void play() override { 
		if (animSet)
			animSet->play(); 
	}
	void idle() override { 
		if (animSet)
			animSet->stop(); 
	}
	TYPE getType() const override { return TYPE::ANIMATION; }

	std::shared_ptr<AnimationSet>& getAnimationSet() { return animSet; }

	~AnimationComponent() {  }

private:
	std::shared_ptr<AnimationSet> animSet;
};

class ShaderComponent : public Component
{
public:
	ShaderComponent(const char* vertexPath, const char* shaderPath) :
		Component(nullptr), shader(vertexPath, shaderPath) {};

	void bind() override {
		shader.use();
	}
	void update() override {}
	void render() override {}
	void play() override { /*unused*/ }
	void idle() override { /*unused*/ }
	TYPE getType() const override { return TYPE::SHADER; }

	Shader& getShader() { return shader; }
			
	~ShaderComponent() { }

private:
	Shader shader;
};

class AIComponent : public Component {
public:
	AIComponent(std::shared_ptr<AI> ai) : Component(nullptr), ai(ai) {}

	void bind() override { /*unused*/ }
	void update() override { if (ai) ai->update(); }
	void render() override { /*unused*/ }
	void play() override { /*unused*/ }
	void idle() override { /*unused*/ }
	TYPE getType() const override { return TYPE::AI; }

	~AIComponent() { }

private:
	std::shared_ptr<AI> ai;
};

#endif // _H_COMPONENT_H
