#include "graphics/FontTexture.h"

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

#include "graphics/Image.h"
#include "graphics/Texture.h"
#include "graphics/TextureManager.h"
#include "utilities/IOUtilities.h"
#include "utilities/JSONParser.h"

FontTexture * FontTexture_create() {
	FontTexture * self;
	
	self = malloc(sizeof(FontTexture));
	FontTexture_init(self);
	return self;
}

void FontTexture_init(FontTexture * self) {
	int charIndex;
	
	self->texture = NULL;
	self->emHeight = 0;
	for (charIndex = 0; charIndex < 95; charIndex++) {
		self->characters[charIndex].textureLeft = 0.0f;
		self->characters[charIndex].textureRight = 0.0f;
		self->characters[charIndex].textureBottom = 0.0f;
		self->characters[charIndex].textureTop = 0.0f;
		self->characters[charIndex].advancement = 0.0f;
		self->characters[charIndex].kerningTable.numberOfEntries = 0;
		self->characters[charIndex].kerningTable.entries = NULL;
	}
}

void FontTexture_readProperties(FontTexture * self, const char * filePath) {
	JSONNode * fontProperties = NULL;
	
	fontProperties = jsonFromFile(filePath);
	
	if (fontProperties != NULL) {
		// TODO: Validation
		size_t propertyIndex;
		
		for (propertyIndex = 0; propertyIndex < fontProperties->numberOfChildren; propertyIndex++) {
			if (!strcmp("texture", fontProperties->children[propertyIndex].key)) {
				self->texture = TextureManager_getTexture(fontProperties->children[propertyIndex].value.string);
				
			} else if (!strcmp("em_height", fontProperties->children[propertyIndex].key)) {
				self->emHeight = fontProperties->children[propertyIndex].value.number;
				
			} else if (!strcmp("character_dimensions", fontProperties->children[propertyIndex].key)) {
				unsigned int characterIndex;
				
				for (characterIndex = 0; characterIndex < fontProperties->children[propertyIndex].numberOfChildren; characterIndex++) {
					if (fontProperties->children[propertyIndex].children[characterIndex].key[0] >= ' ' &&
					    fontProperties->children[propertyIndex].children[characterIndex].key[0] <= '~') {
						unsigned int dimensionsPropertyIndex;
						unsigned int characterDimensionsIndex;
						
						characterDimensionsIndex = fontProperties->children[propertyIndex].children[characterIndex].key[0] - ' ';
						for (dimensionsPropertyIndex = 0; dimensionsPropertyIndex < fontProperties->children[propertyIndex].children[characterIndex].numberOfChildren; dimensionsPropertyIndex++) {
							if (!strcmp("offset", fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].key)) {
								self->characters[characterDimensionsIndex].offset = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].value.number;
								
							} else if (!strcmp("advancement", fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].key)) {
								self->characters[characterDimensionsIndex].advancement = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].value.number;
								
							} else if (!strcmp("texture_bounds", fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].key)) {
								self->characters[characterDimensionsIndex].textureLeft   = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].children[0].value.number;
								self->characters[characterDimensionsIndex].textureRight  = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].children[1].value.number;
								self->characters[characterDimensionsIndex].textureBottom = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].children[2].value.number;
								self->characters[characterDimensionsIndex].textureTop    = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].children[3].value.number;
								
							} else if (!strcmp("kerning_table", fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].key)) {
								unsigned int entryIndex;
								
								self->characters[characterDimensionsIndex].kerningTable.numberOfEntries = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].numberOfChildren;
								free(self->characters[characterDimensionsIndex].kerningTable.entries);
								self->characters[characterDimensionsIndex].kerningTable.entries = malloc(sizeof(struct FontTexture_kerningTableEntry) * self->characters[characterDimensionsIndex].kerningTable.numberOfEntries);
								for (entryIndex = 0; entryIndex < self->characters[characterDimensionsIndex].kerningTable.numberOfEntries; entryIndex++) {
									self->characters[characterDimensionsIndex].kerningTable.entries[entryIndex].previous = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].children[entryIndex].key[0];
									self->characters[characterDimensionsIndex].kerningTable.entries[entryIndex].offset = fontProperties->children[propertyIndex].children[characterIndex].children[dimensionsPropertyIndex].children[entryIndex].value.number;
								}
							}
						}
					}
				}
			}
		}
		
		JSONParser_freeNodeContents(fontProperties);
		free(fontProperties);
	}
	
	if (self->texture != NULL && self->texture->image != NULL) {
		int charIndex;
		float imageWidth, imageHeight;
		unsigned int entryIndex;
		
		imageWidth = self->texture->image->width;
		imageHeight = self->texture->image->height;
		for (charIndex = 0; charIndex < 95; charIndex++) {
			self->characters[charIndex].offset /= (self->characters[charIndex].textureTop - self->characters[charIndex].textureBottom);
			self->characters[charIndex].advancement /= (self->characters[charIndex].textureTop - self->characters[charIndex].textureBottom);
			
			for (entryIndex = 0; entryIndex < self->characters[charIndex].kerningTable.numberOfEntries; entryIndex++) {
				self->characters[charIndex].kerningTable.entries[entryIndex].offset /= (self->characters[charIndex].textureTop - self->characters[charIndex].textureBottom);
			}
			
			self->characters[charIndex].textureLeft   /= imageWidth;
			self->characters[charIndex].textureRight  /= imageWidth;
			self->characters[charIndex].textureBottom /= imageHeight;
			self->characters[charIndex].textureTop    /= imageHeight;
		}
	}
}

void FontTexture_dispose(FontTexture * self) {
	int charIndex;
	
	for (charIndex = 0; charIndex < 95; charIndex++) {
		free(self->characters[charIndex].kerningTable.entries);
	}
	free(self);
}
