#include "shaders.h"
#include "textfiles.h"

GLuint loadShaders(const char* vertexShaderPath, const char* fragmentShaderPath)
{
    char* vertexShaderCode = readTextFile( vertexShaderPath );
    char* fragmentShaderCode = readTextFile( fragmentShaderPath );

    GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
	GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    GLint result = GL_FALSE;
    int infoLogLength;

    printf("Compiling vertex shader...\n");
    glShaderSource(vertexShaderID, 1, &vertexShaderCode, NULL);
    glCompileShader(vertexShaderID);

    glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &result);
    glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
    if( infoLogLength > 0 )
    {
        char vertexShaderErrorMessage[infoLogLength + 1];
        glGetShaderInfoLog(vertexShaderID, infoLogLength, NULL, &vertexShaderErrorMessage);
        printf("%s\n", &vertexShaderErrorMessage);
    }

    printf("Compiling fragment shader...\n");
    glShaderSource(fragmentShaderID, 1, &fragmentShaderCode, NULL);
    glCompileShader(fragmentShaderID);

    glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &result);
    glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
    if( infoLogLength > 0 )
    {
        char fragmentShaderErrorMessage[infoLogLength + 1];
        glGetShaderInfoLog(fragmentShaderID, infoLogLength, NULL, &fragmentShaderErrorMessage);
        printf("%s\n", &fragmentShaderErrorMessage);
    }

    printf("Linking program\n");
    GLuint programID = glCreateProgram();
    glAttachShader(programID, vertexShaderID);
    glAttachShader(programID, fragmentShaderID);
    glLinkProgram(programID);

    glGetProgramiv(programID, GL_LINK_STATUS, &result);
    glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
    if( infoLogLength > 0 )
    {
        char programErrorMessage[infoLogLength + 1];
        glGetProgramInfoLog(programID, infoLogLength, NULL, &programErrorMessage);
        printf("%s\n", &programErrorMessage);
    }

    free( vertexShaderCode );
    free( fragmentShaderCode );

    glDetachShader( programID, vertexShaderID );
    glDetachShader( programID, fragmentShaderID );

    glDeleteShader( vertexShaderID );
    glDeleteShader( fragmentShaderID );
    return programID;
}

void shaderSetBool(GLuint ID, char* name, bool value)
{
    glUniform1i(glGetUniformLocation(ID, name), (int) value);
}

void shaderSetInt(GLuint ID, char* name, int value)
{
    glUniform1i(glGetUniformLocation(ID, name), value);
}

void shaderSetFloat(GLuint ID, char* name, float value)
{
    glUniform1f(glGetUniformLocation(ID, name), value);
}

void shaderSetVec2(GLuint ID, char* name, vec2s* ref)
{
    glUniform2fv(glGetUniformLocation(ID, name), 1, ref);
}

void shaderSet2f(GLuint ID, char* name, float x, float y)
{
    glUniform2f(glGetUniformLocation(ID, name), x, y);
}

void shaderSetVec3(GLuint ID, char* name, vec3s* ref)
{
    glUniform3fv(glGetUniformLocation(ID, name), 1, ref);
}

void shaderSet3f(GLuint ID, char* name, float x, float y, float z)
{
    glUniform3f(glGetUniformLocation(ID, name), x, y, z);
}

void shaderSetVec4(GLuint ID, char* name, vec4s* ref)
{
    glUniform4fv(glGetUniformLocation(ID, name), 1, ref);
}

void shaderSet4f(GLuint ID, char* name, float x, float y, float z, float w)
{
    glUniform4f(glGetUniformLocation(ID, name), x, y, z, w);
}

void shaderSetMat2(GLuint ID, char* name, mat2s* ref)
{
    glUniformMatrix2fv(glGetUniformLocation(ID, name), 1, GL_FALSE, ref);
}

void shaderSetMat3(GLuint ID, char* name, mat3s* ref)
{
    glUniformMatrix3fv(glGetUniformLocation(ID, name), 1, GL_FALSE, ref);
}

void shaderSetMat4(GLuint ID, char* name, mat4s* ref)
{
    glUniformMatrix4fv(glGetUniformLocation(ID, name), 1, GL_FALSE, ref);
}
