#include <gtk/gtk.h>
#include <gtk/gtkx.h>
#include <locale.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <libintl.h>
#include <getopt.h>
#include <libublsettings.h>
#include <libublsettings-gtk3.h>
#include <libublsettingsui-gtk3.h>
#ifdef WEBKIT_FOUND
    #include <webkit2/webkit2.h>
#endif 
#include "ubl-strings.h"

#define _(String) gettext(String)



#define glade_path "/com/ublinux/ui/ubl-settings-keyboard.glade"
#define glade_layouts_path "/com/ublinux/ui/ubl-settings-keyboard-layouts.glade"
#define glade_options_path "/com/ublinux/ui/ubl-settings-keyboard-options.glade"
#define glade_keymaps_path "/com/ublinux/ui/ubl-settings-keyboard-keymaps.glade"
#define glade_font_path "/com/ublinux/ui/ubl-settings-keyboard-font.glade"
#define CssPath "/com/ublinux/css/ubl-settings-keyboard.css"
#define config_path yon_char_unite(yon_ubl_user_get_home_directory(),"/.config/",LocaleName,"/",LocaleName,".conf",NULL)
#define icon_path "com.ublinux.ubl-settings-keyboard"

#define keymap_list_path "resource://com/ublinux/csv/keymap-list.csv"
#define font_list_path "resource://com/ublinux/csv/font-list.csv"

#define LocaleName "ubl-settings-keyboard"

#define model_parameter "XKBMODEL"
#define model_parameter_command "ubconfig --source global get [keyboard] XKBMODEL"
#define keyboard_layout_parameter "XKBLAYOUT"
#define keyboard_layout_parameter_command "ubconfig --source global get [keyboard] XKBLAYOUT"
#define options_parameter "XKBOPTIONS"
#define options_parameter_command "ubconfig --source global get [keyboard] XKBOPTIONS"
#define num_lock_boot_parameter "NUMLOCK"
#define num_lock_boot_parameter_command "ubconfig --source global get [keyboard] NUMLOCK"

#define console_keymap_parameter "CONSOLE_KEYMAP"
#define console_keymap_parameter_command "ubconfig --source global get [keyboard] CONSOLE_KEYMAP"

#define console_keymap_toggle_parameter "CONSOLE_KEYMAP_TOGGLE"
#define console_keymap_toggle_parameter_command "ubconfig --source global get [keyboard] CONSOLE_KEYMAP_TOGGLE"

#define console_font_parameter "CONSOLE_FONT"
#define console_font_parameter_command "ubconfig --source global get [locale] CONSOLE_FONT"

#define config_get_command(target) yon_char_unite("ubconfig --source ",target," -ea get [keyboard] XKBMODEL XKBLAYOUT XKBOPTIONS NUMLOCK CONSOLE_KEYMAP CONSOLE_KEYMAP_TOGGLE -- [locale] CONSOLE_FONT",NULL)
#define config_get_default_command "ubconfig --source default -ea get [keyboard] XKBMODEL XKBLAYOUT XKBOPTIONS NUMLOCK CONSOLE_KEYMAP CONSOLE_KEYMAP_TOGGLE -- [locale] CONSOLE_FONT"

#define config_get_global_only_parameters ""
#define config_get_local_only_parameters ""


#define get_options_command "grep -E \"grp:.*toggle|grp_led:.*toggle|compose:.*toggle\" /usr/share/X11/xkb/rules/base.lst|sed -e 's/^  *//g' -e 's/\t//g' -e 's/toggle  */toggle;/g'"
#define get_models_command "sed -En '/^! model$/,/^ *$/!d;s/[[:blank:]]+([^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"
#define layouts_path "resource:///com/ublinux/csv/layouts.csv"

#define layouts_command "sed -En '/^! layout$/,/^ *$/!d;s/[[:blank:]]+([^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"
#define layouts_variant_command "sed -En '/^! variant$/,/^ *$/!d;s/[[:blank:]]+([^ ]+)[[:blank:]]+([^ :]+):[[:blank:]]+(.*)/\\2|\\1|\\3/p' /usr/share/X11/xkb/rules/evdev.lst"

// grp : Switching to another layout
#define grp_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(grp:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// lv2 : Key to choose the 2nd level
#define lv2_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(lv2:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// lv3 : Key to choose the 3nd level
#define lv3_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(lv3:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// ctrl : Ctrl position
#define ctrl_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(ctrl:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// grp_led : Use keyboard LED to show alternative layout
#define grp_led_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(grp_led:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// mod_led : Use keyboard LED to indicate modifiers
#define mod_led_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(mod_led:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// keypad : Layout of numeric keypad
#define keypad_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(keypad:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// kpdl : Numeric keypad Delete behavior
#define kpdl_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(kpdl:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// caps : Caps Lock behavior
#define caps_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(caps:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// altwin : Alt and Win behavior
#define altwin_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(altwin:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// Compose key : Position of Compose key
#define Compose_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(compose:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// compat : Compatibility options
#define compat_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+((numpad|srvrkeys|apple|shift|misc|keypad|grab):[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// currencysign : Currency signs
#define currencysign_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+((eurosign|rupeesign):[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// lv5 : Key to choose the 5th level
#define lv5_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(lv5:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// nbsp : Non-breaking space input
#define nbsp_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(nbsp:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// japan : Japanese keyboard options
#define japan_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(japan:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// korean : Korean Hangul/Hanja keys
#define korean_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(korean:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// esperanto : Esperanto letters with superscripts
#define esperanto_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(esperanto:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// solaris : Old Solaris keycodes compatibility
#define solaris_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(solaris:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

// terminate : Key sequence to kill the X server
#define terminate_options_command "sed -En '/^! option$/,/^ *$/!d;s/[[:blank:]]+(terminate:[^ ]+)[[:blank:]]+(.*)/\\1|\\2/p' /usr/share/X11/xkb/rules/evdev.lst"

#define tty_layout_command "find /usr/share/kbd/keymaps/ -type f -name \"*.map.*\" | sed -En \"s:.*/(.*)\\..*\\..*:\\1:p\" | sort -ufV"
#define tty_keymap_command "find /usr/share/kbd/keymaps/ -type f -name \"*.map.*\" | sed -En \"s:.*/(.*)\\..*\\..*:\\1:p\" | sort -ufV"
#define tty_font_command "find /usr/share/kbd/consolefonts -maxdepth 1 -type f -name \"*.gz\" | sed -En \"s:.*/(.*)(\\.psf\\.gz|\\.psfu\\.gz)$:\\1:p\" | sort -ufV"

typedef char* string;

__attribute__((unused)) static \
string version_application;

typedef struct {
    template_config_fields
    int save_config;
    config_str launch_arguments;
    int launch_size;
    GHashTable *options;
    GtkTreeStore *layouts_store;
    GtkListStore *options_list;
    GtkListStore *models_list;
    config_str variants_list;
    int variants_size;
    config_str layouts_list;
    int layouts_size;
} config;

extern config main_config;

typedef struct {
    template_window_fields
    
    GtkWidget *KeyboardModelCombo;
    GtkWidget *DefaultLayoutsSwitch;
    GtkWidget *LayoutTree;
    GtkWidget *LayoutAddButton;
    GtkWidget *LayoutRemoveButton;
    GtkWidget *LayoutMoveUpButton;
    GtkWidget *LayoutMoveDownButton;
    GtkWidget *LayoutChangingCombo;
    GtkWidget *OptionsTree;
    GtkWidget *OptionsEditButton;
    GtkWidget *OptionsRemoveButton;
    GtkWidget *ComposeSwitch;
    GtkWidget *ScrollLockSwitch;
    GtkWidget *NumLockCombo;
    GtkWidget *TTYLayoutEntry;
    GtkWidget *TTYLayoutButton;
    GtkWidget *TTYSecondLayoutEntry;
    GtkWidget *TTYSecondLayoutButton;
    GtkWidget *TTYFontEntry;
    GtkWidget *TTYFontButton;
    GtkListStore *LayoutsList;
    GtkListStore *OptionsList;
} main_window;


typedef struct {
    GtkWidget *Window;

    GtkWidget *HatText;
    GtkWidget *HeaderText;
    GtkWidget *InfoText;
    GtkWidget *AlwaysOpenCheck;

    GtkWidget *CloseButton;
    GtkWidget *AcceptButton;
} documentation_confirmation_window;

typedef struct {
    GtkWidget *Window;
    GtkWidget *StatusBox;
    GtkWidget *MainTree;
    GtkWidget *CancelButton;
    GtkWidget *AcceptButton;
    GtkWidget *OptionsFilterCombo;
    GtkWidget *OptionsEntry;
    GtkCellRenderer *ChosenCell;
    GtkTreeStore *list;
    GtkListStore *OptionsList;
    GtkTreeModel *OptionsFilter;
    char *parameters;
} layouts_window;

typedef struct {
    GtkWidget *Window;
    GtkWidget *CancelButton;
    GtkWidget *AcceptButton;
} options_window;

void on_save_done(main_window *, config_str output, int size);
void on_config_global_local_save(GtkWidget *, main_window *);
void on_config_local_save(GtkWidget *, main_window *);
void on_config_global_save(GtkWidget *, main_window *);
void on_config_custom_save(GtkWidget *, main_window *);
void on_config_local_load(GtkWidget *,main_window *);
void on_config_global_load(GtkWidget *,main_window *);
void on_config_custom_load(GtkWidget *,main_window *);

void yon_load_proceed(YON_CONFIG_TYPE type);

gboolean yon_interface_update(main_window *);

void on_save_done(main_window *widgets, config_str output, int size);

void config_init();

void yon_main_window_complete(main_window *widgets);
void on_move_down(GtkWidget *self, main_window *widgets);
void on_move_up(GtkWidget *self, main_window *widgets);
void on_layouts_accept(GtkWidget *self, layouts_window *window);
void on_options_open(GtkWidget *self, main_window *widgets);
void on_options_accept(GtkWidget *self, layouts_window *window);
void on_model_changed(GtkComboBoxText *self, main_window *widgets);
void on_num_lock_changed(GtkComboBox *self, main_window *widgets);
void on_layouts_chosen(GtkCellRenderer *self, gchar *path, layouts_window *window);
GList *yon_get_all_selected(GtkTreeView *tree, int column);
void on_system_layouts_add(GtkWidget *, main_window *widgets);
void yon_layouts_add(GtkTreeView *tree, GtkListStore *cur_list, main_window *widgets);
void yon_layouts_remove(GtkTreeView *tree, GtkListStore *cur_list, main_window *widgets);
void on_system_layouts_remove(GtkWidget *, main_window *widgets);
void yon_config_init();
void yon_layout_build(layouts_window *window);
config_str yon_layout_get_children(char *layout_id, int *size);
layouts_window *yon_layouts_window_new();
void yon_layout_load(char *layout,main_window *widgets);
void yon_options_setup(layouts_window *window);
layouts_window *yon_options_window_new();
void on_options_filter_changed(GtkWidget *, layouts_window *window);
gboolean yon_filter_refilter(GtkTreeModel *model, GtkTreeIter *iter, layouts_window *window);
void yon_options_setup(layouts_window *window);
void on_option_chosen(GtkCellRenderer *, gchar *path, layouts_window *window);
void on_options_save(GtkWidget *,main_window *widgets);
void on_compose_switch(GtkWidget *,int status,main_window *widgets);
void on_scroll_lock_switch(GtkWidget *,int status,main_window *widgets);
void on_option_remove(GtkWidget*, main_window *widgets);
void on_layout_move_down(GtkWidget *, main_window *widgets);
void on_layout_move_up(GtkWidget *, main_window *widgets);
void on_layout_dnd_inserted(GtkTreeModel *,  GtkTreePath* path,  GtkTreeIter* iter, main_window *widgets);
void on_layout_dnd_deleted(GtkTreeModel *,  GtkTreePath* path,  GtkTreeIter* iter, main_window *widgets);
void on_tty_changed(GtkWidget *, main_window *widgets);
void on_tty_keymap_changed(GtkWidget *, main_window *widgets);
void on_tty_font_changed(GtkWidget *, main_window *widgets);
void yon_keymaps_open(GtkWidget *,main_window *widgets);
layouts_window *yon_keymaps_window_new();
void on_keymaps_accept(GtkWidget *, layouts_window *window);
void on_font_accept(GtkWidget *, layouts_window *window);
layouts_window *yon_font_window_new();
void yon_font_open(GtkWidget *,main_window *widgets);
void on_keymaps_selection_changed(GtkWidget *,layouts_window *window);
void on_font_accept(GtkWidget *, layouts_window *window);
void on_font_selection_changed(GtkWidget *,layouts_window *window);
void yon_interface_save(main_window *widgets);
void on_layout_default_toggled(GtkWidget *, int status, main_window *widgets);
void on_layout_selection_changed(GtkTreeView*,main_window *widgets);
void on_option_selection_changed(GtkTreeView *self,main_window *widgets);
void on_layout_default_sensitive_toggled(GtkWidget *, int status, main_window *widgets);