module patch.background_image;

import st;
import x;
import config;
import patches;
import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;
import deimos.X11.Xlib;
import deimos.X11.X;
import deimos.X11.Xutil;

static if (isPatchEnabled!"BACKGROUND_IMAGE_PATCH") {
    import core.sys.posix.arpa.inet : ntohl;
    
    void updatexy() {
        Window child;
        XTranslateCoordinates(xw.dpy, xw.win, DefaultRootWindow(xw.dpy), 
                              0, 0, &win.x, &win.y, &child);
    }
    
    /*
     * load farbfeld file to XImage
     */
    XImage* loadff(const(char)* filename) {
        uint[4] hdr;
        uint w, h, size;
        ulong* data;
        FILE* f = fopen(filename, "rb".ptr);
        
        if (f is null) {
            fprintf(stderr, "could not load background image.\n");
            return null;
        }
        
        if (fread(hdr.ptr, uint.sizeof, hdr.length, f) != hdr.length) {
            fprintf(stderr, "fread: %s\n", ferror(f) ? "".ptr : "Unexpected end of file reading header");
            fclose(f);
            return null;
        }
        
        if (memcmp("farbfeld".ptr, hdr.ptr, "farbfeld".length - 1) != 0) {
            fprintf(stderr, "Invalid magic value\n");
            fclose(f);
            return null;
        }
        
        w = ntohl(hdr[2]);
        h = ntohl(hdr[3]);
        size = w * h;
        data = cast(ulong*)xmalloc(size * ulong.sizeof);
        
        if (fread(data, ulong.sizeof, size, f) != size) {
            fprintf(stderr, "fread: %s\n", ferror(f) ? "".ptr : "Unexpected end of file reading data");
            fclose(f);
            free(data);
            return null;
        }
        
        fclose(f);
        
        for (uint i = 0; i < size; i++) {
            data[i] = (data[i] & 0x00000000000000FF) << 16 |
                      (data[i] & 0x0000000000FF0000) >> 8  |
                      (data[i] & 0x000000FF00000000) >> 32 |
                      (data[i] & 0x00FF000000000000) >> 24;
        }
        
        static if (isPatchEnabled!"ALPHA_PATCH") {
            XImage* xi = XCreateImage(xw.dpy, xw.vis, xw.depth, ZPixmap, 0,
                cast(char*)data, w, h, 32, w * 8);
        } else {
            XImage* xi = XCreateImage(xw.dpy, DefaultVisual(xw.dpy, xw.scr),
                DefaultDepth(xw.dpy, xw.scr), ZPixmap, 0,
                cast(char*)data, w, h, 32, w * 8);
        }
        xi.bits_per_pixel = 64;
        return xi;
    }
    
    /*
     * initialize background image
     */
    extern(C) void bginit() {
        XGCValues gcvalues;
        Drawable bgimg;
        XImage* bgxi = loadff(config.bgfile.ptr);
        
        memset(&gcvalues, 0, XGCValues.sizeof);
        xw.bggc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues);
        if (!bgxi)
            return;
            
        static if (isPatchEnabled!"ALPHA_PATCH") {
            bgimg = XCreatePixmap(xw.dpy, xw.win, bgxi.width, bgxi.height, xw.depth);
        } else {
            bgimg = XCreatePixmap(xw.dpy, xw.win, bgxi.width, bgxi.height,
                DefaultDepth(xw.dpy, xw.scr));
        }
        
        XPutImage(xw.dpy, bgimg, dc.gc, bgxi, 0, 0, 0, 0, bgxi.width, bgxi.height);
        XDestroyImage(bgxi);
        XSetTile(xw.dpy, xw.bggc, bgimg);
        XSetFillStyle(xw.dpy, xw.bggc, FillTiled);
        
        if (config.pseudotransparency) {
            updatexy();
            xw.attrs.event_mask |= PropertyChangeMask;
            XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
        }
    }
    
    static if (isPatchEnabled!"BACKGROUND_IMAGE_RELOAD_PATCH") {
        void reload_image() {
            XGCValues gcvalues;
            Drawable bgimg;
            
            // Recreate background GC
            if (xw.bggc)
                XFreeGC(xw.dpy, xw.bggc);
                
            memset(&gcvalues, 0, XGCValues.sizeof);
            xw.bggc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues);
            
            XImage* bgxi = loadff(config.bgfile.ptr);
            if (!bgxi)
                return;
                
            static if (isPatchEnabled!"ALPHA_PATCH") {
                bgimg = XCreatePixmap(xw.dpy, xw.win, bgxi.width, bgxi.height, xw.depth);
            } else {
                bgimg = XCreatePixmap(xw.dpy, xw.win, bgxi.width, bgxi.height,
                    DefaultDepth(xw.dpy, xw.scr));
            }
            
            XPutImage(xw.dpy, bgimg, dc.gc, bgxi, 0, 0, 0, 0, bgxi.width, bgxi.height);
            XDestroyImage(bgxi);
            XSetTile(xw.dpy, xw.bggc, bgimg);
            XSetFillStyle(xw.dpy, xw.bggc, FillTiled);
            
            if (config.pseudotransparency) {
                updatexy();
            }
            redraw();
        }
    }
}