/*
 * DWN - Desktop Window Manager
 * retoor <retoor@molodetz.nl>
 * Window marks implementation
 */

#include "marks.h"
#include "client.h"
#include "workspace.h"
#include "notifications.h"
#include "util.h"

#include <string.h>
#include <ctype.h>

typedef enum {
    MARKS_MODE_NONE,
    MARKS_MODE_SET,
    MARKS_MODE_GOTO
} MarksMode;

static Client *marked_clients[MAX_MARKS];
static MarksMode current_mode = MARKS_MODE_NONE;

void marks_init(void)
{
    memset(marked_clients, 0, sizeof(marked_clients));
    current_mode = MARKS_MODE_NONE;
    LOG_INFO("Window marks system initialized");
}

void marks_cleanup(void)
{
    marks_clear_all();
}

static int mark_to_index(char mark)
{
    char lower = (char)tolower((unsigned char)mark);
    if (lower >= 'a' && lower <= 'z') {
        return lower - 'a';
    }
    return -1;
}

void marks_set(char mark, Client *client)
{
    int idx = mark_to_index(mark);
    if (idx < 0 || client == NULL) {
        return;
    }

    for (int i = 0; i < MAX_MARKS; i++) {
        if (marked_clients[i] == client) {
            marked_clients[i] = NULL;
        }
    }

    marked_clients[idx] = client;

    char msg[128];
    snprintf(msg, sizeof(msg), "Window marked as '%c'", mark);
    notification_show("DWN Marks", "Mark Set", msg, NULL, 1500);

    LOG_DEBUG("Set mark '%c' for window '%s'", mark, client->title);
}

Client *marks_get(char mark)
{
    int idx = mark_to_index(mark);
    if (idx < 0) {
        return NULL;
    }
    return marked_clients[idx];
}

void marks_clear(char mark)
{
    int idx = mark_to_index(mark);
    if (idx >= 0) {
        marked_clients[idx] = NULL;
    }
}

void marks_clear_all(void)
{
    memset(marked_clients, 0, sizeof(marked_clients));
}

void marks_remove_client(Client *client)
{
    if (client == NULL) {
        return;
    }

    for (int i = 0; i < MAX_MARKS; i++) {
        if (marked_clients[i] == client) {
            marked_clients[i] = NULL;
        }
    }
}

bool marks_is_waiting_for_mark(void)
{
    return current_mode == MARKS_MODE_SET;
}

bool marks_is_waiting_for_goto(void)
{
    return current_mode == MARKS_MODE_GOTO;
}

void marks_start_set_mode(void)
{
    Workspace *ws = workspace_get_current();
    if (ws == NULL || ws->focused == NULL) {
        notification_show("DWN Marks", "No Window",
                          "Focus a window first to set a mark", NULL, 2000);
        return;
    }

    current_mode = MARKS_MODE_SET;
    notification_show("DWN Marks", "Set Mark",
                      "Press a-z to set mark for this window", NULL, 0);
}

void marks_start_goto_mode(void)
{
    current_mode = MARKS_MODE_GOTO;
    notification_show("DWN Marks", "Go to Mark",
                      "Press a-z to jump to marked window", NULL, 0);
}

void marks_cancel_mode(void)
{
    if (current_mode != MARKS_MODE_NONE) {
        current_mode = MARKS_MODE_NONE;
        notification_close_all();
    }
}

bool marks_handle_key(char key)
{
    if (current_mode == MARKS_MODE_NONE) {
        return false;
    }

    char lower = (char)tolower((unsigned char)key);
    if (lower < 'a' || lower > 'z') {
        marks_cancel_mode();
        return true;
    }

    notification_close_all();

    if (current_mode == MARKS_MODE_SET) {
        Workspace *ws = workspace_get_current();
        if (ws != NULL && ws->focused != NULL) {
            marks_set(lower, ws->focused);
        }
    } else if (current_mode == MARKS_MODE_GOTO) {
        Client *c = marks_get(lower);
        if (c != NULL) {
            if (c->workspace != (unsigned int)dwn->current_workspace) {
                workspace_switch((int)c->workspace);
            }
            client_focus(c, true);
            client_raise(c);
        } else {
            char msg[64];
            snprintf(msg, sizeof(msg), "No window marked as '%c'", lower);
            notification_show("DWN Marks", "Mark Not Found", msg, NULL, 1500);
        }
    }

    current_mode = MARKS_MODE_NONE;
    return true;
}

char marks_get_mark_for_client(Client *client)
{
    if (client == NULL) {
        return '\0';
    }

    for (int i = 0; i < MAX_MARKS; i++) {
        if (marked_clients[i] == client) {
            return (char)('a' + i);
        }
    }

    return '\0';
}
