#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "img/image.h"
#include "types.h"
#include "color_bits.h"

Window create_window(Display *dpy, int xsz, int ysz);
XImage *create_ximage(Display *dpy, int xsz, int ysz, uint32_t *img);
void event_loop(Display *dpy, Window win, XImage *ximg);

int main(int argc, char **argv) {
    Display *dpy;
    Window win;
    XImage *ximg;
    int i;
    uint32_t *img;
    unsigned long xsz, ysz;

    if(!(dpy = XOpenDisplay(0))) {
        fprintf(stderr, "Could not connect to the X server\n");
        return EXIT_FAILURE;
    }

    for(i=1; i<argc; i++) {
        if(argv[i][0] == '-') {
            fprintf(stderr, "unrecognized argument: %s\n", argv[i]);
            break;
        } else {
            if(!(img = load_image(argv[i], &xsz, &ysz))) {
                continue;
            }
            win = create_window(dpy, xsz, ysz);
            ximg = create_ximage(dpy, xsz, ysz, img);

            if(win && ximg) {
                event_loop(dpy, win, ximg);
            }

            if(ximg) XDestroyImage(ximg);
            if(win) XDestroyWindow(dpy, win);
        }
    }

    XCloseDisplay(dpy);
    return 0;
}


Window create_window(Display *dpy, int xsz, int ysz) {
    Window win, root_win;
    int screen;
    XSetWindowAttributes xattr;
    Atom wm_delete;
    XTextProperty tp_wname;
    static char *win_title = "mindlapse :: image viewer";
    XClassHint class_hint;

    screen = DefaultScreen(dpy);
    root_win = RootWindow(dpy, screen);

    xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, screen);
    xattr.colormap = DefaultColormap(dpy, screen);

    win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, CopyFromParent, InputOutput,
            DefaultVisual(dpy, screen), CWColormap | CWBackPixel | CWBorderPixel, &xattr);
    XSelectInput(dpy, win, ExposureMask | StructureNotifyMask | KeyPressMask);

    /* set WM cooperation settings */
    wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
    XSetWMProtocols(dpy, win, &wm_delete, 1);

    XStringListToTextProperty(&win_title, 1, &tp_wname);
    XSetWMName(dpy, win, &tp_wname);
    XFree(tp_wname.value);

    class_hint.res_name = "imgv";
    class_hint.res_class = "imgv_window";
    XSetClassHint(dpy, win, &class_hint);

    XMapWindow(dpy, win);
    XFlush(dpy);

    return win;
}

XImage *create_ximage(Display *dpy, int xsz, int ysz, uint32_t *img) {
    XImage *ximg;
    int screen = DefaultScreen(dpy);

    if(!(ximg = XCreateImage(dpy, DefaultVisual(dpy, screen), 24, ZPixmap, 0, (void*)img, xsz, ysz, 8, 0))) {
        fprintf(stderr, "XCreateImage failed\n");
        return 0;
    }

    return ximg;
}

void event_loop(Display *dpy, Window win, XImage *ximg) {
    KeySym keysym;
    int window_mapped = 0;

    while(1) {
        XEvent event;
        XNextEvent(dpy, &event);

        switch(event.type) {
        case MapNotify:
            window_mapped = 1;
            break;

        case UnmapNotify:
            window_mapped = 0;
            break;

        case Expose:
            if(window_mapped && event.xexpose.count == 0) {
                GC gc = XCreateGC(dpy, win, 0, 0);
                XPutImage(dpy, win, gc, ximg, 0, 0, 0, 0, ximg->width, ximg->height);
                XFreeGC(dpy, gc);
                XFlush(dpy);
            }
            break;

        case KeyPress:
            keysym = XLookupKeysym((XKeyEvent*)&event.xkey, 0);
            if((keysym & 0xff) == 27) {
                return;
            }
            break;

        case ClientMessage:
            {
                char *atom_name = XGetAtomName(dpy, event.xclient.message_type);
                if(!strcmp(atom_name, "WM_PROTOCOLS")) {
                    XFree(atom_name);
                    return;
                }
                XFree(atom_name);
            }
            break;

        default:
            break;
        }
    }
}