#include "ShaderProgram.h"
#include <iostream>
graphics::ShaderProgram::ShaderProgram() : m_program(0) {
}

graphics::ShaderProgram::ShaderProgram(graphics::Shader * vertexShader, graphics::Shader * fragmentShader) {
    m_program = glCreateProgram();

    vertexShader->bindToProgram(m_program);
    fragmentShader->bindToProgram(m_program);

    link();
    validate();
}

void graphics::ShaderProgram::link() {
    GLint success;
    GLchar errorLog[1024];
    glLinkProgram(m_program);
    glGetProgramiv(m_program, GL_LINK_STATUS, &success);
    if (success == 0) {
        glGetProgramInfoLog(m_program, sizeof(errorLog), NULL, errorLog);
        std::cout << "UNABLE TO LINK PROGRAM " << errorLog;
        exit(1);
    }
};

void graphics::ShaderProgram::validate() {
    glValidateProgram(m_program);
    GLint success;
    GLchar errorLog[1024];

    glGetProgramiv(m_program, GL_VALIDATE_STATUS, &success);
    if (success == 0) {
        glGetProgramInfoLog(m_program, sizeof(errorLog), NULL, errorLog);
        std::cout <<  "UNABLE TO VALIDATE PROGRAM " << errorLog;
        exit(1);
    }
}

void graphics::ShaderProgram::useProgram() {
    glUseProgram(m_program);
}

graphics::ShaderProgram::~ShaderProgram() {
    glDeleteProgram(m_program);
}

GLint graphics::ShaderProgram::getLocation(const char * uniformName) {
	LocationContainer::iterator it = m_locations.find(uniformName);
	GLint result;
	if (it == m_locations.end()) {
		result = glGetUniformLocation(m_program, uniformName);
		m_locations.insert(std::make_pair(uniformName, result));
	}
	else {
		result = it->second;
	}
	return result;
}

GLint graphics::ShaderProgram::getLocation(const std::string & uniformName) {
	return getLocation(uniformName.c_str());
}