/*
	Really hacked-together naiive implementation of gettext
*/
#include "i18n.h"

#include <stdlib.h>
#include <stdio.h>
#include <SDL3/SDL_stdinc.h>

char** strdict = 0;
unsigned int nStr = 0;

const int MAX_LANGUAGES = 20;

const int LANGCODE_SIZE = 16;
const int LANGFONT_SIZE = 128;

char* currentLocale = 0;

struct LanguageFontAndSize {
	char* lang_code = 0;
	int size = 0;
	char* font_name = 0;
};

LanguageFontAndSize** languageMetadata = 0;

const char* findtext(unsigned int msgid, const char* fallback) {
	if (msgid >= nStr) {
		return fallback;
	} else {
		return strdict[msgid];
	}
}

void unloadLocale() {
	for (unsigned int i = 0; i < nStr; i++) {
		SDL_free(strdict[i]);
	}
	SDL_free(strdict);
	SDL_free(currentLocale);
	strdict = 0;
	nStr = 0;
}


void unloadLanguageMetadata() {
	if (languageMetadata) {
		for (int i = 0; i < MAX_LANGUAGES; ++i) {
			LanguageFontAndSize* ldata = languageMetadata[i];
			if (ldata) {
				if (ldata->font_name) {
					SDL_free(ldata->font_name);
				}
				if (ldata->lang_code) {
					SDL_free(ldata->lang_code);
				}
				SDL_free(ldata);
			}
		}
	}
	SDL_free(languageMetadata);
}

void loadLanguageMetadata() {
	if (languageMetadata) {
		unloadLanguageMetadata();
	}

	// char line[256];
	char line[1024];

	languageMetadata = (LanguageFontAndSize**) SDL_calloc(MAX_LANGUAGES, sizeof(LanguageFontAndSize*));
	FILE* fontsFile = fopen("Languages/internal/language_fonts.ini", "r");
	if (fontsFile) {

		int languageMetadataIndex = 0;

		while (fgets(line, 1024, fontsFile)) {
			char* indexOfEquals = SDL_strchr(line, '=');
			if (indexOfEquals) {
				// splitting the string in place here
				indexOfEquals[0] = 0;
				char* indexOfFontName = indexOfEquals + 1;
				
				// remove new line from end of font name
				char* indexOfNewLine = SDL_strchr(indexOfFontName, '\n');
				if (indexOfNewLine) {
					indexOfNewLine[0] = 0;
				}

				// make new strings for code and font name
				char* langCode = (char*)SDL_calloc(LANGCODE_SIZE, sizeof(char));
				char* langFont = (char*)SDL_calloc(LANGFONT_SIZE, sizeof(char));

				SDL_strlcpy(langCode, line, sizeof(line));
				SDL_strlcpy(langFont, indexOfFontName, sizeof(indexOfFontName));

				// allocate metadata mem
				LanguageFontAndSize* metadata = (LanguageFontAndSize*) SDL_calloc(1, sizeof(LanguageFontAndSize));
				metadata->font_name = langFont;
				metadata->lang_code = langCode;

				// put into metadata array and check if we're going to go over the language limit
				languageMetadata[languageMetadataIndex] = metadata;
				languageMetadataIndex++;
				if (languageMetadataIndex >= MAX_LANGUAGES) {
					break;
				}
			}
		}

		//fclose(fontsFile);
	}


	FILE* fontSizesFile = fopen("Languages/internal/language_sizes.ini", "r");
	if (fontSizesFile) {
		while (fgets(line, 1024, fontSizesFile)) {
			int languageMetadataIndex = 0;
			char* indexOfEquals = SDL_strchr(line, '=');
			if (indexOfEquals) {
				// splitting the string in place here
				indexOfEquals[0] = 0;
				char* indexOfFontSize = indexOfEquals + 1;

				// remove new line from end of font size
				char* indexOfNewLine = SDL_strchr(indexOfFontSize, '\n');
				if (indexOfNewLine) {
					indexOfNewLine[0] = 0;
				}

				int fontSize = SDL_atoi(indexOfFontSize);

				for (int i = 0; i < MAX_LANGUAGES; i++) {
					// search for corresponding langCode in metadata array to populate font size in the appropriate metadata
					LanguageFontAndSize* metadata = languageMetadata[i];
					if (metadata && SDL_strcmp(line, metadata->lang_code) == 0) {
						metadata->size = fontSize;
						break;
					}
				}
			}
		}
	}
}

int getFontSize() {
	for (int i = 0; i < MAX_LANGUAGES; i++) {
		LanguageFontAndSize* metadata = languageMetadata[i];
		if (metadata && SDL_strcmp(currentLocale, metadata->lang_code) == 0) {
			return metadata->size;
		}
	}

	// default to 12?
	return 12;
}

char* getFontName() {
	for (int i = 0; i < MAX_LANGUAGES; i++) {
		LanguageFontAndSize* metadata = languageMetadata[i];
		if (metadata && SDL_strcmp(currentLocale, metadata->lang_code) == 0) {
			return metadata->font_name;
		}
	}

	// default to terminus?
	return "Terminus (TTF)";
}

void loadLocale(const char* locale) {
	char line[1024];
	char pathbuf[100];
	FILE* locfile;

	unloadLocale();

	currentLocale = (char*) SDL_calloc(128, sizeof(char));
	SDL_strlcpy(currentLocale, locale, 128 - 1);

	int dictSize = 100;
	// currently there are 52, but 100 should be plenty if we ever do add more
	strdict = (char**)SDL_malloc(sizeof(char*) * dictSize);

	sprintf(pathbuf, "Languages/internal/%s.po", locale);
	locfile = fopen(pathbuf, "r");
	if (locfile) {
		while (fgets(line, 1024, locfile)) {
			if (SDL_strncmp("msgstr \"", line, 8) == 0) {
				char* lineWithoutMsgid = line + 8;
				
				char* endQuoteAddress = SDL_strrchr(lineWithoutMsgid, '"');

				// end string at last quotation mark
				if (endQuoteAddress != 0) {
					endQuoteAddress[0] = 0;
				}

				decodeEscapeChars(lineWithoutMsgid);

				int lineLen = SDL_strlen(lineWithoutMsgid);

				strdict[nStr] = (char*)SDL_malloc(lineLen + 1);
				SDL_strlcpy(strdict[nStr], lineWithoutMsgid, sizeof(lineWithoutMsgid));

				nStr++;
			}
		}

		fclose(locfile);
	}
}

// replaces escape characters with their actual values in-place in a string
// can do it in-place because the replacement values are always smaller than the original value
// it only handles \\ and \", but this can be expanded to include more if needed
void decodeEscapeChars(char* s) {
	char* dest = s;
	char* src = s;
	while (src[0] != 0) {
		switch (src[0]) {
			// might be an escape character?
			case '\\':
				switch (src[1]) {
					case '\\' :
						dest[0] = '\\';
						dest++;
						src += 2;
						break;
					case '\"':
						dest[0] = '\"';
						dest++;
						src += 2;
						break;
					// end of the string?
				    // so only advance forward 1 character
					case 0:
						dest[0] = '\\';
						dest++;
						src++;
						break;
					// not escape, handle normally
					default:
						dest[0] = '\\';
						dest[1] = src[1];
						dest+=2;
						src+=2;
						break;
				}
				break;
			default:
				dest[0] = src[0];
				dest++;
				src++;
		}
	}
	// cap the end of the string
	dest[0] = 0;
}

