#include "font.h"
#include "default_font_gif.h"
#include "default_font_fnt.h"

#include "mini/surf/surf.h"
#include "mini/file/file.h"
#include "other/log.h"

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

#define MAX_FONTS 5

namespace mini
{
    namespace font
    {
        font_t fonts[MAX_FONTS];
        font_t *current_font;

        uint8_t load_from_buffer(const char* buffer, uint8_t index, const char* name) {
            if (!buffer) return false;

            const char* ptr = buffer;
            char line[256];

            // --- Read first line ---
            {
                // Extract line
                int len = 0;
                while (ptr[len] && ptr[len] != '\n' && len < 255) len++;

                memcpy(line, ptr, len);
                line[len] = '\0';
                ptr += (ptr[len] == '\n') ? len + 1 : len; // Advance pointer
                if (len > 0 && line[len - 1] == '\r') line[len - 1] = '\0';

                if (strncmp(line, "bitmap=", 7) != 0) return false; // Parse first line

                fonts[index].surface = surf::load(line + 7);

                fonts[index].name = (char*)malloc(strlen(name)+1);
                strcpy(fonts[index].name, name);
            }

            // --- Read character lines ---
            while (*ptr) {
                // Extract next line
                int len = 0;
                while (ptr[len] && ptr[len] != '\n' && len < 255) len++;

                memcpy(line, ptr, len);
                line[len] = '\0';
                ptr += (ptr[len] == '\n') ? len + 1 : len; // Advance pointer
                if (len > 0 && line[len - 1] == '\r') line[len - 1] = '\0';

                // Remove comments
                char* hash = strchr(line, '#');
                if (hash) *hash = '\0';

                // Parse
                int code, x, y, w, h, base;
                if (sscanf(line, "%d: %d %d %d %d %d", &code, &x, &y, &w, &h, &base) == 6) {
                    if (code >= 0 && code < 256) {
                        fonts[index].chars[code] = { (uint8_t)x, (uint8_t)y, (uint8_t)w, (uint8_t)h, (uint8_t)base };
                    }
                }
            }
            return index;
        }

        uint8_t load(const char *filename) {
            // Si la font ja s'ha carregat, tornem eixa font
            for (unsigned int i=0; i<MAX_FONTS; ++i)
                if (fonts[i].name && strcmp(fonts[i].name, filename)==0) {
                    log_msg(LOG_INFO, "Carrega de '%s' abortada: Reusant: %i.\n", filename, i);
                    return i;
                }

            // Agafar la pròxima font lliure
            unsigned int i = 0;
            while (i<MAX_FONTS && fonts[i].name != NULL) ++i;
            if (i==MAX_FONTS) return 255;

            // Carregar l'arxiu de disc
            int size;
            char *buffer;
            buffer = file::getfilebuffer(filename, size);

            // Si no s'ha pogut, petar
            if (!buffer) {
                log_msg(LOG_FAIL, "Error al intentar obrir l'arxiu '%s'\n", filename);
                exit(-1);
                return 255;
            }

            load_from_buffer(buffer, i, filename);
            free(buffer);
            
            log_msg(LOG_INFO, "Arxiu '%s' carregat en font: %i.\n", filename, i);
            return i;
        }

        void init() {
            //uint8_t font_surf = 
            surf::load(default_font_gif, "default_font");
            //surfaces[font_surf].flags |= SURF_GENERATED;
            font::load_from_buffer((const char*)default_font_fnt, 0, "default_font");
            current_font = &fonts[0];
        }

        void quit() {
            for (int i=0;i<MAX_FONTS;++i) {
                if (fonts[i].name != NULL) free(fonts[i].name);
                fonts[i].name = NULL;
            }
        }

        namespace current {
            void set(uint8_t font) {
                current_font = &fonts[font];
            }
            uint8_t get() {
                for (unsigned int i=0; i<MAX_FONTS; ++i) if (current_font == &fonts[i]) return i;
                return 0;
            }
        }

        namespace spacing {
            void set(uint8_t spacing) {
                current_font->spacing = spacing;
            }
            uint8_t get() {
                return current_font->spacing;
            }
        }
    }
}