#include "Program.hpp"

#include <algorithm>
#include <stdexcept>
#include "../api/Images.hpp"
#include "../../../../core/utils/logger.hpp"

#define CONTENT_DIR "content/"
#define SHADER_DIR CONTENT_DIR "shaders/"
#define TEXTURES_DIR CONTENT_DIR "textures/"

using namespace pass;

void Program::load(const std::vector<Shader*>& shaders) {
    ProgramID = glCreateProgram();

    for(auto shader : shaders) {
        glAttachShader(ProgramID, shader->getId());
    }
    glLinkProgram(ProgramID);

    // Check the program
    GLint result = GL_FALSE;
    int infoLogLength;
    glGetProgramiv(ProgramID, GL_LINK_STATUS, &result);
    glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &infoLogLength);
    if (infoLogLength > 0) {
        std::string errorMessage(infoLogLength, '\0');
        glGetProgramInfoLog(ProgramID, infoLogLength, NULL, errorMessage.data());
        FATAL("Failed to link GL program: " << errorMessage);
    }

    for(auto shader : shaders) {
        glDetachShader(ProgramID, shader->getId());
        delete shader;
    }
}
Program::~Program() {
    glDeleteProgram(ProgramID);
}
Shader* Program::loadShader(GLenum type, const std::vector<std::string>& flags) {
    return new Shader(type, SHADER_DIR + getName() + "." + Shader::getExt(type), flags);
}

void Program::useIt() {
    glUseProgram(ProgramID);
}

/*
GLuint Program::loadTexture(const std::string& name, bool linear) {
    auto img = render::gl::Texture::LoadFromFile(TEXTURES_DIR + name + ".dds", {linear, linear});
    auto id = img->getId();
    std::free(img.release());
    return id;
}
GLuint Program::loadTextureArray(const std::vector<std::string> &names, const std::string& suffix, float mipMapLOD, float anisotropy) {

    std::vector<std::string> paths;
    std::transform(names.begin(), names.end(), std::back_inserter(paths),
                   [suffix](const std::string &name) -> std::string { return TEXTURES_DIR + name + suffix + ".dds"; });

    auto img = render::gl::TextureArray::LoadFromFiles(paths, {true, true, render::Texture::Wrap::REPEAT, anisotropy, true, mipMapLOD});
    auto id = img->getId();
    std::free(img.release());
    return id;
}
GLuint Program::loadTextureCube(const std::string &name) {
    auto img = render::gl::TextureCube::LoadFromFiles(TEXTURES_DIR + name + ".cube", {});
    auto id = img->getId();
    std::free(img.release());
    return id;
}*/