#pragma once

#include <unordered_map>
#include "ofMain.h"
//#include "ofTrueTypeFont.h"
//#include "msdfgen.h"
//#include "msdfgen-ext.h"
#include <msdf-atlas-gen/msdf-atlas-gen.h>
//#include <msdf-atlas-gen/types.h>
//#include "import-font.h"
#include "conversion.h"
//#include "BitmapRef.hpp"
//#include "GlyphBox.h"
//#include "conversion.h"
//#include "edge-coloring.h"
//#include "import-font.h"
//#include "ofFileUtils.h"
//#include "ofTrueTypeFont.h"
//#include <cstdlib>
//#include <set>

namespace ofxMsdfgen {
struct AtlasSettings {
    float maxCornerAngle = 3.0;
    float scale = 24.0;
    float minimumScale = 24.0;
    float pixelRange = 2.0;
    float miterLimit = 1.0;
    float maxInterpolationStepSize = 42.0;
    string characters = "charset::ascii";
    #ifdef TARGET_EMSCRIPTEN
        int threadCount = 1;
    #else
        int threadCount = 4;
    #endif
};
struct FontVariation {
    string name;
    float value;
    bool operator==(const FontVariation & other) const {
        return (name == other.name
                && value == other.value);
    }
};
struct FontVariationAxis {
    string name;
    float minValue;
    float maxValue;
    float defaultValue;
};
struct GlyphVariationKey {
    unsigned char character;
    FontVariation variation;

    bool operator==(const GlyphVariationKey & other) const {
        return (character == other.character
                && variation.name == other.variation.name
                && variation.value == other.variation.value);
    }
};
bool compareFontVariations(const FontVariation & a, const FontVariation & b);

}
namespace std {
template <>
struct hash <ofxMsdfgen::GlyphVariationKey> {
    std::size_t operator()(const ofxMsdfgen::GlyphVariationKey & k) const {
        using std::size_t;
        using std::hash;
        using std::string;

        // Compute individual hash values for first,
        // second and third and combine them using XOR
        // and bit shifting:

        return ((hash <unsigned char>()(k.character)
                 ^ (hash <string>()(k.variation.name) << 1)) >> 1)
               ^ (hash <float>()(k.variation.value) << 1);
    }
};
}
namespace ofxMsdfgen {
class Atlas {
    public:
        Atlas();
        ~Atlas();
        void setup(string _fontPath);
        void setup(string _fontPath, AtlasSettings _settings);
        void addVariations(vector <FontVariation> variations);
        bool generate(bool useCache = true,
                      bool saveToCache = false);
        const ofImage & getAtlasImage();
        const vector <GlyphGeometry> & getGlyphGeometries();
        const GlyphGeometry & getGlyphGeometry(unsigned char character);
        const GlyphGeometry & getGlyphGeometry(unsigned char character,
                                               FontVariation variation);
        bool getGlyphGeometryPair(const unsigned char character,
                                  const FontVariation variation,
                                  GlyphGeometry & a,
                                  GlyphGeometry & b,
                                  float & mix);

        //const GlyphGeometry & getGlyphGeometry(GlyphVariationKey key);
        const FontGeometry & getFontGeometry();
        const vector <FontVariationAxis> & getVariationAxesAvailable();
        AtlasSettings settings;
        msdfgen::FontHandle * font;
        msdfgen::FreetypeHandle * ft;
        string getAtlasPathDir();
        string getAtlasPath();
    private:
        string fontPath;
        ofImage atlasImage;
        vector <GlyphGeometry> glyphGeometries;
        unordered_map <GlyphVariationKey, int> glyphGeometryMap;
        vector <FontVariationAxis> variationAxesAvailable;
        vector <FontVariation> variationExtremes;
        vector <FontVariation> variationSteps;
        FontGeometry fontGeometry;
};
}
