#include "graphics/TextDisplay.h"

#include <stdlib.h>
#include <string.h>

#include "graphics/FontTexture.h"
#include "graphics/GLIncludes.h"
#include "graphics/Image.h"
#include "graphics/Texture.h"
#include "graphics/TextureManager.h"

void TextDisplay_drawString(const char * string, FontTexture * fontTexture, float emHeight, float x, float y) {
	GLfloat * texCoords;
	GLfloat * vertices;
	size_t length;
	unsigned int charIndex;
	float offsetX;
	struct FontTexture_characterDimensions characterDimensions;
	float glyphX, glyphWidth;
	unsigned int entryIndex;
	float kerningOffset;
	
	if (fontTexture == NULL || fontTexture->texture == NULL || fontTexture->texture->image == NULL) {
		return;
	}
	
	length = strlen(string);
	texCoords = malloc(sizeof(GLfloat) * length * 12);
	vertices = malloc(sizeof(GLfloat) * length * 12);
	
	offsetX = 0;
	for (charIndex = 0; charIndex < length; charIndex++) {
		if (string[charIndex] >= ' ' && string[charIndex] <= '~') {
			characterDimensions = fontTexture->characters[string[charIndex] - ' '];
			
			kerningOffset = 0.0f;
			if (charIndex > 0) {
				for (entryIndex = 0; entryIndex < characterDimensions.kerningTable.numberOfEntries; entryIndex++) {
					if (characterDimensions.kerningTable.entries[entryIndex].previous == string[charIndex - 1]) {
						kerningOffset = characterDimensions.kerningTable.entries[entryIndex].offset;
						break;
					}
				}
			}
			
			texCoords[charIndex * 12 +  0] = characterDimensions.textureLeft;
			texCoords[charIndex * 12 +  1] = characterDimensions.textureBottom;
			texCoords[charIndex * 12 +  2] = characterDimensions.textureRight;
			texCoords[charIndex * 12 +  3] = characterDimensions.textureBottom;
			texCoords[charIndex * 12 +  4] = characterDimensions.textureLeft;
			texCoords[charIndex * 12 +  5] = characterDimensions.textureTop;
			texCoords[charIndex * 12 +  6] = characterDimensions.textureLeft;
			texCoords[charIndex * 12 +  7] = characterDimensions.textureTop;
			texCoords[charIndex * 12 +  8] = characterDimensions.textureRight;
			texCoords[charIndex * 12 +  9] = characterDimensions.textureBottom;
			texCoords[charIndex * 12 + 10] = characterDimensions.textureRight;
			texCoords[charIndex * 12 + 11] = characterDimensions.textureTop;
			
			glyphX = (characterDimensions.offset + kerningOffset) * emHeight;
			glyphWidth = (characterDimensions.textureRight - characterDimensions.textureLeft) * fontTexture->texture->image->width / fontTexture->emHeight * emHeight;
			
			vertices[charIndex * 12 +  0] = x + offsetX + glyphX;
			vertices[charIndex * 12 +  1] = y;
			vertices[charIndex * 12 +  2] = x + offsetX + glyphX + glyphWidth;
			vertices[charIndex * 12 +  3] = y;
			vertices[charIndex * 12 +  4] = x + offsetX + glyphX;
			vertices[charIndex * 12 +  5] = y + emHeight;
			vertices[charIndex * 12 +  6] = x + offsetX + glyphX;
			vertices[charIndex * 12 +  7] = y + emHeight;
			vertices[charIndex * 12 +  8] = x + offsetX + glyphX + glyphWidth;
			vertices[charIndex * 12 +  9] = y;
			vertices[charIndex * 12 + 10] = x + offsetX + glyphX + glyphWidth;
			vertices[charIndex * 12 + 11] = y + emHeight;
			
			offsetX += (characterDimensions.advancement + kerningOffset) * emHeight;
		}
	}
	
	Texture_activate(fontTexture->texture);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
	glVertexPointer(2, GL_FLOAT, 0, vertices);
	glDrawArrays(GL_TRIANGLES, 0, length * 6);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	Texture_deactivate(fontTexture->texture);
	
	free(texCoords);
	free(vertices);
}

float TextDisplay_measureString(const char * string, struct FontTexture * fontTexture, float emHeight) {
	size_t length;
	unsigned int charIndex;
	float measuredLength = 0.0f;
	unsigned int entryIndex;
	float kerningOffset;
	
	if (fontTexture == NULL || fontTexture->texture == NULL || fontTexture->texture->image == NULL) {
		return 0.0f;
	}
	
	length = strlen(string);
	for (charIndex = 0; charIndex < length; charIndex++) {
		if (string[charIndex] >= ' ' && string[charIndex] <= '~') {
			kerningOffset = 0.0f;
			if (charIndex > 0) {
				for (entryIndex = 0; entryIndex < fontTexture->characters[string[charIndex] - ' '].kerningTable.numberOfEntries; entryIndex++) {
					if (fontTexture->characters[string[charIndex] - ' '].kerningTable.entries[entryIndex].previous == string[charIndex - 1]) {
						kerningOffset = fontTexture->characters[string[charIndex] - ' '].kerningTable.entries[entryIndex].offset;
						break;
					}
				}
			}
			measuredLength += (fontTexture->characters[string[charIndex] - ' '].advancement + kerningOffset) * emHeight;
		}
	}
	
	return measuredLength;
}
