#ifndef MR4TH_OSW_WAYLAND_H
#define MR4TH_OSW_WAYLAND_H

#include <wayland-client.h>
#include <wayland-client-core.h>
#include <wayland-cursor.h>

#include "wayland/xdg-shell-client-protocol.h"
#include "wayland/xdg-decoration-client-protocol.h"

////////////////////////////////
// Types: OSW Wayland

typedef enum OSW_WL_ColorScheme{
  OSW_WL_ColorScheme_Default,
  OSW_WL_ColorScheme_Dark,
  OSW_WL_ColorScheme_Light
} OSW_WL_ColorScheme;

typedef struct OSW_WL_CursorTheme{
  String8 name;
  S32 size;
} OSW_WL_CursorTheme;

typedef U32 OSW_WL_WindowFlags;
enum{
  OSW_WL_WindowFlag_IsFullscreen  = (1 << 0),
  OSW_WL_WindowFlag_IsMax         = (1 << 1),
  OSW_WL_WindowFlag_IsActivated   = (1 << 2),
  OSW_WL_WindowFlag_IsTiledLeft   = (1 << 3),
  OSW_WL_WindowFlag_IsTiledRight  = (1 << 4),
  OSW_WL_WindowFlag_IsTiledTop    = (1 << 5),
  OSW_WL_WindowFlag_IsTiledBottom = (1 << 6),
  OSW_WL_WindowFlag_IsResizing    = (1 << 7),
  OSW_WL_WindowFlag_IsSuspended   = (1 << 8),
  OSW_WL_WindowFlag_IsConstrainedLeft   = (1 << 9),
  OSW_WL_WindowFlag_IsConstrainedRight  = (1 << 10),
  OSW_WL_WindowFlag_IsConstrainedTop    = (1 << 11),
  OSW_WL_WindowFlag_IsConstrainedBottom = (1 << 12),
};

#define OSW_WL_WindowMask_IsAnchored                             \
(OSW_WL_WindowFlag_IsFullscreen|OSW_WL_WindowFlag_IsMax|        \
OSW_WL_WindowFlag_IsTiledLeft |OSW_WL_WindowFlag_IsTiledRight| \
OSW_WL_WindowFlag_IsTiledTop  |OSW_WL_WindowFlag_IsTiledBottom)

typedef U32 OSW_WL_WindowControlFlags;
enum{
  OSW_WL_WindowControlFlag_Move       = (1 << 0),
  OSW_WL_WindowControlFlag_Resize     = (1 << 1),
  OSW_WL_WindowControlFlag_Min        = (1 << 2),
  OSW_WL_WindowControlFlag_Max        = (1 << 3),
  OSW_WL_WindowControlFlag_Close      = (1 << 4),
};

typedef struct OSW_WL_Config{
  U32 serial;
  V2S32 dim;
  OSW_WL_WindowFlags flags;
  U32 decoration_mode;
} OSW_WL_Config;

typedef struct OSW_WL_CSDFrame{
  RectS32 border_size;
  V2S32   min_size;
} OSW_WL_CSDFrame;

typedef struct OSW_WL_SubSurface{
  struct wl_surface    *wl_surface;
  struct wl_subsurface *wl_subsurface;
  struct wl_buffer     *wl_buffer;
  void *data;
  U64   size;
  V2S32 dim;
  V2S32 pos;
} OSW_WL_SubSurface;

// gtk

#include <cairo/cairo.h>
#include <gtk/gtk.h>

typedef struct OSW_WL_GTK_Ctx{
  cairo_surface_t *shadow_blur;
} OSW_WL_GTK_Ctx;

typedef struct OSW_WL_GTK_Window{
  OSW_WL_SubSurface titlebar;
  OSW_WL_SubSurface shadow;
  
  GtkWidget *window;
  GtkWidget *header;
  
  S32 double_click_time_ms;
  U32 active_header_button;
} OSW_WL_GTK_Window;

// ctx

typedef struct OSW_WL_Seat{
  struct wl_seat    *wl_seat;
  struct wl_pointer *wl_pointer;
  struct wl_surface *cursor_surface;
  
  struct wl_surface *hover_surface;
  OSW_Window *hover_window;
  V2S32 hover_p;
  U32 serial;
} OSW_WL_Seat;

typedef struct OSW_WL_Ctx{
  Arena *arena;
  OSW_WL_ColorScheme color_scheme;
  OSW_WL_CursorTheme cursor_theme;
  
  OSW_WL_GTK_Ctx gtk_ctx;
  
  struct wl_display *wl_display;
  struct wl_registry *wl_registry;
  struct wl_compositor    *wl_compositor;
  struct wl_subcompositor *wl_subcompositor;
  struct wl_shm           *wl_shm;
  struct xdg_wm_base      *xdg_wm_base;
  struct zxdg_decoration_manager_v1 *zxdg_decoration_manager;
  
  struct wl_cursor_theme *wl_cursor_theme;
  struct wl_cursor       *wl_cursors[OSW_CursorShape_COUNT];
  
  OSW_WL_Seat seat;
  
  B32 did_set_cursor;
} OSW_WL_Ctx;

////////////////////////////////
// Wayland Implementation: OSW Types

struct OSW_Window{
  OSW_WindowBase base;
  
  struct wl_surface   *main_wl_surface;
  struct xdg_surface  *main_xdg_surface;
  struct xdg_toplevel *main_xdg_toplevel;
  struct zxdg_toplevel_decoration_v1 *main_zxdg_toplevel_decoration;
  
  OSW_WL_WindowControlFlags control_flags;
  RectS32 mmbox;
  
  OSW_WL_Config config;
  OSW_WL_Config config_staged;
  
  OSW_WL_CSDFrame csd_frame;
  V2S32           csd_dim;
  
  B32   handled_first_size;
  V2S32 dim;
  
  U32 title_size;
  U8 title_buffer[MR4TH_OSW_MAX_WINDOW_TITLE_SIZE + 1];
  
  OSW_WL_GTK_Window gtk_window;
};

////////////////////////////////
// Functions: OSW Wayland

MR4TH_SYMBOL OSW_WL_WindowFlags osw_wl_window_flags_from_states_array(struct wl_array *states);

// gtk

MR4TH_SYMBOL void osw_wl_gtk_init(OSW_WL_GTK_Ctx *gtk_ctx);

MR4TH_SYMBOL void osw_wl_gtk_window_init(struct wl_surface *main_wl_surface,
                                         OSW_WL_GTK_Window *gtk_window);
MR4TH_SYMBOL void osw_wl_gtk_window_update_and_render(OSW_Window *window);
MR4TH_SYMBOL void osw_wl_gtk_window_disable(OSW_WL_GTK_Window *window);

MR4TH_SYMBOL OSW_WL_CSDFrame osw_wl_gtk_calc_frame(OSW_Window *window);
MR4TH_SYMBOL B32             osw_wl_gtk_calc_surface_off(OSW_WL_GTK_Window *gtk_window, struct wl_surface *surface, V2S32 *off_out);

MR4TH_SYMBOL GtkWidget* osw_wl_gtk_widget_from_name(GtkWidget *root, char *name);
MR4TH_SYMBOL void       osw_wl_gtk_widget_from_name__r(GtkWidget *root, void *data);

// sub-surfaces

MR4TH_SYMBOL OSW_WL_SubSurface osw_wl_subsurface_new(struct wl_surface *main_wl_surface);
MR4TH_SYMBOL void              osw_wl_subsurface_buffer_clear(OSW_WL_SubSurface *subsurface);
MR4TH_SYMBOL void              osw_wl_subsurface_buffer_alloc(OSW_WL_SubSurface *subsurface, V2S32 dim);
MR4TH_SYMBOL void              osw_wl_subsurface_set_position(OSW_WL_SubSurface *subsurface, V2S32 pos);
MR4TH_SYMBOL void              osw_wl_subsurface_commit(OSW_WL_SubSurface *subsurface);

// anonymous files

MR4TH_SYMBOL int osw_wl_resize_anonymous_file(int fd, off_t size);
MR4TH_SYMBOL int osw_wl_create_anonymous_file(off_t size);

// desktop settings

MR4TH_SYMBOL OSW_WL_ColorScheme osw_wl_desktop_get_color_scheme(Arena *arena);
MR4TH_SYMBOL OSW_WL_CursorTheme osw_wl_desktop_get_cursor_theme(Arena *arena);

MR4TH_SYMBOL OSW_WL_CursorTheme osw_wl_desktop_get_cursor_theme_from_env(Arena *arena);

#ifdef HAS_DBUS
MR4TH_SYMBOL DBusMessage*osw_wl_desktop__get_setting_sync(DBusConnection *const connection, const char *key1, const char *key2);
MR4TH_SYMBOL int         osw_wl_desktop__parse_type(DBusMessage *const reply, const int type, void *value);
#endif

// cairo shadow rendering
MR4TH_SYMBOL int  osw_wl_cairo_blur_surface(cairo_surface_t *surface, int margin);
MR4TH_SYMBOL void osw_wl_cairo_render_shadow(cairo_t *cr, cairo_surface_t *surface,
                                             int x, int y, int width, int height,
                                             int margin, int top_margin);

#endif //MR4TH_OSW_WAYLAND_H
