
// font class library
#pragma once
#include <cstdint>

class font_t
{
public:


  /// \param height - pixel character height
  /// \param width  - pixel character width
  /// \param spacing - character to character spacing
  /// \param chars  - number of characters in character set
  /// \param data - constant data
  /// \param mult - coordinate multiplied by before sampling bitmap
  /// \param shift- coordinate right shifted by after multiplication : mult=1, shift=1 means half sized
  font_t(uint8_t const height, uint8_t const width,
         uint8_t const spacing, uint8_t const chars,
         char const *data,
         uint8_t const mult, uint8_t const shift)
      : m_height(height),
        m_width(width),
        m_mapheight(PIXELS(height,mult,shift)),
        m_mapwidth(PIXELS(width,mult,shift)),
        m_spacing(PIXELS(spacing,mult,shift)),
        m_chars(chars),
        m_data(data),
        m_mult(mult),
        m_shift(shift),
        m_round(ROUNDING(shift))
  {
  }

  virtual char
  getPixel(char c, int x, int y) = 0;

  // character width
  uint8_t
  width()
  {
    return m_mapwidth;
  }

  // character height
  uint8_t
  height()
  {
    return m_mapheight;
  }

  uint8_t
  chars()
  {
    return m_chars;
  }

  uint8_t
  spacing()
  {
    return m_spacing;
  }

private:

  /// @brief Convert from real bitmap dimension to virtual dimension given 
  /// @param dimension original dimension
  /// @param mult  scale up multiplier 
  /// @param shift bit shift right after scaling
  /// @return virtual dimension
  static constexpr unsigned PIXELS(uint8_t dimension,uint8_t mult, uint8_t shift) { return (dimension << shift )/mult; };

  /// @brief Calculate a rounding value that is 0.5 << shift
  /// @param val shift value 
  /// @return 0.5 << shift or 0
  static constexpr uint8_t ROUNDING(uint8_t shift) { return (shift>0) ? (0) : 1<<(shift-1);};


protected:
  /// @brief Pixel height
  uint8_t const m_height;
  /// @brief Bitmap width
  uint8_t const m_width;

  /// @brief bitmap virtual height
  uint8_t const m_mapheight;
  /// @brief Bitmap virtual width  
  uint8_t const m_mapwidth;
  
  /// @brief Spacing between characters
  uint8_t const m_spacing;
  /// @brief Number of characters in the character set bit map
  

  uint8_t const m_chars;
  char const *m_data;

  unsigned char const m_mult;  //
  unsigned char const m_shift; // bit shift after multiplication
  unsigned char const m_round; // round up value 0.5 << shift
};

class font5x7_t : public font_t
{
public:
  // one byte of pixels per character row.
  font5x7_t(unsigned char_count, char const *data) : font_t(7, 5, 6, char_count, data, 1, 0){};

  char
  getPixel(char c, int x, int y) override;
};

class font10x18_t : public font_t
{
public:
  
  // XBM format with optional multiply, right shift scaling of coordinates
  font10x18_t(unsigned char_count, char const *data, unsigned char mult=1, unsigned char shift=0) : font_t(18,10,10, char_count, data, mult, shift){};

  char
  getPixel(char c, int x, int y) override;
};

// defined fonts
// original 5x7
extern font5x7_t small_font;

// lucida font
// in 10x18
extern font10x18_t large_font;

// scaled down lucida font
// in 5 x 9
extern font10x18_t medium_font;