#include "Assets.h"

#include <iostream>
#include <sstream>
#include <fstream>

#include <SDL_image.h>

#include "Utility.h" 


Shader Assets::loadShader(const GLchar *vShaderFile, const GLchar *fShaderFile, const GLchar *gShaderFile, std::string name) {
	shaders[name] = loadShaderFromFile(vShaderFile, fShaderFile, gShaderFile);
	return shaders[name];
}
Shader Assets::getShader(std::string name) {
	return shaders[name];
}
Texture2D Assets::loadTexture(const GLchar *file, GLboolean alpha, std::string name) {
	textures[name] = loadTextureFromFile(file,alpha);
	return textures[name];
}
Texture2D Assets::getTexture(std::string name) {
	return textures[name];
}

Texture2D Assets::loadTextureFromFile(const GLchar *file, GLboolean alpha) { 
	Texture2D texture;
	if(alpha) {
		texture.Internal_Format = GL_RGBA;
		texture.Image_Format = GL_RGBA;
	}

	SDL_Surface *loadedSurface;
	loadedSurface = IMG_Load( file );
	
	if(loadedSurface == NULL) {
		std::cout << "Unable to load Image " << file << " SDL_Image Error: " << IMG_GetError() << std::endl;
		SDL_FreeSurface(loadedSurface);
		return texture;
	}
	texture.Generate(loadedSurface->w, loadedSurface->h, (unsigned char *) loadedSurface->pixels);

	Utility::checkOpenGLError();
	
	SDL_FreeSurface(loadedSurface);
	return texture;
}

Shader Assets::loadShaderFromFile(const GLchar *vShaderFile,const GLchar *fShaderFile, const GLchar *gShaderFile) {
	 // 1. Retrieve the vertex/fragment source code from filePath
    std::string vertexCode;
    std::string fragmentCode;
    std::string geometryCode;
    try
    {
        // Open files
        std::ifstream vertexShaderFile(vShaderFile);
        std::ifstream fragmentShaderFile(fShaderFile);
        std::stringstream vShaderStream, fShaderStream;
        // Read file's buffer contents into streams
        vShaderStream << vertexShaderFile.rdbuf();
        fShaderStream << fragmentShaderFile.rdbuf();
        // close file handlers
        vertexShaderFile.close();
        fragmentShaderFile.close();
        // Convert stream into string
        vertexCode = vShaderStream.str();
        fragmentCode = fShaderStream.str();
        // If geometry shader path is present, also load a geometry shader
        if (gShaderFile != nullptr)
        {
            std::ifstream geometryShaderFile(gShaderFile);
            std::stringstream gShaderStream;
            gShaderStream << geometryShaderFile.rdbuf();
            geometryShaderFile.close();
            geometryCode = gShaderStream.str();
        }
    }
    catch (std::exception e)
    {
        std::cout << "ERROR::SHADER: Failed to read shader files" << std::endl;
    }
    const GLchar *vShaderCode = vertexCode.c_str();
    const GLchar *fShaderCode = fragmentCode.c_str();
    const GLchar *gShaderCode = geometryCode.c_str();
    // 2. Now create shader object from source code
    Shader shader;
    shader.Compile(vShaderCode, fShaderCode, gShaderFile != nullptr ? gShaderCode : nullptr);
    return shader;
}

Assets::~Assets() {
	std::cout << "Deleting Assets" << std::endl;
	for(auto iter : shaders) {
		glDeleteProgram(iter.second.ID);
	}
	for(auto iter : textures) {
		glDeleteTextures(1, &iter.second.ID);
	}
}

