#ifndef GLSLPROGRAM_H
#define GLSLPROGRAM_H

#include "OpenGLEnv.h"

#include <map>
#include <string>

namespace GemRB
{
	class GLSLProgram
	{
	public:
		static GLSLProgram* Create(const std::string& vertexSource, const std::string& fragmentSource, GLuint programID = 0);
		static GLSLProgram* CreateFromFiles(std::string vertexSourceFileName, std::string fragmentSourceFileName, GLuint programID = 0);

		static std::string GetLastError();

		GLSLProgram() = default;
		GLSLProgram(const GLSLProgram&) = delete;
		~GLSLProgram();
		GLSLProgram& operator=(const GLSLProgram&) = delete;
		void Use() const;
		void UnUse() const;
		bool SetUniformValue(const std::string& uniformName, const unsigned char size, GLfloat value1, GLfloat value2 = 0.0f, GLfloat value3 = 0.0f, GLfloat value4 = 0.0f) const;
		bool SetUniformValue(const std::string& uniformName, const unsigned char size, GLint value1, GLint value2 = 0, GLint value3 = 0, GLint value4 = 0) const;
		bool SetUniformValue(const std::string& uniformName, const unsigned char size, GLsizei count, const GLfloat* value) const;
		bool SetUniformValue(const std::string& uniformName, const unsigned char size, GLsizei count, const GLint* value) const;
		bool SetUniformMatrixValue(const std::string& uniformName, const unsigned char size, GLsizei count, const GLfloat* value) const;
		GLint GetAttribLocation(const std::string& attribName) const;
		GLuint GetProgramID() const;
	private:
		static std::string errMessage;

		GLuint program = 0;
		std::map<std::string, GLint> uniforms;
		bool buildProgram(const std::string& vertexSource, const std::string& fragmentSource, GLuint programID);
		GLuint buildShader(GLenum type, std::string source) const;
		GLint getUniformLocation(const std::string& uniformName) const;
		bool storeUniformLocation(const std::string& uniformName);
	};
}

#endif
