#pragma once

#include <string>
#include "td/Defines.h"
#include "client/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 Vec2f& vector) const;
	void LoadVector(unsigned int location, const Vec3f& vector) const;
	void LoadBoolean(unsigned int location, bool value) const;
	void LoadMat4(unsigned int location, const Mat4f& mat) 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