#include "X11/Xlib.h"
#include <X11/Xutil.h>
#include <stdlib.h>
#include <stdio.h>

#include "include/window_manager.h"
#include "include/taskbar_draw.h"
#include "include/window_draw.h"

#include <assert.h>

struct linked_window minimized_windows;

Window taskbar;

#define APP_WIDTH_BASE 100

int count_minimized_windows() {
    linked_window * curr = &minimized_windows;
    int count = 0;
    while (curr->next != NULL) {
        curr = curr->next;
        count ++;
    }
    return count;
}

void unmap_all_frames() {
    linked_window * curr = &minimized_windows;
    while (curr->next != NULL) {
        curr = curr->next;
        XDestroyWindow(X_display, curr->frame);
    }
}

linked_window * find_minimized_by_frame(Window w) {
    linked_window *curr_check = &minimized_windows;
    while (curr_check->next != NULL){
        curr_check = curr_check->next;
        if (curr_check->frame == w) {
            return curr_check;
        }
    }
    return NULL;
}

void add_minimized_client(Window w, Window frame) {
    linked_window * curr_ptr = &minimized_windows;
    while (curr_ptr->next != NULL) {
        curr_ptr = curr_ptr->next;
    }
    linked_window * new = malloc(sizeof(linked_window));
    new->prev = curr_ptr;
    curr_ptr->next = new;
    new->client = w;
    new->frame = frame;
    new->next = NULL; // to be sure
}

void remove_minimized_client_by_frame(Window frame) {
    linked_window * removal = find_minimized_by_frame(frame);
    if (removal == NULL) return;
    assert(removal->prev != NULL && "Cannot remove taskbar!");
    removal->prev->next = removal->next;
    if (removal->next != NULL) {
        removal->next->prev = removal->prev;
    }
    free(removal);
}

GC context;

void create_taskbar() {
    int height = XHeightOfScreen(XDefaultScreenOfDisplay(X_display)), width = XWidthOfScreen(XDefaultScreenOfDisplay(X_display));
    taskbar = XCreateSimpleWindow(X_display, root_window, 0, height-TASKBAR_HEIGHT, width, TASKBAR_HEIGHT, 2, 0x333333, 0x505050);
    minimized_windows = (struct linked_window) {
        .client = 0,
        .frame = taskbar,
        .next = NULL,
        .prev = NULL
    };
    XMapWindow(X_display, taskbar);
    XSelectInput(X_display, taskbar, SubstructureNotifyMask | SubstructureRedirectMask);
    context = DefaultGC(X_display, DefaultScreen(X_display));
    XSetBackground(X_display, context, 0x333333);
    XSetForeground(X_display, context, 0x888888);
}

#define min(a, b) a<b?a:b

void redraw_taskbar() {
    unmap_all_frames();
    int count = count_minimized_windows();
    if (count == 0) return;
    int width = min(APP_WIDTH_BASE, XHeightOfScreen(XDefaultScreenOfDisplay(X_display))/count);

    linked_window * curr = &minimized_windows;
    int counter = 0;
    XTextProperty title;
    while (curr->next != NULL) {
        curr = curr->next;
        curr->frame = XCreateSimpleWindow(X_display, taskbar, width*counter+2, 0, width-4, TASKBAR_HEIGHT, 1, 0x777777, 0x666666);
        XSelectInput(X_display, curr->frame, ButtonPressMask);        
        XMapWindow(X_display, curr->frame);
        XClearWindow(X_display, curr->frame);
        if (XGetWMName(X_display, curr->client, &title) != 0) {
            Xutf8DrawString(X_display, curr->frame, wm_default_fontset, context, 0, 12, (char*)title.value, title.nitems);
            free(title.value);
        }

        counter ++;
    }

}

void add_minimized(Window w) {
    add_minimized_client(w, 0);
    redraw_taskbar();
}

void minimize_window(linked_window window) {
    //XWithdrawWindow(X_display, window.client, DefaultScreen(X_display));
    XIconifyWindow(X_display, window.client, DefaultScreen(X_display));
    XUnmapWindow(X_display, window.client);
    add_minimized(window.client);
}

void restore_window(Window frame) {
    linked_window * window = find_minimized_by_frame(frame);
    if (window == NULL) return;

    reframe_decorate(window->client);
    XMapWindow(X_display, window->client);
    remove_minimized_client_by_frame(window->frame);
    XDestroyWindow(X_display, window->frame);
    redraw_taskbar();
}