#include "GLObject.h"
#include "../utils.h"

#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

GLObject::GLObject(ShaderProgram *shaderProgram): _sp(shaderProgram) {
}

GLObject::~GLObject() {
	glDeleteBuffers(1, &_vertexVbo);
	glDeleteBuffers(1, &_indexVbo);
	glDeleteVertexArrays(1, &_vao);
}

void GLObject::create() {
	generateVertices();
	generateIndices();

	GLuint vbo[2];
	glGenBuffers(2, vbo);
	_vertexVbo = vbo[0];
	_indexVbo = vbo[1];

	glBindBuffer(GL_ARRAY_BUFFER, _vertexVbo);
	glBufferData(GL_ARRAY_BUFFER, _vertexCount*sizeof(Vertex), nullptr, GL_STREAM_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexVbo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indexCount*sizeof(GLuint), _indices.get(), GL_STREAM_DRAW);

	_trianglesCount = _indexCount*sizeof(GLuint)/sizeof(GLuint);

	glGenVertexArrays(1, &_vao);
	glBindVertexArray(_vao);
	glBindBuffer(GL_ARRAY_BUFFER, _vertexVbo);

	// configuring attributes of vertex
	// coordinates
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr);
	glEnableVertexAttribArray(0);

	// normals
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (GLchar*)(3*sizeof(float)));
	glEnableVertexAttribArray(1);
}

void GLObject::rotate(glm::vec3 angles) {
	// FIXME: Change transformation code
	GLint world = glGetUniformLocation(*_sp, "mWorld");
	_worldMatrix = glm::rotate(_worldMatrix, angles.x, glm::vec3(1.0f, 0.0f, 0.0f));
	_worldMatrix = glm::rotate(_worldMatrix, angles.y, glm::vec3(0.0f, 1.0f, 0.0f));
	_worldMatrix = glm::rotate(_worldMatrix, angles.z, glm::vec3(0.0f, 0.0f, 1.0f));
	glUniformMatrix4fv(world, 1, GL_FALSE, glm::value_ptr(_worldMatrix));
}

void GLObject::scale(glm::vec3 scaleFactor) {
	// FIXME: Change transformation code
	GLint world = glGetUniformLocation(*_sp, "mWorld");
	_worldMatrix = glm::scale(_worldMatrix, scaleFactor);
	glUniformMatrix4fv(world, 1, GL_FALSE, glm::value_ptr(_worldMatrix));
}

void GLObject::translate(glm::vec3 point) {

}

void GLObject::draw() {
	GLint world = glGetUniformLocation(*_sp, "mWorld");
	glUniformMatrix4fv(world, 1, GL_FALSE, glm::value_ptr(_worldMatrix));
	glBindVertexArray(_vao);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexVbo);
	glDrawElements(GL_TRIANGLES, _trianglesCount, GL_UNSIGNED_INT, nullptr);
}

void GLObject::update() {
	updateVertices();
	glBindBuffer(GL_ARRAY_BUFFER, _vertexVbo);
	//glBufferData(GL_ARRAY_BUFFER, _vertexCount*sizeof(Vertex), _vertices.get(), GL_STATIC_DRAW);
	glBufferSubData(GL_ARRAY_BUFFER, 0, _vertexCount*sizeof(Vertex), _vertices.get());
}
