#include "libublsettings-gtk3.h"


    #define check_window_config_setup if(__yon_window_config_target_window&&__yon_window_config_path)

    typedef struct {
        char *parameter_name;
        enum YON_TYPE containing_type;
        GtkWidget *track_widget;
        char *property_name;
    } __yon_listener_parameter;

    typedef struct {
        char *parameter_name;
        char *section;
        enum YON_TYPE containing_type;
        void *property;
    } __yon_custom_parameter;

    struct {
        int x;
        int y;
        int width;
        int height;
        int fullscreen;
        dictionary *custom_listeners;
        dictionary *custom_parameters;
        dictionary *deleted_parameters;
    } __yon_main_window_config;
    
    static GtkWindow *__yon_window_config_target_window = NULL;
    static GKeyFile *__yon_window_config_file = NULL;
    static char *__yon_window_config_path = NULL;

    void yon_window_config_save(){
        check_window_config_setup {
        
            g_key_file_set_integer(__yon_window_config_file,"window","WindowPosX",__yon_main_window_config.x);
            g_key_file_set_integer(__yon_window_config_file,"window","WindowPosY",__yon_main_window_config.y);
            g_key_file_set_integer(__yon_window_config_file,"window","WindowWidth",__yon_main_window_config.width);
            g_key_file_set_integer(__yon_window_config_file,"window","WindowHeight",__yon_main_window_config.height);
            g_key_file_set_integer(__yon_window_config_file,"window","fullscreen",__yon_main_window_config.fullscreen);
            dictionary *dict=NULL;
            if (__yon_main_window_config.deleted_parameters)
            for_dictionaries(dict,__yon_main_window_config.deleted_parameters){
                __yon_custom_parameter *param = yon_dictionary_get_data(dict,__yon_custom_parameter*);
                g_key_file_remove_key(__yon_window_config_file,param->section,param->parameter_name,NULL);
            }
            if (__yon_main_window_config.custom_listeners)
            for_dictionaries(dict,__yon_main_window_config.custom_listeners){
                __yon_listener_parameter *param = yon_dictionary_get_data(dict,__yon_listener_parameter*);
                GValue *val = g_malloc0(sizeof(GValue));
                g_object_get_property(G_OBJECT(param->track_widget),param->property_name,val);
                switch(param->containing_type){
                    case YON_TYPE_STRING:
                        g_key_file_set_string(__yon_window_config_file,"window",param->parameter_name, g_value_get_string(val));
                        break;
                    case YON_TYPE_INT:
                        g_key_file_set_integer(__yon_window_config_file,"window",param->parameter_name, g_value_get_int(val));
                        break;
                    case YON_TYPE_BOOLEAN:
                        g_key_file_set_boolean(__yon_window_config_file,"window",param->parameter_name, g_value_get_boolean(val));
                        break;
                    case YON_TYPE_OTHER:printf("\033[0;31mCannot save %s property with %s key\033[0m\n",param->property_name,param->parameter_name);break;
                }
            }
            if (__yon_main_window_config.custom_parameters)
            for_dictionaries(dict,__yon_main_window_config.custom_parameters){
                __yon_custom_parameter *param = yon_dictionary_get_data(dict,__yon_custom_parameter*);
                switch (param->containing_type){
                    case YON_TYPE_STRING:
                        g_key_file_set_string(__yon_window_config_file,param->section,param->parameter_name, (char*)param->property);
                        break;
                    case YON_TYPE_INT:
                        g_key_file_set_integer(__yon_window_config_file,param->section,param->parameter_name, *(int*)param->property);
                        break;
                    case YON_TYPE_BOOLEAN:
                        g_key_file_set_boolean(__yon_window_config_file,param->section,param->parameter_name, *(gboolean*)param->property);
                        break;
                    default:
                        break;
                }
            }
            
            GError *err = NULL;
            if (!g_key_file_save_to_file(__yon_window_config_file,__yon_window_config_path,&err)){
                printf("%s\n",err->message);
            }
            {
                struct passwd *user = getpwnam(yon_ubl_root_user_get());
                int chown_success = chown(__yon_window_config_path,user->pw_uid,user->pw_gid);
            }
        } else {
            // g_warning("config file were not loaded properly");
        }
    }

    void yon_get_is_fullscreen(){
        gtk_window_is_maximized(__yon_window_config_target_window);
        __yon_main_window_config.fullscreen = gtk_window_is_maximized(__yon_window_config_target_window);
        if (!__yon_main_window_config.fullscreen) gtk_window_get_position(__yon_window_config_target_window,&__yon_main_window_config.x,&__yon_main_window_config.y); 
    }

    void yon_window_config_save_instant(){
        check_window_config_setup{
            yon_get_is_fullscreen();
            yon_window_config_save();
        }
    }

    /**yon_on_configured_window_destroy(GtkWidget* self,GdkEvent* event)
     * [EN]
     * 
     * [RU]
     * Сохраняет настройки основного окна. Вызывается когда основное окно уничтожается.
    */
    void yon_on_configured_window_destroy(GtkWidget* self,GdkEvent* event){
        check_window_config_setup{
            if (__yon_window_config_path){
                yon_get_is_fullscreen();
                yon_window_config_save();
            }
        } else {
            g_warning("config file were not loaded properly");
        }
        gtk_main_quit();
    }

    void __yon_window_config_on_resize(){
        if (__yon_window_config_path){
            int max=0;
            max=gtk_window_is_maximized(__yon_window_config_target_window);
            if(max==0){
                gtk_window_get_size(__yon_window_config_target_window,&__yon_main_window_config.width,&__yon_main_window_config.height); 
                gtk_window_get_position(__yon_window_config_target_window,&__yon_main_window_config.x,&__yon_main_window_config.y); 
            }
        }
    }

    void yon_window_config_setup(GtkWindow *window){
            __yon_window_config_target_window = window;
            g_signal_connect(G_OBJECT(window),"delete-event",G_CALLBACK(yon_on_configured_window_destroy),NULL);
            g_signal_connect(G_OBJECT(window),"check-resize"/*"configure-event"*/,G_CALLBACK(__yon_window_config_on_resize),NULL);
    }   

    void _yon_maximize(void *){
        g_usleep(G_USEC_PER_SEC/10);
        if(__yon_main_window_config.fullscreen ==1) gtk_window_maximize(__yon_window_config_target_window);
    }
    
    int yon_window_config_load(char *path){
        if(__yon_window_config_target_window){
        if (access(path,0)){
            yon_file_create_full_path(path,0755);
        }
            __yon_window_config_file = g_key_file_new();
            __yon_window_config_path=yon_char_new(path);
            if (!g_key_file_load_from_file(__yon_window_config_file,__yon_window_config_path,G_KEY_FILE_NONE,NULL)){
                struct stat st;
                int size;
                g_key_file_load_from_file(__yon_window_config_file,__yon_window_config_path,G_KEY_FILE_NONE,NULL);
            }
            __yon_main_window_config.x = g_key_file_get_integer(__yon_window_config_file,"window","WindowPosX",NULL);
            __yon_main_window_config.y = g_key_file_get_integer(__yon_window_config_file,"window","WindowPosY",NULL);
            __yon_main_window_config.width = g_key_file_get_integer(__yon_window_config_file,"window","WindowWidth",NULL);
            __yon_main_window_config.height = g_key_file_get_integer(__yon_window_config_file,"window","WindowHeight",NULL);
            __yon_main_window_config.fullscreen = g_key_file_get_integer(__yon_window_config_file,"window","fullscreen",NULL);
            dictionary *dict=NULL;
            if (__yon_main_window_config.custom_listeners)
            for_dictionaries(dict,__yon_main_window_config.custom_listeners){
                __yon_listener_parameter *param = yon_dictionary_get_data(dict,__yon_listener_parameter*);
                GValue *val = g_malloc0(sizeof(GValue));
                g_object_get_property(G_OBJECT(param->track_widget),param->property_name,val);
                switch(param->containing_type){
                    case YON_TYPE_STRING:
                        g_value_set_string(val,g_key_file_get_string(__yon_window_config_file,"window",param->parameter_name, NULL));
                        break;
                    case YON_TYPE_INT:
                        int output = g_key_file_get_integer(__yon_window_config_file,"window",param->parameter_name, NULL);
                        if (!output) output=-1;
                        g_value_set_int(val,output);
                        break;
                    case YON_TYPE_BOOLEAN:
                        gboolean res = g_key_file_get_boolean(__yon_window_config_file,"window",param->parameter_name, NULL);
                        g_value_set_boolean(val,res); 
                        break;
                    default:printf("\033[0;31mCannot load %s property with %s key\033[0m\n",param->property_name,param->parameter_name);break;
                }
                g_object_set_property(G_OBJECT(param->track_widget),param->property_name,val);
            }
            if (__yon_main_window_config.width&&__yon_main_window_config.height) gtk_window_resize(__yon_window_config_target_window,__yon_main_window_config.width,__yon_main_window_config.height);
            
        if (__yon_main_window_config.x&&__yon_main_window_config.y){
            gtk_window_move(__yon_window_config_target_window,__yon_main_window_config.x,__yon_main_window_config.y);
        } else {
            GdkRectangle geom;
            gtk_widget_realize(GTK_WIDGET(__yon_window_config_target_window));
            
            gdk_monitor_get_geometry(gdk_display_get_monitor(gdk_display_get_default(),0),&geom);
            gtk_window_move(__yon_window_config_target_window,
            geom.width/2-gdk_window_get_width(gtk_widget_get_window(GTK_WIDGET(__yon_window_config_target_window)))/2,
            geom.height/2-gdk_window_get_height(gtk_widget_get_window(GTK_WIDGET(__yon_window_config_target_window)))/2);
        }
            pthread_t tid;
            pthread_create(&tid,NULL,(void *)_yon_maximize,NULL);
            return 1;
            }
        return 0;
    }

    void yon_window_config_apply(){
        dictionary *dict=NULL;
        gtk_window_move(__yon_window_config_target_window,__yon_main_window_config.x,__yon_main_window_config.y);
        gtk_window_resize(__yon_window_config_target_window,__yon_main_window_config.width,__yon_main_window_config.height);
    } 

    config_str yon_window_config_get_section(char *section, gsize *size){
        (*size)=0;
        config_str key = g_key_file_get_keys(__yon_window_config_file,section,size,NULL);
        return key;
    }

    void yon_window_config_add_listener(GtkWidget *widget, char *param_name, char *widget_property, enum YON_TYPE val_type){
        __yon_listener_parameter *param = NULL;
        param = yon_remalloc(param,sizeof(__yon_listener_parameter));
        param->parameter_name = yon_char_new(param_name);
        param->track_widget = widget;
        param->property_name = yon_char_new(widget_property);
        param->containing_type = val_type;
        yon_dictionary_add_or_create_if_exists_with_data(__yon_main_window_config.custom_listeners,param->parameter_name,param);
    }

    void yon_window_config_add_custom_parameter(char *param_name, char *section, void *tracked_value, enum YON_TYPE val_type){
        __yon_custom_parameter *param = NULL;
        param = yon_remalloc(param,sizeof(__yon_custom_parameter));
        param->parameter_name = yon_char_new(param_name);
        param->section=section;
        param->property = tracked_value;
        param->containing_type = val_type;
        yon_dictionary_add_or_create_if_exists_with_data(__yon_main_window_config.custom_parameters,param->parameter_name,param);
        dictionary *dict=NULL;
        if (__yon_main_window_config.deleted_parameters)
        for_dictionaries(dict,__yon_main_window_config.deleted_parameters){
            if (strcmp(dict->key,param->parameter_name))
                yon_dictionary_rip(dict);
        }
    }

    void yon_window_config_add_instant_parameter(char *param_name, char *section, void *tracked_value, enum YON_TYPE val_type){
        check_window_config_setup {
            switch (val_type){
            case YON_TYPE_BOOLEAN: g_key_file_set_boolean(__yon_window_config_file,section,param_name,*((gboolean*)tracked_value));
                break;
            case YON_TYPE_INT: g_key_file_set_integer(__yon_window_config_file,section,param_name,*((int*)tracked_value));
                break;
            case YON_TYPE_STRING: g_key_file_set_string(__yon_window_config_file,section,param_name,(char*)tracked_value);
                break;
            }
            // GError *err = NULL;
            // if (!g_key_file_save_to_file(__yon_window_config_file,__yon_window_config_path,&err)){
            //     printf("%s\n",err->message);
            // }
            // {
            //     struct passwd *user = getpwnam(yon_ubl_root_user_get());
            //     int chown_success = chown(__yon_window_config_path,user->pw_uid,user->pw_gid);
            // }
        }
    }

    void yon_window_config_erase_custom_parameter(char *param_name, char *section){
        __yon_custom_parameter *param = NULL;
        param = yon_remalloc(param,sizeof(__yon_custom_parameter));
        param->parameter_name=param_name;
        param->section=section;
        yon_dictionary_add_or_create_if_exists_with_data(__yon_main_window_config.deleted_parameters,param->parameter_name,param);
    }

    void yon_window_config_erase_instant_parameter(char *param_name, char *section){
        g_key_file_remove_key(__yon_window_config_file,section,param_name,NULL);
    }
    

    int yon_window_config_get_parameter(char *section, char *config_parameter, void *return_value, enum YON_TYPE type){
        check_window_config_setup{
            GError *err=NULL;
            switch (type){
                case YON_TYPE_BOOLEAN:
                    *((int*)return_value) = g_key_file_get_boolean(__yon_window_config_file,section,config_parameter,&err);
                    if (err) return 0; else return 1;
                break;
                case YON_TYPE_INT:
                    *((int*)return_value) = g_key_file_get_integer(__yon_window_config_file,section,config_parameter,&err);
                    if (err) return 0; else return 1;
                break;
                case YON_TYPE_STRING:
                    *((char**)return_value) = g_key_file_get_string(__yon_window_config_file,section,config_parameter,&err);
                    if (err) return 0; else return 1;
                break;
                case YON_TYPE_STRING_LIST:
                    gsize size=0;
                    *((char***)return_value) = g_key_file_get_string_list(__yon_window_config_file,section,config_parameter,&size,&err);
                    *((char***)return_value)=yon_remalloc(return_value,size+1);
                    *((char***)return_value)[size]=NULL;
                    if (err) return 0; else return 1;
                break;
            }
        } else {
            g_warning("Window configuration were not set");
        }
        return 0;
    }

    void yon_on_window_config_custom_window_destroy(GtkWindow *window, GdkEvent* event, char *window_name){
        if (!gtk_window_is_maximized(window)){
            int height=0;
            int width=0;
            int X=0;
            int Y=0;
            gtk_window_get_position(window,&X,&Y);
            yon_window_config_add_instant_parameter(yon_char_append(window_name,"PosX"),"window",&X,YON_TYPE_INT);
            yon_window_config_add_instant_parameter(yon_char_append(window_name,"PosY"),"window",&Y,YON_TYPE_INT);

        }
    }

    void yon_on_window_config_custom_window_resize(GtkWindow *window, char *window_name){
        if (!gtk_window_is_maximized(window)){
            int height=0;
            int width=0;
            int X=0;
            int Y=0;
            gtk_window_get_size(window,&width,&height);
            gtk_window_get_position(window,&X,&Y);
            yon_window_config_add_instant_parameter(yon_char_append(window_name,"Width"),"window",&width,YON_TYPE_INT);
            yon_window_config_add_instant_parameter(yon_char_append(window_name,"Height"),"window",&height,YON_TYPE_INT);
            yon_window_config_add_instant_parameter(yon_char_append(window_name,"PosX"),"window",&X,YON_TYPE_INT);
            yon_window_config_add_instant_parameter(yon_char_append(window_name,"PosY"),"window",&Y,YON_TYPE_INT);
        }

    }

    void yon_window_config_custom_window_setup(GtkWindow *window, char *window_name){
        int height=0;
        int width=0;
        int X=0;
        int Y=0;
        yon_window_config_get_parameter("window",yon_char_append(window_name,"Width"),&width,YON_TYPE_INT);
        yon_window_config_get_parameter("window",yon_char_append(window_name,"Height"),&height,YON_TYPE_INT);
        yon_window_config_get_parameter("window",yon_char_append(window_name,"PosX"),&X,YON_TYPE_INT);
        yon_window_config_get_parameter("window",yon_char_append(window_name,"PosY"),&Y,YON_TYPE_INT);
        if (width&&height){
            gtk_window_resize(window,width,height);
        }
        if (X&&Y){
            gtk_window_move(window,X,Y);
        } else {
            GdkRectangle geom;
            gtk_widget_realize(GTK_WIDGET(window));
            
            gdk_monitor_get_geometry(gdk_display_get_monitor(gdk_display_get_default(),0),&geom);
            gtk_window_move(window,
            geom.width/2-gdk_window_get_width(gtk_widget_get_window(GTK_WIDGET(window)))/2,
            geom.height/2-gdk_window_get_height(gtk_widget_get_window(GTK_WIDGET(window)))/2);
        }
        char *signals_window_name = yon_char_new(window_name);
        g_signal_connect(G_OBJECT(window),"check-resize",G_CALLBACK(yon_on_window_config_custom_window_resize),signals_window_name);
        g_signal_connect(G_OBJECT(window),"delete-event",G_CALLBACK(yon_on_window_config_custom_window_destroy),signals_window_name);
    }

    void yon_window_config_custom_window_get(GtkWindow *window, char *window_name){
        int height=0;
        int width=0;
        int X=0;
        int Y=0;
        yon_window_config_get_parameter("window",yon_char_append(window_name,"Width"),&width,YON_TYPE_INT);
        yon_window_config_get_parameter("window",yon_char_append(window_name,"Height"),&height,YON_TYPE_INT);
        yon_window_config_get_parameter("window",yon_char_append(window_name,"PosX"),&X,YON_TYPE_INT);
        yon_window_config_get_parameter("window",yon_char_append(window_name,"PosY"),&Y,YON_TYPE_INT);
        if (width&&height)
            gtk_window_resize(window,width,height);
        if (X&&Y){
            gtk_window_move(window,X,Y);
        } else {
            GdkRectangle geom;
            gdk_monitor_get_geometry(gdk_display_get_monitor(gdk_display_get_default(),0),&geom);
            gtk_window_move(window,geom.width/2,geom.height/2);
        }
    }

    void yon_window_config_custom_window_set(GtkWindow *window, char *window_name){
        int height=0;
        int width=0;
        int X=0;
        int Y=0;
        gtk_window_get_size(window,&width,&height);
        gtk_window_get_position(window,&X,&Y);
        yon_window_config_add_instant_parameter(yon_char_append(window_name,"Width"),"window",&width,YON_TYPE_INT);
        yon_window_config_add_instant_parameter(yon_char_append(window_name,"Height"),"window",&height,YON_TYPE_INT);
        yon_window_config_add_instant_parameter(yon_char_append(window_name,"PosX"),"window",&X,YON_TYPE_INT);
        yon_window_config_add_instant_parameter(yon_char_append(window_name,"PosY"),"window",&Y,YON_TYPE_INT);
    }

    int yon_window_config_check_exist(char *section, char *parameter){
        if (__yon_window_config_file&&!yon_char_is_empty(section)&&!yon_char_is_empty(parameter)){
        gsize size;
        char **keys = g_key_file_get_keys(__yon_window_config_file,section,&size,NULL);
        return !!yon_char_parsed_check_exist(keys,size,parameter);
        }
        return 0;
    }

    int yon_window_config_check_init(){
        if (__yon_window_config_target_window&&__yon_window_config_path){
            return 1;
        } else {
            // g_warning("Window configuration were not set");
            return 0;
        }
    }