module patch.font2;

import std.conv : to;
import std.string : toStringz;

import patches : isPatchEnabled;
import config : font2;
import st : xw, xrealloc, die;
import xft_types : XftFont;
import deimos.X11.Xlib : Display;

// Import font cache variables from x module
import x : Fontcache, frc, frclen, frccap, defaultfontsize, usedfontsize;

enum FRC_NORMAL = 0;
enum FRC_ITALIC = 1;
enum FRC_BOLD = 2;
enum FRC_ITALICBOLD = 3;

// External C declarations for Xft and fontconfig functions
extern(C) {
    struct FcPattern;
    alias FcChar8 = ubyte;
    
    // FcResult as an enum
    enum FcResult {
        FcResultMatch = 0,
        FcResultNoMatch,
        FcResultTypeMismatch,
        FcResultNoId,
        FcResultOutOfMemory
    }
    
    // Xft functions
    XftFont* XftFontOpenPattern(Display*, FcPattern*);
    FcPattern* XftXlfdParse(const(char)*, int, int);
    void XftDefaultSubstitute(Display*, int, FcPattern*);
    static if (isPatchEnabled!"USE_XFTFONTMATCH_PATCH") {
        FcPattern* XftFontMatch(Display*, int, FcPattern*, FcResult*);
    }
    
    // Fontconfig functions
    void FcPatternDestroy(FcPattern*);
    FcPattern* FcNameParse(const(FcChar8)*);
    int FcPatternGetDouble(FcPattern*, const(char)*, int, double*);
    int FcPatternDel(FcPattern*, const(char)*);
    int FcPatternAddDouble(FcPattern*, const(char)*, double);
    int FcPatternAddBool(FcPattern*, const(char)*, int);
    int FcPatternAddInteger(FcPattern*, const(char)*, int);
    void FcConfigSubstitute(void*, FcPattern*, int);
    FcPattern* FcFontMatch(void*, FcPattern*, FcResult*);
    
    // Constants
    enum FC_PIXEL_SIZE = "pixelsize";
    enum FC_SIZE = "size";
    enum FC_SCALABLE = "scalable";
    enum FC_SLANT = "slant";
    enum FC_WEIGHT = "weight";
    enum FC_SLANT_ITALIC = 100;
    enum FC_SLANT_ROMAN = 0;
    enum FC_WEIGHT_BOLD = 200;
    enum FcResultMatch = 0;
    enum FcMatchPattern = 0;
}

static if (isPatchEnabled!"FONT2_PATCH") {
    int xloadsparefont(FcPattern* pattern, int flags) {
        FcPattern* match;
        FcResult result;

        static if (isPatchEnabled!"USE_XFTFONTMATCH_PATCH") {
            match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
        } else {
            match = FcFontMatch(null, pattern, &result);
        }
        
        if (!match) {
            return 1;
        }

        frc[frclen].font = XftFontOpenPattern(xw.dpy, match);
        if (!frc[frclen].font) {
            FcPatternDestroy(match);
            return 1;
        }

        frc[frclen].flags = flags;
        frc[frclen].unicodep = 0;
        frclen++;

        return 0;
    }

    void xloadsparefonts() {
        FcPattern* pattern;
        double fontval;
        int fc;

        if (frclen != 0)
            die("can't embed spare fonts. cache isn't empty");

        fc = cast(int)font2.length;
        if (fc == 0)
            return;

        if (frccap < 4 * fc) {
            frccap += 4 * fc - frccap;
            frc = cast(Fontcache*)xrealloc(frc, frccap * Fontcache.sizeof);
        }

        foreach (i, fp; font2) {
            if (fp[0] == '-')
                pattern = XftXlfdParse(fp.toStringz, 0, 0);
            else
                pattern = FcNameParse(cast(FcChar8*)fp.toStringz);

            if (!pattern)
                die("can't open spare font %s\n", fp.toStringz);

            if (defaultfontsize > 0 && defaultfontsize != usedfontsize) {
                if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == 
                        FcResultMatch) {
                    fontval *= usedfontsize / defaultfontsize;
                    FcPatternDel(pattern, FC_PIXEL_SIZE);
                    FcPatternDel(pattern, FC_SIZE);
                    FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval);
                } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) == 
                        FcResultMatch) {
                    fontval *= usedfontsize / defaultfontsize;
                    FcPatternDel(pattern, FC_PIXEL_SIZE);
                    FcPatternDel(pattern, FC_SIZE);
                    FcPatternAddDouble(pattern, FC_SIZE, fontval);
                }
            }

            FcPatternAddBool(pattern, FC_SCALABLE, 1);

            static if (!isPatchEnabled!"USE_XFTFONTMATCH_PATCH") {
                FcConfigSubstitute(null, pattern, FcMatchPattern);
                XftDefaultSubstitute(xw.dpy, xw.scr, pattern);
            }

            if (xloadsparefont(pattern, FRC_NORMAL))
                die("can't open spare font %s\n", fp.toStringz);

            FcPatternDel(pattern, FC_SLANT);
            FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
            if (xloadsparefont(pattern, FRC_ITALIC))
                die("can't open spare font %s\n", fp.toStringz);

            FcPatternDel(pattern, FC_WEIGHT);
            FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
            if (xloadsparefont(pattern, FRC_ITALICBOLD))
                die("can't open spare font %s\n", fp.toStringz);

            FcPatternDel(pattern, FC_SLANT);
            FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
            if (xloadsparefont(pattern, FRC_BOLD))
                die("can't open spare font %s\n", fp.toStringz);

            FcPatternDestroy(pattern);
        }
    }
}