#include "uielements.h"

#include <glm/gtc/type_ptr.hpp>

#include "internal.h"
#include "internal/ui.h"

namespace kek {

TextElement::TextElement(UIValue x, UIValue y, Font *font): UIElement(x, y) {
	this->text = new TextObject(font, "Text");
	this->sizePixels = KEK_DEFAULT_FONT_SIZE_PIXELS;
	this->color = Colors::WHITE;
	this->textMode = TextMode::ORIGIN;
	this->textBounds = TextBounds::SMALLEST;
}

TextElement::TextElement(UIValue x, UIValue y): TextElement(x, y, kekData.ui->defaultFont) {}

TextElement::~TextElement() {
	delete text;
}

UIElementType TextElement::getType() {
	return UIElementType::TEXT;
}

UIBounds TextElement::getBounds() {
	TextMetrics metrics = text->getMetrics(sizePixels);

	int w = metrics.width, h, offsetY = 0;
	switch(textBounds) {
		case TextBounds::SMALLEST:
		default:
			h =	metrics.height;
			offsetY = metrics.offsetY;
			break;
		case TextBounds::LINE:
			FontMetrics metrics = text->getFont()->getMetrics(sizePixels);
			h = metrics.lineHeight;
			offsetY = metrics.ascender;
			break;
	}

	switch(textMode) {
		case TextMode::BASELINE:
			return UIBounds(offsetX(w, origin), -offsetY, w, h);
		case TextMode::ORIGIN:
		default:
			return offsetUIBounds(w, h, origin);
	}

}

void TextElement::setText(std::string text) {
	this->text->setText(text);
}

std::string TextElement::getText() {
	return text->getText();
}

void TextElement::draw(UIPoint screenPos, glm::mat4 projection) {
	UIBounds offset = getBounds();

	switch(textMode) {
		case TextMode::BASELINE:
			text->getFont()->drawText(text, projection, offset.x + screenPos.x, screenPos.y, sizePixels, color);
			break;
		case TextMode::ORIGIN:
			switch(textBounds) {
				case TextBounds::SMALLEST:
				default:
					text->getFont()->drawTextFromOrigin(text, projection, offset.x + screenPos.x, offset.y + screenPos.y, sizePixels, color);
					break;
				case TextBounds::LINE:
					FontMetrics metrics = text->getFont()->getMetrics(sizePixels);
					int offsetY = metrics.ascender;
					text->getFont()->drawText(text, projection, offset.x + screenPos.x, offset.y + screenPos.y + offsetY, sizePixels, color);
					break;
			}

			break;
	}
}

UIWindow::UIWindow(UIValue x, UIValue y): UIElement(x, y) {
	addChild(new TextElement(x, y));
}

UIWindow::~UIWindow() {

}

UIElementType UIWindow::getType() {
	return UIElementType::WINDOW;
}

void UIWindow::draw(UIPoint screenPos, glm::mat4 projection) {

}

static float rectangleVerts[] = {
	0.0f, 1.0f,
	1.0f, 1.0f,
	1.0f, 0.0f,
	1.0f, 0.0f,
	0.0f, 0.0f,
	0.0f, 1.0f,
};

RectangleElement::RectangleElement(UIValue x, UIValue y, UIValue w, UIValue h): UIElement(x, y) {
	this->w = w;
	this->h = h;
	color = Colors::BLACK;

	glCreateVertexArrays(1, &vao);
	glCreateBuffers(1, &vbo);

	glNamedBufferData(vbo, sizeof(rectangleVerts), rectangleVerts, GL_STATIC_DRAW);

	glVertexArrayVertexBuffer(vao, KEK_UI_VERTEX_BUFFER_BINDING, vbo, 0, 2 * sizeof(float));

	glEnableVertexArrayAttrib(vao, KEK_UI_RECT_VERTEX_SHADER_IN_POSITION);
	glVertexArrayAttribFormat(vao, KEK_UI_RECT_VERTEX_SHADER_IN_POSITION, 2, GL_FLOAT, GL_FALSE, 0);
	glVertexArrayAttribBinding(vao, KEK_UI_RECT_VERTEX_SHADER_IN_POSITION, KEK_UI_VERTEX_BUFFER_BINDING);
}

RectangleElement::~RectangleElement() {
	glDeleteVertexArrays(1, &vao);
	glDeleteBuffers(1, &vbo);
}

UIElementType RectangleElement::getType() {
	return UIElementType::RECTANGLE;
}

UIBounds RectangleElement::getBounds() {
	return offsetUIBounds(uiToScreen(w), uiToScreen(h), origin);
}

void RectangleElement::draw(UIPoint screenPos, glm::mat4 projection) {
	kekData.ui->rectangleShader->use();

	UIBounds offset = getBounds();

	glUniformMatrix4fv(glGetUniformLocation(kekData.ui->rectangleShader->id, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
	glm::vec4 bounds = glm::vec4(offset.x + screenPos.x, offset.y + screenPos.y, uiToScreen(w), uiToScreen(h));
	glUniform4fv(glGetUniformLocation(kekData.ui->rectangleShader->id, "bounds"), 1, glm::value_ptr(bounds));
	glUniform4fv(glGetUniformLocation(kekData.ui->rectangleShader->id, "rectColor"), 1, color.valuePointer());

	glBindVertexArray(vao);
	glDrawArrays(GL_TRIANGLES, 0, 6);
}

ButtonElement::ButtonElement(UIValue x, UIValue y, UIValue w, UIValue h): RectangleElement(x, y, w, h) {
	clickable = true;

	text = new TextElement(uiPw(0.5), uiPh(0.5));
	text->origin = Origin::CENTER;
	addChild(text);
}

ButtonElement::~ButtonElement() {
	delete text;
}

UIElementType ButtonElement::getType() {
	return UIElementType::BUTTON;
}

void ButtonElement::click(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) {
	onClick();
}

void ButtonElement::draw(UIPoint screenPos, glm::mat4 projection) {
	RectangleElement::color = hovering ? hoverColor : color;
	RectangleElement::draw(screenPos, projection);
}

}
