#include <iostream>
#include <cstring>
#include "ShaderProgram.h"

ShaderProgram::ShaderProgram(const char* vertexShaderPath, const char* fragmentShaderPath) {
	FILE* f = fopen(vertexShaderPath, "rb");
	fseek(f, 0, SEEK_END);
	long fsize = ftell(f);
	fseek(f, 0, SEEK_SET);
	_vertexShaderText = new char[fsize + 1];
	fread(_vertexShaderText, fsize, 1, f);
	fclose(f);
	_vertexShaderText[fsize] = 0;

	_vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(_vertexShader, 1, (const GLchar**)&_vertexShaderText, nullptr);
	glCompileShader(_vertexShader);

	GLint success = GL_TRUE;
	glGetShaderiv(_vertexShader, GL_COMPILE_STATUS, &success);
	if(success == GL_FALSE) {
		std::cout << "error compilling vertex shader" << std::endl;
		logCompileError(_vertexShader);
	}

	f = fopen(fragmentShaderPath, "rb");
	fseek(f, 0, SEEK_END);
	fsize = ftell(f);
	fseek(f, 0, SEEK_SET);
	_fragmentShaderText = new char[fsize + 1];
	fread(_fragmentShaderText, fsize, 1, f);
	fclose(f);
	_fragmentShaderText[fsize] = 0;

	_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(_fragmentShader, 1,(const GLchar**)&_fragmentShaderText, nullptr);
	glCompileShader(_fragmentShader);

	glGetShaderiv(_fragmentShader, GL_COMPILE_STATUS, &success);
	if(success == GL_FALSE) {
		std::cout << "error compilling fragment shader" << std::endl;
		logCompileError(_fragmentShader);
	}


	_program = glCreateProgram();
	glAttachShader(_program, _vertexShader);
	glAttachShader(_program, _fragmentShader);
	glLinkProgram(_program);
}

void ShaderProgram::use() const {
	glUseProgram(_program);
}

ShaderProgram::~ShaderProgram() {
	delete[] _vertexShaderText;
	delete[] _fragmentShaderText;

	glDeleteShader(_vertexShader);
	glDeleteShader(_fragmentShader);
}

ShaderProgram::operator GLuint() const {
	return _program;
}

void ShaderProgram::logCompileError(GLuint shader) {
	std::cout << "shader: " << shader << std::endl;
	GLint logSize = 0;
	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize);
	std::cout << "log length: " << logSize << std::endl;

	GLchar* log = new GLchar[logSize];
	memset(log, 0, (size_t)logSize);

	glGetShaderInfoLog(shader, logSize, &logSize, log);
	std::cout << "log: " << log << std::endl;
}
