#pragma once

#include <string>
#include <glm/glm.hpp>
#include "render/GL.h"

namespace td {
namespace shader {

class ShaderProgram {
public:
	ShaderProgram();
	virtual ~ShaderProgram();

	void Start() const;
	void Stop() const;

	void LoadProgramFile(const std::string& vertexFile, const std::string& fragmentFile);
	void LoadProgram(const std::string& vertexSource, const std::string& fragmentSource);

protected:
	virtual void GetAllUniformLocation() = 0;
	int GetUniformLocation(const std::string& uniformName) const;

	void LoadFloat(unsigned int location, float value) const;
	void LoadInt(unsigned int location, int value) const;
	void LoadVector(unsigned int location, const glm::vec2& vector) const;
	void LoadVector(unsigned int location, const glm::vec3& vector) const;
	void LoadVector(unsigned int location, const glm::vec4& vector) const;
	void LoadBoolean(unsigned int location, bool value) const;
	void LoadMatrix(unsigned int location, const glm::mat4& matrix) const;
	void CleanUp() const;

private:
	unsigned int m_ProgramID;
	unsigned int m_VertexShaderID;
	unsigned int m_FragmentShaderID;

	unsigned int LoadShaderFromFile(const std::string& file, GLenum type);
	unsigned int LoadShader(const std::string& source, GLenum type);
};

} // namespace shader
} // namespace td