#pragma once
#include "font.hpp"
#include "a83/log.hpp"
extern "C" {
  #include <ft2build.h>
  #include <freetype/ftglyph.h>
}
//! универсальный шрифт
class Unifont: public Font {
private:
  bool mono = false;
public:
  //! exmpl. 0x0000-0x007F, ...
  using range_t = lni::vector<std::pair<uint, uint>>;
  Unifont(CN(Archive) arch, CN(a83::Str) fname, int _width, int _height,
  bool _mono, CN(range_t) range) {
    width = _width; 
    height = _height;
    mono = _mono;
    load(arch, fname, range);
  };
  ~Unifont() = default;
  void print(Image& dst, int x, int y, CN(utf32) text,
  bool black_gr = false, int wnd_x = 0, int wnd_y = 0,
  Image::print_f pf = &Image::print_max) const override {
    (void)wnd_x; (void)wnd_y;
    // рисуем чёрный прямоугольник туда, где будет текст:
    if (black_gr)
      dst.draw_rect_filled(x - 1, y - 1,
        get_text_size_x(text),
        height + 2, Color(Color::BLACK));
    int posx = x;
    int posy = y;
    FOR (i, text.size()) {
      nauto ch = text[i];
      if (ch == '\n') {
        posy += height + space_y;
        posx = x;
        continue;
      }
      nauto glyph = get_char(ch);
      cauto diff_y = height - glyph.getY(); // чтобы символы стояли снизу
      (glyph.*pf)(posx, posy + diff_y, dst);
      posx += (ch == U' ' // проверка на пробел
        ? (0.3f * height)
        : glyph.getX())
      + space_x;
    } // for text size
  } // print
private:
  //! грузит файл шрифтов из архива
  void load(CN(Archive) arch, CN(a83::Str) fname, CN(range_t) range) {
    a83::log("loading ttf font");
    FT_Library library;
    IFERROR(FT_Init_FreeType(&library), "Unifont.load: FT_Init_FreeType");
    FT_Face face;
    auto mem = arch.get_file(fname);
    IFERROR(FT_New_Memory_Face(library, mem.data, mem.size, 0, &face),
      "Unifont.load: FT_New_Memory_Face");
    IFERROR(FT_Set_Pixel_Sizes(face, width, height),
      "Unifont.load: FT_Set_Pixel_Sizes");
    space_x = space_y = 1;
    // загрузка диапазона символов:
    for (cnauto values: range) {
      a83::log("Unifont.load: load unicode range: "
        + a83::n2s(values.first) + '-' + a83::n2s(values.second));
      // i is charcode
      for (uint i = values.first; i < values.second; ++i) {
        nauto img = (chars[i] = {});
        set_glyph_image(img, face, i);
      }
    }
    FT_Done_Face(face);
    FT_Done_FreeType(library);
  } // load
  void set_glyph_image(Image& dst, FT_Face& face, uint char_code) {
    if (mono) {
      IFERROR(FT_Load_Char(face, char_code, FT_LOAD_RENDER | FT_LOAD_MONOCHROME),
        "Unifont.set_glyph_image: FT_Load_Char");
      nauto bitmap = face->glyph->bitmap;
      dst.init(bitmap.width, bitmap.rows, Color::BLACK);
      FOR (y, bitmap.rows) {
        auto row = &bitmap.buffer[y * bitmap.pitch];
        FOR (x, bitmap.pitch) {
          cnauto pixel_pack = *row;
          FOR (i, 8) {
            cauto col = (pixel_pack & (1 << (7 - i)))
              ? Color::WHITE : Color::BLACK;
            dst.set(x * 8 + i, y, col);
          }
          ++row;
        } // for x
      } // for y
    } else { // !mono
      IFERROR(FT_Load_Char(face, char_code, FT_LOAD_RENDER),
        "Unifont.set_glyph_image: FT_Load_Char");
      nauto bitmap = face->glyph->bitmap;
      dst.init(bitmap.width, bitmap.rows, Color::BLACK);
      FOR (y, bitmap.rows)
      FOR (x, bitmap.width) {
        cnauto pix = bitmap.buffer[y * bitmap.pitch + x];
        dst.fast_set(x, y, pix ? Color::WHITE : Color::BLACK);
      }
    } // else !mono
  } // set_glyph_image
  //! получить ширину текста с отступами
  int get_text_size_x(CN(utf32) text) const {
    int size = 0;
    FOR (i, text.length()) {
      cnauto char_x = get_char(text[i]).getX();
      size += (text[i] == U' ' // проверка на пробел
        ? (0.3f * height)
        : char_x);
      size += space_x;
    }
    return size + 1;
  }
}; // Unifont