
#include <fstream>
#include <Spectre/System/File.h>
#include <Spectre/Graphics/OpenGL.h>
#include <Spectre/Graphics/Shader.h>

Shader::Shader(Type type, const std::string& name) : 
m_name		(name)
{
	GLenum internal_type = type == Vertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER;
	m_handle = glCreateShader(internal_type);
}

Shader::~Shader()
{
	if (m_handle) {
		glDeleteShader(m_handle);
	}
}

unsigned int Shader::getHandle() const
{
	return m_handle;
}

const std::string& Shader::getName() const
{
	return m_name;
}

bool Shader::loadFromFile(const std::string& file)
{
	std::string src;
	std::ifstream strm;

	// If this shader does not have a name, pick the filename.
	if (m_name.length() < 1) {
		m_name = File::getBasename(file);
	}

	// Load file into memory.
	strm.open(file.c_str(), std::fstream::in);
	if (!strm.is_open()) {
		m_error = "Can't open file: " + file;
		return false;
	}

	src.assign(std::istreambuf_iterator<char>(strm), std::istreambuf_iterator<char>());

	strm.close();

	return loadFromMemory(src);
}

bool Shader::loadFromMemory(const std::string& source)
{
	const char *s = source.c_str();

	glShaderSource(m_handle, 1, &s, NULL);
	
	return compile();
}

const std::string& Shader::getError() const
{
	return m_error;
}

bool Shader::isCompiled() const
{
	// A shader without handle is not compiled.
	if (m_handle) {

		// Query OpenGL for status.
		GLint status;
		glGetShaderiv(m_handle, GL_COMPILE_STATUS, &status);
		return status == GL_TRUE;
	}
	return false;
}

bool Shader::compile()
{
	glCompileShader(m_handle);

	if (!isCompiled()) {
		m_error = fetchErrorLog();
		return false;
	}
	return true;
}

std::string Shader::fetchErrorLog()
{
	GLchar buf[4096] = { '\0 ' };

	glGetShaderInfoLog(m_handle, sizeof(buf), NULL, buf);

	return std::string(buf);
}
