#include "FreeTypeFontEngine.h"

#include "Image.h"
#include "Grid.h"
#include "FileLogger.h"
#include "FontGlyph.h"

#include <iostream>

void FreeTypeFontEngine::initialize()
{
    if (mLibrary)
    {
        return;
    }

    const auto error = FT_Init_FreeType(&mLibrary);
    if (error)
    {
        MLOG_ERROR("Error initializing FreeType. Code " << static_cast<int>(error));
    }
}

void FreeTypeFontEngine::loadFontFace(const std::filesystem::path& fontFile, float penSize)
{
    if (!mLibrary)
    {
        initialize();
    }

    if (mWorkingFontFace)
    {
        return;
    }

    const auto full_path = mSystemFontLocation / fontFile;
    const auto error = FT_New_Face(mLibrary, full_path.c_str(), 0, &mWorkingFontFace );
    if ( error == FT_Err_Unknown_File_Format )
    {
        MLOG_ERROR("Found file but format not supported. Code " << static_cast<int>(error));
    }
    else if ( error )
    {
        MLOG_ERROR("Failed to find or open file. Code " << static_cast<int>(error));
    }
    FT_Set_Pixel_Sizes(mWorkingFontFace, penSize, 0);
}

std::unique_ptr<FontGlyph> FreeTypeFontEngine::loadGlyph(uint32_t charCode)
{
    auto glyph_index = FT_Get_Char_Index( mWorkingFontFace, charCode );
    if (glyph_index == 0)
    {
        MLOG_ERROR("Got the null glyph");
        return nullptr;
    }

    auto error = FT_Load_Glyph(mWorkingFontFace, glyph_index, FT_LOAD_DEFAULT );
    if (error == FT_Err_Invalid_Argument)
    {
        MLOG_ERROR("Error loading glyph - bad arg. Code " << static_cast<int>(error));
        return nullptr;
    }
    else if(error)
    {
        MLOG_ERROR("Error loading glyph. Code " << static_cast<int>(error));
        return nullptr;
    }

    if (mWorkingFontFace->glyph->format != FT_GLYPH_FORMAT_BITMAP)
    {
        error = FT_Render_Glyph( mWorkingFontFace->glyph, FT_RENDER_MODE_NORMAL );
    }
    if (error)
    {
        MLOG_ERROR("Error rendering glyph. Code " << static_cast<int>(error));
        return nullptr;
    }

    auto rows = mWorkingFontFace->glyph->bitmap.rows;
    auto columns = mWorkingFontFace->glyph->bitmap.width;
    auto image = std::make_unique<Image>(columns, rows);

    unsigned counter = 0;
    std::vector<unsigned char> data(rows*columns, 0);
    for (unsigned idx=0; idx<rows; idx++)
    {
        for (unsigned jdx=0; jdx<columns; jdx++)
        {
            data[counter] = mWorkingFontFace->glyph->bitmap.buffer[counter];
            counter++;
        }
    }
    image->getGridT<unsigned char>()->setData(data);
    auto glyph = std::make_unique<FontGlyph>(mWorkingFontFace->glyph->bitmap.width,
            mWorkingFontFace->glyph->bitmap.rows,
            mWorkingFontFace->glyph->bitmap_left,
            mWorkingFontFace->glyph->bitmap_top,
            mWorkingFontFace->glyph->advance.x,
            std::move(image));

    return glyph;
}
