#pragma once

#include <stdint.h>
#include <stdbool.h>
#include <char32.h>

#include <wlr-layer-shell-unstable-v1.h>

#include <tllist.h>
#include <xkbcommon/xkbcommon.h>

#define DEFINE_LIST(type) \
    type##_list {         \
        size_t count;     \
        type *arr;        \
    }

struct rgba {double r; double g; double b; double a;};
struct pt_or_px {int px; float pt;};

enum dpi_aware {
    DPI_AWARE_AUTO,
    DPI_AWARE_YES,
    DPI_AWARE_NO,
};

enum dmenu_mode {
    DMENU_MODE_TEXT,
    DMENU_MODE_INDEX,
};

enum match_fields {
    MATCH_FILENAME =   0x01,
    MATCH_NAME =       0x02,
    MATCH_GENERIC =    0x04,
    MATCH_EXEC =       0x08,
    MATCH_CATEGORIES = 0x10,
    MATCH_KEYWORDS =   0x20,
    MATCH_COMMENT =    0x40,
};

struct config_key_modifiers {
    bool shift;
    bool alt;
    bool ctrl;
    bool super;
};

struct config_key_binding {
    int action;  /* One of the varios bind_action_* enums from wayland.h */
    struct config_key_modifiers modifiers;
    union {
        /* Key bindings */
        struct {
            xkb_keysym_t sym;
        } k;

#if 0
        /* Mouse bindings */
        struct {
            int button;
            int count;
        } m;
#endif
    };

    /* For error messages in collision handling */
    const char *path;
    int lineno;
};
DEFINE_LIST(struct config_key_binding);

struct config {
    char *output;
    char32_t *prompt;
    enum match_fields match_fields;

    struct {
        char32_t character;
        bool enabled;
    } password_mode;

    char *terminal;
    char *launch_prefix;

    char *font;
    enum dpi_aware dpi_aware;

    bool filter_desktop;

    bool icons_enabled;
    char *icon_theme;

    bool actions_enabled;

    struct config_key_binding_list key_bindings;

    struct {
        size_t min_length;
        size_t max_length_discrepancy;
        size_t max_distance;
        bool enabled;
    } fuzzy;

    struct {
        bool enabled;
        enum dmenu_mode mode;
        bool exit_immediately_if_empty;
        char delim;
    } dmenu;

    unsigned lines;
    unsigned chars;
    unsigned tabs;  /* Tab stop every number of #spaces */

    struct {
        unsigned x;
        unsigned y;
        unsigned inner;
    } pad;

    struct {
        struct rgba background;
        struct rgba border;
        struct rgba text;
        struct rgba match;
        struct rgba selection;
        struct rgba selection_text;
        struct rgba selection_match;
    } colors;

    struct {
        unsigned size;
        unsigned radius;
    } border;

    float image_size_ratio;

    struct pt_or_px line_height;
    struct pt_or_px letter_spacing;

    enum zwlr_layer_shell_v1_layer layer;
    bool exit_on_kb_focus_loss;
};

typedef tll(char *) config_override_t;

bool config_load(
    struct config *conf, const char *path, const config_override_t *overrides,
    bool errors_are_fatal);
void config_free(struct config *conf);

struct rgba conf_hex_to_rgba(uint32_t color);
