/*
 * DWN - Desktop Window Manager
 * Backend Abstraction Interface
 */

#ifndef BACKEND_INTERFACE_H
#define BACKEND_INTERFACE_H

#include "core/wm_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/*==============================================================================
 * Backend Capabilities
 *============================================================================*/

typedef enum {
    WM_BACKEND_CAP_WINDOWS        = (1 << 0),
    WM_BACKEND_CAP_COMPOSITING    = (1 << 1),
    WM_BACKEND_CAP_TRANSPARENCY   = (1 << 2),
    WM_BACKEND_CAP_ANIMATIONS     = (1 << 3),
    WM_BACKEND_CAP_MULTI_MONITOR  = (1 << 4),
    WM_BACKEND_CAP_INPUT_EVENTS   = (1 << 5),
    WM_BACKEND_CAP_CLIPBOARD      = (1 << 6),
    WM_BACKEND_CAP_DRAG_DROP      = (1 << 7),
    WM_BACKEND_CAP_TOUCH          = (1 << 8),
    WM_BACKEND_CAP_GESTURES       = (1 << 9)
} WmBackendCapabilities;

/*==============================================================================
 * Backend Information
 *============================================================================*/

typedef struct {
    const char *name;
    const char *version;
    const char *description;
    uint32_t capabilities;
    bool supports_multiple_instances;
    bool requires_compositor;
} WmBackendInfo;

/*==============================================================================
 * Backend Event Types
 *============================================================================*/

typedef enum {
    WM_BACKEND_EVENT_NONE,
    WM_BACKEND_EVENT_EXPOSE,
    WM_BACKEND_EVENT_CONFIGURE,
    WM_BACKEND_EVENT_MAP,
    WM_BACKEND_EVENT_UNMAP,
    WM_BACKEND_EVENT_DESTROY,
    WM_BACKEND_EVENT_FOCUS_IN,
    WM_BACKEND_EVENT_FOCUS_OUT,
    WM_BACKEND_EVENT_KEY_PRESS,
    WM_BACKEND_EVENT_KEY_RELEASE,
    WM_BACKEND_EVENT_BUTTON_PRESS,
    WM_BACKEND_EVENT_BUTTON_RELEASE,
    WM_BACKEND_EVENT_MOTION,
    WM_BACKEND_EVENT_ENTER,
    WM_BACKEND_EVENT_LEAVE,
    WM_BACKEND_EVENT_PROPERTY,
    WM_BACKEND_EVENT_CLIENT_MESSAGE,
    WM_BACKEND_EVENT_SELECTION,
} WmBackendEventType;

typedef struct {
    WmBackendEventType type;
    WmWindowHandle window;
    WmTime timestamp;
    union {
        struct { int x, y, width, height; } configure;
        struct { int x, y; } point;
        struct { unsigned int keycode; unsigned int state; } key;
        struct { unsigned int button; int x, y; unsigned int state; } button;
        struct { const char *name; const void *data; size_t size; } property;
    } data;
} WmBackendEvent;

/*==============================================================================
 * Backend Interface Definition
 *============================================================================*/

typedef struct BackendInterface {
    /* Identification */
    const char *name;
    WmBackendInfo (*get_info)(void);
    
    /* Lifecycle */
    bool (*init)(void *config);
    void (*shutdown)(void);
    bool (*is_initialized)(void);
    
    /* Connection */
    bool (*connect)(void);
    void (*disconnect)(void);
    bool (*is_connected)(void);
    int (*get_file_descriptor)(void);
    void (*flush)(void);
    void (*sync)(void);
    
    /* Screen/Display */
    void (*get_screen_dimensions)(int *width, int *height);
    int (*get_screen_count)(void);
    void (*get_screen_geometry)(int screen, WmRect *geometry);
    
    /* Monitor Management */
    int (*get_monitor_count)(void);
    void (*get_monitor_geometry)(int monitor, WmRect *geometry);
    bool (*get_monitor_primary)(int monitor);
    const char* (*get_monitor_name)(int monitor);
    
    /* Work Area */
    void (*get_work_area)(int monitor, WmRect *area);
    void (*set_work_area)(int monitor, const WmRect *area);
    
    /* Window Management - Lifecycle */
    WmWindowHandle (*window_create)(const WmRect *geometry, uint32_t flags);
    void (*window_destroy)(WmWindowHandle window);
    WmWindowHandle (*window_create_frame)(WmWindowHandle parent, const WmRect *geometry);
    
    /* Window Management - Geometry */
    void (*window_get_geometry)(WmWindowHandle window, WmRect *geometry);
    void (*window_set_geometry)(WmWindowHandle window, const WmRect *geometry);
    void (*window_move)(WmWindowHandle window, int x, int y);
    void (*window_resize)(WmWindowHandle window, int width, int height);
    void (*window_move_resize)(WmWindowHandle window, const WmRect *geometry);
    
    /* Window Management - Visibility */
    void (*window_show)(WmWindowHandle window);
    void (*window_hide)(WmWindowHandle window);
    bool (*window_is_visible)(WmWindowHandle window);
    void (*window_map)(WmWindowHandle window);
    void (*window_unmap)(WmWindowHandle window);
    bool (*window_is_mapped)(WmWindowHandle window);
    
    /* Window Management - Stacking */
    void (*window_raise)(WmWindowHandle window);
    void (*window_lower)(WmWindowHandle window);
    void (*window_raise_above)(WmWindowHandle window, WmWindowHandle above);
    void (*window_lower_below)(WmWindowHandle window, WmWindowHandle below);
    void (*window_set_stack_position)(WmWindowHandle window, int position);
    int (*window_get_stack_position)(WmWindowHandle window);
    
    /* Window Management - Reparenting */
    void (*window_reparent)(WmWindowHandle window, WmWindowHandle parent, int x, int y);
    WmWindowHandle (*window_get_parent)(WmWindowHandle window);
    
    /* Window Management - Focus */
    void (*window_focus)(WmWindowHandle window);
    void (*window_unfocus)(WmWindowHandle window);
    bool (*window_is_focused)(WmWindowHandle window);
    WmWindowHandle (*window_get_focused)(void);
    
    /* Window Management - Decoration */
    void (*window_set_decorated)(WmWindowHandle window, bool decorated);
    bool (*window_is_decorated)(WmWindowHandle window);
    void (*window_set_border_width)(WmWindowHandle window, int width);
    int (*window_get_border_width)(WmWindowHandle window);
    void (*window_set_border_color)(WmWindowHandle window, WmColor color);
    
    /* Window Management - Properties */
    void (*window_set_title)(WmWindowHandle window, const char *title);
    char* (*window_get_title)(WmWindowHandle window);
    void (*window_set_class)(WmWindowHandle window, const char *class, const char *instance);
    void (*window_get_class)(WmWindowHandle window, char **class, char **instance);
    void (*window_set_icon_name)(WmWindowHandle window, const char *name);
    
    /* Window Management - Protocols */
    bool (*window_supports_protocol)(WmWindowHandle window, const char *protocol);
    void (*window_send_protocol)(WmWindowHandle window, const char *protocol, WmTime timestamp);
    void (*window_close)(WmWindowHandle window);
    void (*window_kill)(WmWindowHandle window);
    
    /* Window Management - State */
    void (*window_set_fullscreen)(WmWindowHandle window, bool fullscreen);
    bool (*window_is_fullscreen)(WmWindowHandle window);
    void (*window_set_maximized)(WmWindowHandle window, bool maximized);
    bool (*window_is_maximized)(WmWindowHandle window);
    void (*window_set_minimized)(WmWindowHandle window, bool minimized);
    bool (*window_is_minimized)(WmWindowHandle window);
    void (*window_set_modal)(WmWindowHandle window, bool modal);
    void (*window_set_sticky)(WmWindowHandle window, bool sticky);
    void (*window_set_shaded)(WmWindowHandle window, bool shaded);
    void (*window_set_skip_taskbar)(WmWindowHandle window, bool skip);
    void (*window_set_skip_pager)(WmWindowHandle window, bool skip);
    void (*window_set_urgent)(WmWindowHandle window, bool urgent);
    bool (*window_is_urgent)(WmWindowHandle window);
    
    /* Window Management - Type */
    void (*window_set_type)(WmWindowHandle window, WmWindowType type);
    WmWindowType (*window_get_type)(WmWindowHandle window);
    
    /* Window Management - Selection */
    void (*window_set_selection_owner)(WmWindowHandle window, const char *selection, WmTime time);
    WmWindowHandle (*window_get_selection_owner)(const char *selection);
    void (*window_convert_selection)(WmWindowHandle requestor, const char *selection, 
                                      const char *target, WmTime time);
    
    /* Window Management - Client List */
    WmContainer* (*window_get_stacking_list)(void);
    WmContainer* (*window_get_client_list)(void);
    
    /* Input - Events */
    bool (*poll_event)(WmBackendEvent *event);
    void (*wait_event)(WmBackendEvent *event);
    bool (*check_mask_event)(uint32_t mask, WmBackendEvent *event);
    void (*put_back_event)(const WmBackendEvent *event);
    
    /* Input - Key Grabbing */
    void (*grab_key)(int keycode, uint32_t modifiers, WmWindowHandle window, 
                     bool owner_events, uint32_t pointer_mode, uint32_t keyboard_mode);
    void (*ungrab_key)(int keycode, uint32_t modifiers, WmWindowHandle window);
    void (*grab_keyboard)(WmWindowHandle window, bool owner_events, 
                          uint32_t pointer_mode, uint32_t keyboard_mode, WmTime time);
    void (*ungrab_keyboard)(WmTime time);
    
    /* Input - Button Grabbing */
    void (*grab_button)(int button, uint32_t modifiers, WmWindowHandle window,
                        bool owner_events, uint32_t event_mask,
                        uint32_t pointer_mode, uint32_t keyboard_mode,
                        WmWindowHandle confine_to, uint32_t cursor);
    void (*ungrab_button)(int button, uint32_t modifiers, WmWindowHandle window);
    void (*grab_pointer)(WmWindowHandle window, bool owner_events, uint32_t event_mask,
                         uint32_t pointer_mode, uint32_t keyboard_mode,
                         WmWindowHandle confine_to, uint32_t cursor, WmTime time);
    void (*ungrab_pointer)(WmTime time);
    
    /* Input - Pointer */
    void (*query_pointer)(WmWindowHandle window, int *root_x, int *root_y, 
                          int *win_x, int *win_y, uint32_t *mask);
    void (*warp_pointer)(WmWindowHandle dest_w, int dest_x, int dest_y);
    void (*set_cursor)(WmWindowHandle window, uint32_t cursor);
    
    /* Rendering - Basic */
    void (*fill_rectangle)(WmWindowHandle window, const WmRect *rect, WmColor color);
    void (*draw_rectangle)(WmWindowHandle window, const WmRect *rect, WmColor color, int line_width);
    void (*draw_line)(WmWindowHandle window, int x1, int y1, int x2, int y2, 
                      WmColor color, int line_width);
    void (*clear_window)(WmWindowHandle window);
    void (*copy_area)(WmWindowHandle src, WmWindowHandle dst, 
                      int src_x, int src_y, int width, int height,
                      int dst_x, int dst_y);
    
    /* Rendering - Text (if supported) */
    void* (*font_load)(const char *name, int size);
    void (*font_destroy)(void *font);
    int (*font_text_width)(void *font, const char *text, int len);
    void (*draw_text)(WmWindowHandle window, void *font, int x, int y, 
                      const char *text, int len, WmColor color);
    
    /* Rendering - Images (if supported) */
    void* (*image_load)(const uint8_t *data, size_t size);
    void (*image_destroy)(void *image);
    void (*image_get_size)(void *image, int *width, int *height);
    void (*draw_image)(WmWindowHandle window, void *image, int x, int y, 
                       int width, int height);
    
    /* Rendering - Sync */
    void (*begin_paint)(WmWindowHandle window);
    void (*end_paint)(WmWindowHandle window);
    
    /* Atoms/Properties */
    uint32_t (*atom_get)(const char *name);
    const char* (*atom_get_name)(uint32_t atom);
    void (*property_set)(WmWindowHandle window, uint32_t property, uint32_t type,
                         int format, const void *data, int num_items);
    int (*property_get)(WmWindowHandle window, uint32_t property, uint32_t type,
                        void **data, int *num_items);
    void (*property_delete)(WmWindowHandle window, uint32_t property);
    
    /* Session Management */
    void (*set_selection_owner)(WmWindowHandle owner, const char *selection);
    void (*send_client_message)(WmWindowHandle window, const char *message_type,
                                const void *data, int format);
    
    /* Error Handling */
    int (*get_last_error)(void);
    void (*set_error_handler)(int (*handler)(void *display, void *event));
    void (*set_io_error_handler)(int (*handler)(void *display));
    
} BackendInterface;

/*==============================================================================
 * Backend Registration
 *============================================================================*/

typedef const BackendInterface* (*BackendEntryFunc)(void);

void wm_backend_register(const char *name, BackendEntryFunc entry);
const BackendInterface* wm_backend_get(const char *name);
WmContainer* wm_backend_get_available(void);

/*==============================================================================
 * Backend Helpers
 *============================================================================*/

static inline bool wm_backend_has_capability(const BackendInterface *backend, 
                                              WmBackendCapabilities cap) {
    WmBackendInfo info = backend->get_info();
    return (info.capabilities & cap) != 0;
}

#ifdef __cplusplus
}
#endif

#endif /* BACKEND_INTERFACE_H */
