#ifndef GLSHADER_H
#define GLSHADER_H

#include <GLES2/gl2.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <memory>
#include <stdexcept>
#include "RNGLContext/RNGLContext.h"

class RNGLContext;

class GLShader {
public:
    GLShader(std::shared_ptr<GLShaderData>& data, int id, std::shared_ptr<RNGLContext>& rnglContext);
    ~GLShader();

    void bind();
    void validate();
    void setUniform(const std::string& name, GLint i);
    void setUniform(const std::string& name, GLfloat f);
    void setUniform(const std::string& name, const GLfloat* buf, int type);
    void setUniform(const std::string& name, const GLint* buf, int type);
    const std::string& getName() const;
    const std::unordered_map<std::string, GLint>& getUniformTypes() const;
    const std::unordered_map<std::string, GLint>& getUniformSizes() const;
    const std::vector<std::string>& getUniformNames() const;
    bool isReady() const;
    bool ensureCompile();
    void runtimeException(const std::string& msg);

private:
    std::string name;
    std::string vert;
    std::string frag;
    std::unordered_map<std::string, GLint> uniformTypes;
    std::vector<std::string> uniformNames;
    GLuint program = 0;
    GLuint buffer = 0;
    GLint pointerLoc = -1;
    std::unordered_map<std::string, GLint> uniformLocations;
    std::unordered_map<std::string, GLint> uniformSizes;
    int id;
    std::shared_ptr<RNGLContext> rnglContext;
    std::runtime_error* compilationFailed;

    GLuint compileShader(const std::string& code, GLenum shaderType);
    void computeMeta();
    void makeProgram();
};

#endif