#include "graphics/TextureManager.h"

#include <limits.h>
#ifdef __linux
#include <linux/limits.h>
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "graphics/Texture.h"

#include "utilities/IOUtilities.h"
#include "utilities/JSONParser.h"

#define TEXTURE_IDENTIFIER_MAX 64

struct TextureRecord {
	Texture * texture;
	char identifier[TEXTURE_IDENTIFIER_MAX];
};

struct TextureManager {
	int numberOfTextures;
	int textureListSize;
	struct TextureRecord * textures;
};
typedef struct TextureManager TextureManager;

static TextureManager * sharedInstance = NULL;

static TextureManager * TextureManager_sharedInstance() {
	if (sharedInstance == NULL) {
		sharedInstance = malloc(sizeof(TextureManager));
		sharedInstance->numberOfTextures = 0;
		sharedInstance->textureListSize = 1;
		sharedInstance->textures = malloc(sizeof(struct TextureRecord) * sharedInstance->textureListSize);
	}
	
	return sharedInstance;
}

void TextureManager_loadTextureList(const char * filePath, const char * prefix) {
	TextureManager * self;
	JSONNode * textureList = NULL;
	
	self = TextureManager_sharedInstance();
	
	textureList = jsonFromFile(filePath);
	
	if (textureList != NULL) {
		if (textureList->type == JSON_TYPE_OBJECT) {
			size_t textureIndex;
			
			for (textureIndex = 0; textureIndex < textureList->numberOfChildren; textureIndex++) {
				if (textureList->children[textureIndex].type == JSON_TYPE_STRING) {
					JSONNode * textureProperties = NULL;
					char filePath[PATH_MAX];
					
					sprintf(filePath, "%s/%s", prefix, textureList->children[textureIndex].value.string);
					textureProperties = jsonFromFile(filePath);
					
					if (textureProperties == NULL) {
						fprintf(stderr, "Warning: Unable to load \"%s/%s\"\n", prefix, textureList->children[textureIndex].value.string);
						
					} else {
						if (self->numberOfTextures >= self->textureListSize) {
							self->textureListSize *= 2;
							self->textures = realloc(self->textures, sizeof(struct TextureRecord) * self->textureListSize);
						}
						
						strncpy(self->textures[self->numberOfTextures].identifier, textureList->children[textureIndex].key, TEXTURE_IDENTIFIER_MAX);
						self->textures[self->numberOfTextures].texture = Texture_create();
						Texture_loadJSON(self->textures[self->numberOfTextures].texture, textureProperties, prefix);
						self->numberOfTextures++;
						JSONParser_freeNodeContents(textureProperties);
						free(textureProperties);
					}
				}
			}
		}
		
		JSONParser_freeNodeContents(textureList);
		free(textureList);
	}
}

Texture * TextureManager_getTexture(const char * textureIdentifier) {
	TextureManager * self;
	int textureIndex;
	
	self = TextureManager_sharedInstance();
	
	for (textureIndex = 0; textureIndex < self->numberOfTextures; textureIndex++) {
		if (!strncmp(self->textures[textureIndex].identifier, textureIdentifier, TEXTURE_IDENTIFIER_MAX)) {
			return self->textures[textureIndex].texture;
		}
	}
	return NULL;
}
