#include <opengl-playground/textured-rectangle.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

TexturedRectangle::TexturedRectangle(float x0, float y0, float x1, float y1, std::shared_ptr<OpenGlShaderProgram> &shaderprog,
				     std::shared_ptr<OpenGlTexture> &texture) :
	OpenGlGraphics(shaderprog)
{
	this->pos1[0] = x0;
	this->pos1[1] = y0;
	this->pos2[0] = x1;
	this->pos2[1] = y1;
	this->setZoom(1.0f);
	this->setOffset(0.0f, 0.0f);
	this->vao = 0;
	this->base_color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
	this->m_texture = texture;
}

void TexturedRectangle::realize()
{
	GLuint vbo;
	GLuint elem_buff;
	const unsigned int indices[] = {
			0, 1, 2,
			2, 0, 3
		    };

	float vertices[16] = {
		this->pos1[0], this->pos1[1],	0.0f, 0.0f,
		this->pos1[0], this->pos2[1],	0.0f, 1.0f,
		this->pos2[0], this->pos2[1],	1.0f, 1.0f,
		this->pos2[0], this->pos1[1],	1.0f, 0.0f,
	};

	glGenVertexArrays(1, &this->vao);
	glBindVertexArray(this->vao);
	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
	glGenBuffers(1, &elem_buff);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem_buff);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);

	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2*sizeof(float)));
	glEnableVertexAttribArray(1);
}

void TexturedRectangle::render()
{
	this->shaderprog->use();
	this->shaderprog->setUniformVec4("base_color", this->base_color);
	this->shaderprog->setUniformMat4("model_matrix", this->model_matrix);
	this->shaderprog->setUniformInt("uni_texture", 0);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	this->m_texture->use(0UL);
	glBindVertexArray(this->vao);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

void TexturedRectangle::setZoom(float zoom)
{
	this->zoom = zoom;
	this->calculateModelMatrix();
}

float TexturedRectangle::getZoom()
{
	return this->zoom;
}

void TexturedRectangle::setOffset(float x_off, float y_off)
{
	this->x_offset = x_off;
	this->y_offset = y_off;
	this->calculateModelMatrix();
}

float TexturedRectangle::getOffsetX()
{
	return this->x_offset;
}

float TexturedRectangle::getOffsetY()
{
	return this->y_offset;
}

void TexturedRectangle::setBaseColor(const glm::vec4 &color)
{
	this->base_color = color;
}

void TexturedRectangle::calculateModelMatrix()
{
	glm::mat4 moved_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(-this->x_offset, -this->y_offset, 0.0f));
	this->model_matrix = glm::scale(moved_matrix, glm::vec3(this->zoom, this->zoom, 0.0f));
}
