#include "libublsettings-gtk3.h"

// static render_data render = {};

struct status_struct {
    GtkWidget *box;
    GtkWidget *revealer;
    GtkWidget *label;
    GtkWidget *icon;
    guint thread;
    GMutex mutex;

    int sleep_timer;
    int window_height;
};

void __yon_ubl_status_box_destroyed(GtkWidget *self,struct status_struct *statusstruct);
void yon_ubl_status_box_despawn(GtkContainer *status_container);
gboolean yon_ubl_status_destroy_status(struct status_struct *statusstruct);
gboolean _yon_ubl_status_box_timed_remove(struct status_struct *statusstruct);
gboolean yon_status_shrink_window(struct status_struct *statusstruct);
void yon_status_struct_destroy(struct status_struct *status);

GMutex status_remove_mutex;

struct status_struct *render = NULL;

struct status_struct *yon_status_struct_new(){
    struct status_struct *status = malloc(sizeof(struct status_struct));
    memset(status,0,sizeof(struct status_struct));
    status->box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5);
    status->revealer = gtk_revealer_new();
    status->label = gtk_label_new("");
    status->icon = gtk_image_new();
    gtk_label_set_line_wrap(GTK_LABEL(status->label),1);
    gtk_label_set_line_wrap_mode(GTK_LABEL(status->label),PANGO_WRAP_WORD);
    gtk_container_add(GTK_CONTAINER(status->revealer),status->box);
    gtk_box_pack_start(GTK_BOX(status->box),status->icon,0,0,5);
    gtk_box_pack_start(GTK_BOX(status->box),status->label,0,0,5);

    gtk_widget_set_margin_bottom(status->label,9);
    gtk_widget_set_margin_top(status->label,9);
    gtk_label_set_xalign(GTK_LABEL(status->label),0.0);

    PangoAttrList *attributes = pango_attr_list_new();
    PangoAttribute *boldAttr = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
    pango_attr_list_insert(attributes, boldAttr);
    gtk_label_set_attributes(GTK_LABEL(status->label),attributes);

    GdkRGBA textColor;
    gdk_rgba_parse(&textColor, "#4d4d4d4d4d4d");
    PangoAttribute *colorAttr = pango_attr_foreground_new(
        (int)(textColor.red * 65535),
        (int)(textColor.green * 65535),
        (int)(textColor.blue * 65535)
    );
    pango_attr_list_insert(attributes, colorAttr);

    gtk_revealer_set_transition_duration(GTK_REVEALER(status->revealer),200);
    g_signal_connect(G_OBJECT(status->revealer),"destroy", G_CALLBACK(__yon_ubl_status_box_destroyed),status);
    g_object_set_data(G_OBJECT(status->revealer),"status_struct",status);
    gtk_widget_show_all(status->revealer);
    return status;
}

GMutex _render_block_mutex;
gboolean _render_blocked=0;

void *_yon_ubl_status_box_block_input(int*seconds){
    g_mutex_lock(&_render_block_mutex);
    _render_blocked = 1;
    g_mutex_unlock(&_render_block_mutex);
    sleep(*seconds);
    g_mutex_lock(&_render_block_mutex);
    _render_blocked = 0;
    g_mutex_unlock(&_render_block_mutex);
}

void yon_ubl_status_box_block_input(int seconds){
    g_thread_new("block_thread",(GThreadFunc)_yon_ubl_status_box_block_input,&seconds);
}

void yon_ubl_status_box_set(BACKGROUND_IMAGE_TYPE type, GtkRevealer *root){
    struct status_struct *status = g_object_get_data(G_OBJECT(root),"status_struct");
    if (!status){
        status = g_object_get_data(G_OBJECT(root),"status_def_struct");
    }
    GtkIconTheme *ictheme = gtk_icon_theme_get_default();
    switch (type){
            case BACKGROUND_IMAGE_SUCCESS_TYPE:{
            gtk_style_context_remove_class(gtk_widget_get_style_context(status->box), "boxInfoMessError");
            gtk_style_context_add_class(gtk_widget_get_style_context(status->box), "boxInfoMessOK");
            gtk_image_set_from_icon_name(GTK_IMAGE(status->icon),"com.ublinux.libublsettingsui-gtk3.checked",GTK_ICON_SIZE_BUTTON);
            gtk_image_set_pixel_size(GTK_IMAGE(status->icon),25);
        }
        break;
        case BACKGROUND_IMAGE_FAIL_TYPE:{
            gtk_style_context_remove_class(gtk_widget_get_style_context(status->box), "boxInfoMessOK");
            gtk_style_context_add_class(gtk_widget_get_style_context(status->box), "boxInfoMessError");
            gtk_image_set_from_icon_name(GTK_IMAGE(status->icon),"com.ublinux.libublsettingsui-gtk3.warning",GTK_ICON_SIZE_BUTTON);
            gtk_image_set_pixel_size(GTK_IMAGE(status->icon),25);
        }
        break;
        case BACKGROUND_IMAGE_INFO_TYPE:{
            gtk_style_context_remove_class(gtk_widget_get_style_context(status->box), "boxInfoMessError");
            gtk_style_context_add_class(gtk_widget_get_style_context(status->box), "boxInfoMessOK");
            gtk_image_set_from_icon_name(GTK_IMAGE(status->icon),"com.ublinux.libublsettingsui-gtk3.important-symbolic",GTK_ICON_SIZE_BUTTON);
            gtk_image_set_pixel_size(GTK_IMAGE(status->icon),25);
        }
        break;
    }
}


gboolean _yon_ubl_status_list_store_highlight_incorrect_start(GtkWidget **widget_pack){
    GtkListStore *list = (GtkListStore*)widget_pack[0];
    GtkTreeIter *iter = (GtkTreeIter*)widget_pack[1];
    GdkRGBA rgba,rgba2;
    rgba.alpha=1;
    rgba.blue=153.0/255.0;
    rgba.green=153.0/255.0;
    rgba.red=234.0/255.0;
    rgba2.alpha=1;
    rgba2.blue=0;
    rgba2.green=0;
    rgba2.red=0;
    gtk_list_store_set(list,iter,1,gdk_rgba_to_string(&rgba2),2,gdk_rgba_to_string(&rgba),-1);
    return G_SOURCE_REMOVE;
}

gboolean _yon_ubl_status_list_store_highlight_incorrect_stop(GtkWidget **widget_pack){
    GtkListStore *list = (GtkListStore*)widget_pack[0];
    GtkTreeIter *iter = (GtkTreeIter*)widget_pack[1];
    gtk_list_store_set(list,iter,1,NULL,2,NULL,-1);
    return G_SOURCE_REMOVE;
}

void _yon_ubl_status_list_store_highlight_incorrect(GtkWidget **widget_pack){
    g_idle_add((GSourceFunc)_yon_ubl_status_list_store_highlight_incorrect_start,widget_pack);
    sleep(5);
    g_idle_add((GSourceFunc)_yon_ubl_status_list_store_highlight_incorrect_stop,widget_pack);
}

void yon_ubl_status_list_store_highlight_incorrect(GtkListStore *list, GtkTreeIter *iter){
    GtkWidget **pack = malloc(sizeof(GtkWidget *)*2);
    pack[0]=(GtkWidget*)list;
    pack[1]=(GtkWidget*)iter;
    g_thread_new("error_highlight",(GThreadFunc)_yon_ubl_status_list_store_highlight_incorrect,pack);
}

struct temp_statusbox {
            int times;
            GtkWidget *revealer;
            int window_height;
        };

// Standard status box functions
void _yon_ubl_header_setup(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path){
    gtk_overlay_add_overlay(GTK_OVERLAY(Overlay), Head);
    gtk_image_set_from_file(GTK_IMAGE(Image), image_path);
}

int yon_ubl_status_box_setup(GtkWidget *icon, GtkWidget *box, GtkWidget *label){
    if(icon&&box&&label){
        render = malloc(sizeof(struct status_struct));
        memset(render,0,sizeof(struct status_struct));
        render->box = box;
        render->label = label;
        render->icon = icon;
        g_object_set_data(G_OBJECT(render->box),"status_def_struct",render);
        return 1;
    } else return 0;
} 

int yon_status_box_is_set(){
    if (render){
        return 1;
    }
    return 0;
}

void _yon_ubl_status_box_render(char *text, BACKGROUND_IMAGE_TYPE type){
    struct status_struct *data = render;
    yon_ubl_status_box_set(type,(GtkRevealer*)data->box);
    if (text)
        gtk_label_set_text(GTK_LABEL(data->label), text);
}

void yon_ubl_status_box_render(char *text, BACKGROUND_IMAGE_TYPE type){
    g_mutex_lock(&_render_block_mutex);
    int blocked = _render_blocked;
    g_mutex_unlock(&_render_block_mutex);
    if (blocked) return;
    _yon_ubl_status_box_render(text,type);
}

struct __yon_ubl_status_box_render_thread_struct{
    char *text;
    BACKGROUND_IMAGE_TYPE type;
};

void _yon_ubl_status_box_render_thread(struct __yon_ubl_status_box_render_thread_struct *data){
    yon_ubl_status_box_render(data->text,data->type);
    free(data);
}

void yon_ubl_status_box_render_thread(char *text, BACKGROUND_IMAGE_TYPE type){
    g_mutex_lock(&_render_block_mutex);
    int blocked = _render_blocked;
    g_mutex_unlock(&_render_block_mutex);
    if (blocked) return;
    struct __yon_ubl_status_box_render_thread_struct *data = malloc(sizeof(struct __yon_ubl_status_box_render_thread_struct));
    data->text=yon_char_new(text);
    data->type=type;
    g_idle_add_once((GSourceOnceFunc)_yon_ubl_status_box_render_thread,data);
}

// Status spawn functions
void __yon_ubl_status_box_destroyed(GtkWidget *,struct status_struct *statusstruct){
}

void yon_status_destory_cancel(GtkWidget *, struct status_struct *status){
    g_source_remove(status->thread);
}

void yon_ubl_status_box_spawn(GtkContainer *container,char *display_text, int timeout,BACKGROUND_IMAGE_TYPE type){
    g_mutex_lock(&_render_block_mutex);
    int blocked = _render_blocked;
    g_mutex_unlock(&_render_block_mutex);
    if (blocked) return;
    GList *list = gtk_container_get_children(container);
    guint len = g_list_length(list);
    if (len>=3){
        struct status_struct *status = g_object_get_data(G_OBJECT(g_list_nth_data(list,len-3)),"status_struct");
        if (status->thread){
            g_mutex_lock(&status_remove_mutex);
            if (status&&gtk_revealer_get_reveal_child(GTK_REVEALER(status->revealer))){
                yon_status_struct_destroy(status);
            }
            g_mutex_unlock(&status_remove_mutex);
        }
    }

    struct status_struct *status = yon_status_struct_new();

    status->sleep_timer = timeout;

    gtk_container_add(container,status->revealer);
    gtk_revealer_set_reveal_child(GTK_REVEALER(status->revealer),1);

    yon_ubl_status_box_set(type,GTK_REVEALER(status->revealer));
    if (display_text){
        gtk_label_set_text(GTK_LABEL(status->label),display_text);
    }
    
    gtk_window_get_size(GTK_WINDOW(gtk_widget_get_toplevel(status->revealer)),NULL,&status->window_height);
    if (status->sleep_timer>0){
        g_mutex_lock(&status_remove_mutex);
        g_mutex_lock(&status->mutex);
        status->thread = g_timeout_add(status->sleep_timer*1000,(GSourceFunc)_yon_ubl_status_box_timed_remove,status);
        g_signal_connect(G_OBJECT(status->box),"destroy",G_CALLBACK(yon_status_destory_cancel),status);
        g_mutex_unlock(&status->mutex);
        g_mutex_unlock(&status_remove_mutex);
    }
}




// Status despawn functions
void yon_ubl_status_hide_revealer(struct status_struct *status){
    gtk_revealer_set_transition_type(GTK_REVEALER(status->revealer),GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
    gtk_revealer_set_reveal_child(GTK_REVEALER(status->revealer),0);
}

gboolean __yon_ubl_status_box_despawn(struct status_struct *status){
    gtk_widget_destroy(status->revealer);
    free(status);
    return G_SOURCE_REMOVE;
}

void yon_ubl_status_box_despawn(GtkContainer *status_container){
    GList *list = gtk_container_get_children(status_container);
    if (!list) return;
    GList *iter;
    for (iter=list;iter;iter=iter->next){
        struct status_struct *status = g_object_get_data(G_OBJECT(iter->data),"status_struct");
        if (status->thread>(guint)0){
            g_mutex_lock(&status->mutex);
            g_source_remove(status->thread);
            status->thread=0;
            g_mutex_unlock(&status->mutex);
        }
        g_idle_add_once((GSourceOnceFunc)yon_ubl_status_hide_revealer,status);
        g_timeout_add(1000,(GSourceFunc)__yon_ubl_status_box_despawn,status);
    }
    g_list_free(list);
    return;
}

gboolean _yon_ubl_status_box_timed_remove(struct status_struct *statusstruct){
    if (statusstruct->revealer){
        g_signal_handlers_disconnect_by_func(G_OBJECT(statusstruct->box),G_CALLBACK(yon_status_destory_cancel),statusstruct);
        yon_ubl_status_hide_revealer(statusstruct);
        g_idle_add((GSourceFunc)yon_status_shrink_window,statusstruct);
        g_timeout_add(200,(GSourceFunc)yon_ubl_status_destroy_status,statusstruct);
    }
    return G_SOURCE_REMOVE;
}

gboolean yon_ubl_status_destroy_status(struct status_struct *statusstruct){
    if (statusstruct->window_height <=0) return G_SOURCE_REMOVE;
        GtkWidget *window = gtk_widget_get_toplevel(statusstruct->revealer);
        if (!GTK_IS_WIDGET(statusstruct->revealer)) return G_SOURCE_REMOVE;
        gtk_widget_destroy(statusstruct->revealer);
        statusstruct->revealer = NULL;
        int width, height;
        gtk_window_get_size(GTK_WINDOW(window),&width,NULL);
        gtk_window_resize(GTK_WINDOW(window),width,statusstruct->window_height);
        return G_SOURCE_REMOVE;
}

gboolean yon_status_shrink_window(struct status_struct *statusstruct){
    if (statusstruct->revealer){
        GtkWidget *window = gtk_widget_get_toplevel(statusstruct->revealer);
        
        int width, height;
        gtk_window_get_size(GTK_WINDOW(window),&width,NULL);
        gtk_window_resize(GTK_WINDOW(window),width,statusstruct->window_height);
        return G_SOURCE_CONTINUE;
    } 
}

void yon_status_struct_destroy(struct status_struct *status){
    _yon_ubl_status_box_timed_remove(status);
    g_mutex_lock(&status->mutex);
    g_source_remove(status->thread);
    status->thread=0;
    g_mutex_unlock(&status->mutex);
}



// Widget highlight functions
gboolean _yon_ubl_status_highlight_incorrect_start(GtkWidget *widget){
    gtk_style_context_add_class(gtk_widget_get_style_context(widget),"errorBox");
    return G_SOURCE_REMOVE;
}

gboolean _yon_ubl_status_highlight_incorrect_stop(GtkWidget *widget){
    gtk_style_context_remove_class(gtk_widget_get_style_context(widget),"errorBox");
    guint *thread = g_object_get_data(G_OBJECT(widget),"highlight_thread");
    if (thread&&(*thread)>(guint)0){
        g_object_set_data(G_OBJECT(widget),"highlight_thread",NULL);
        free(thread);
    }
    return G_SOURCE_REMOVE;
}

gboolean _yon_ubl_status_highlight_incorrect(GtkWidget *widget){
    g_idle_add((GSourceFunc)_yon_ubl_status_highlight_incorrect_stop,widget);
    return G_SOURCE_REMOVE;
}

void yon_ubl_status_highlight_incorrect(GtkWidget *widget){
    guint *thread = NULL;
    thread = g_object_get_data(G_OBJECT(widget),"highlight_thread");
    if (thread&&(*thread)>(guint)0){
        g_source_remove((*thread));
    g_object_set_data(G_OBJECT(widget),"highlight_thread",NULL);
        free(thread);
    }
    thread = malloc(sizeof(guint));
    _yon_ubl_status_highlight_incorrect_start(widget);
    (*thread) = g_timeout_add(5000,(GSourceFunc)_yon_ubl_status_highlight_incorrect,widget);
    g_object_set_data(G_OBJECT(widget),"highlight_thread",thread);
}