//
// Created by Evgenij on 09.04.2024.
//

#include <locale>
#include <codecvt>
#include <vector>
#include "psf.h"

std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> conv_utf8_utf16;

Font readPSF(const std::string &filename) {
    {
        PSF2Header psf2Header;
        std::ifstream ifs(filename, std::ios_base::binary);
        if (!ifs.good()) {
            throw std::runtime_error("File read error");
        }
        uint8_t magicNumber[4];
        ifs.read((char *) magicNumber, 4);
        ifs.seekg(0, std::ios_base::beg);
        if (magicNumber[0] == 0x36 && magicNumber[1] == 0x04)
            throw std::runtime_error("PSF1 not supported");
        if (magicNumber[0] != 0x72 || magicNumber[1] != 0xb5 || magicNumber[2] != 0x4a || magicNumber[3] != 0x86)
            throw std::runtime_error("Invalid font file");
        ifs.read((char *) &psf2Header, sizeof(psf2Header));
        auto font = Font(psf2Header.numberOfGlyphs, psf2Header.glyphWidth, psf2Header.glyphHeight);
        Glyph glyphs[psf2Header.numberOfGlyphs];
        for (int i = 0; i < psf2Header.numberOfGlyphs; ++i) {
            auto glyph = Glyph(psf2Header.glyphWidth, psf2Header.glyphHeight);
            char glyphBytes[psf2Header.bytesPerGlyph];
            ifs.read((char *) &glyphBytes, psf2Header.bytesPerGlyph);
            for (int j = 0; j < psf2Header.bytesPerGlyph; ++j) {
                for (int k = 0; k < 8; ++k) {
                    uint8_t bit = (glyphBytes[j] & (1 << k)) != 0; // Получить к-ый бит
                    glyph.glyph[(j * 8 + k) / psf2Header.glyphWidth][psf2Header.glyphWidth - 1 -
                                                                     (j * 8 + k) % psf2Header.glyphWidth] = bit;
                }
            }
            glyphs[i] = glyph;
        }
        // Чтение таблицы unicode

        uint32_t curGlyph = 0;
        std::vector<unsigned char> vectorOfBytes;
        while (not ifs.eof() && curGlyph < psf2Header.numberOfGlyphs) {
            unsigned char curByte;
            ifs.read((char *) &curByte, 1);
            if (curByte != 0xFF) {
                vectorOfBytes.push_back(curByte);
            } else {
                unsigned long long int bytesCount = vectorOfBytes.size();
                unsigned char bytes[bytesCount];
                for (int i = 0; i < bytesCount; ++i) {
                    bytes[i] = vectorOfBytes[i];
                }
                char chars8[bytesCount + 1];
                memcpy(chars8, bytes, bytesCount);
                chars8[bytesCount] = 0;
                std::string str8(chars8);
                std::u16string str16 = conv_utf8_utf16.from_bytes(str8);
                for (auto chr: str16) {
                    font._glyphs[chr] = glyphs[curGlyph];
                }
                curGlyph++;
                vectorOfBytes.clear();
            }
        }
        return font;
    }
}

Glyph::Glyph(uint32_t width, uint32_t height) {
    this->glyph = new uint8_t *[height];
    for (int i = 0; i < height; ++i) {
        this->glyph[i] = new uint8_t[width];
    }
    this->width = width;
    this->height = height;
}

Glyph::Glyph() {

}

Font::Font(uint32_t glyphsCount, uint32_t glyphWidth, uint32_t glyphHeight) {
    this->glyphsCount = glyphsCount;
    this->glyphWidth = glyphWidth;
    this->glyphHeight = glyphHeight;
}

Font::Font() {

}
