//
//  Font.h
//  DescriptionHere
//
//  Created by John Ryland (jryland@xiaofrog.com) on 02/12/2017.
//  Copyright 2017 InvertedLogic. All rights reserved.
//
#pragma once
#include "Common.h"
#include "Graphics.h"
BEGIN_NAMESPACE

// Public API

struct PointF
{
  float m_x, m_y;
};


struct Curve
{
  PointF m_controlPoints[3];
};


struct Glyph
{
  Vector<Curve> m_lines;
};


struct OutlineText
{
  Vector<Glyph> m_text;
};


//
// This is to be able to call setFont on the painter or widget
//
// internally need to add the used fonts to a font manager inside Application
// so that re-used fonts don't maintain two copies in memory. Each font that
// is in use needs to maintain a mmap open handle. It then also needs to have
// a cache of the raw un-scaled glyph outlines. And then a cache of rasterized
// bitmaps of these for various sizes.
//
// The un-scaled glyph outlines can on demand be scaled and positioned for each
// time an outline is requested, or for each time rasterization needs to take place.
//
// Where to do the colorizing? During rasterization or after?
// How about ClearType / Sub-Pixel effects? This requires the color or perhaps
// strategy is to rasterize without color at a higher x-resolution. I'm already
// thinking that to do anti-aliasing, to rasterize at a higher resolution and
// smoothly down-scale it. Possibly with GPU acceleration, this can be offloaded to
// the GPU, so it might be an idea to rasterize to a given resolution and scale and
// colorize there.
//
class Font
{
public:
  Font();
  Font(const char* a_fontFamily, float a_pointSize);
  ~Font();
  void setFontFamily();
  void setPointSize(float a_pointSize);
  // setColor ?

  OutlineText asOutline(const char* a_text);

private:
  struct FontData;
  //FontData* m_data; // TODO: if make a copy of a Font, this raw pointer is copied
                    // then in the destructor it deletes it which the other has a hold of
                    // therefore need to solve - copyConstructor + assignment impl, or shared_ptr
                    // Need to check other classes and use a consistent safe solution
  SharedPtr<FontData> m_data;
};



//
// This is internal implementation detail
//
class FontFixedPoint
{
public:
  FontFixedPoint() {}
  FontFixedPoint(int16_t x, int16_t y) // values should be already in fixed-point 
    : m_x(x), m_y(y)
  {
  }
  // Raw fixed-point value
  int16_t x() const { return m_x; }
  int16_t y() const { return m_y; }
  // As a float
  float  xf() const { return float(m_x) * scale; }
  float  yf() const { return float(m_y) * scale; }
private:
  const unsigned int shiftBits = 10;
  const float scale = 1.0f / float(1 << shiftBits);
  int16_t  m_x = 0, m_y = 0;
};


struct FontCurveFixed
{
  FontFixedPoint m_controlPoints[3];
};


struct FontGlyphFixed
{
  //Vector<FontCurve> m_lines;
  Vector<Curve> m_lines;
};


class RasterizedFont
{
public:
  RasterizedFont(const char* a_family, float a_pointSize, uint32_t a_color);
	   
  // class _Hash = hash<_Key>
	// class _Pred = std::equal_to<_Key>

  static uint32_t hash(const char* a_family, float a_pointSize, uint32_t a_color)
  {
    std::string family = a_family;
    // uint32_t hash = family.hash();
    uint32_t hash1 = std::hash<std::string>{}(family);
    hash1 += uint32_t(a_pointSize * 100.0f);
    hash1 ^= a_color;
    return hash1;
  }

  int compare(const char* a_family, float a_pointSize, uint32_t a_color)
  {
    int ret = strcmp(a_family, m_family.c_str());
    if (ret != 0)
      return ret;
    ret = (a_pointSize < m_pointSize) ? -1 : ((a_pointSize > m_pointSize) ? 1 : 0);
    if (ret != 0)
      return ret;
    return (a_color < m_color) ? -1 : ((a_color > m_color) ? 1 : 0);
  }

  int getIndexForValues(float a_pointSize, uint32_t a_color);
  int index();

private:
  String m_family;
  float m_pointSize;
  uint32_t m_color;

  Cache<int, PixelBuffer>  m_glyphCache;
};


class ManagedFont
{
public:

  void getRasterizedGlyph(const char* a_family, float a_size, uint32_t a_color);


private:
  // For bitmap glyph caching, need to look up based on both the pointsize and the index
  // also how about color too? Perhaps another layer needed here.
  //Cache<int, FontGlyphFixed>  m_glyphCache;

  // class _Hash = hash<_Key>
	// class _Pred = std::equal_to<_Key>
  Cache<int, RasterizedFont>  m_rasterCache;

  // If idea is to use the GPU, one raster size might be better. Turn the font in to
  // like a sprite-sheet and render the glyphs out of the font texture - can scale and
  // colorize in a shader.
  // Using shaders, can also do signed-distance fields.
  Cache<int, PixelBuffer>  m_glyphCache;
};


class FontManager
{
public:
  FontManager();
  ~FontManager();

  Vector<String> getAvailableFontNames();

  ManagedFont& getFont(String fontName);

  Cache<String, ManagedFont> m_loadedFonts;
};

END_NAMESPACE

