#include "libublsettings-gtk3.h"

dictionary *yon_gtk_tree_store_get_children(GtkTreeStore *tree, GtkTreeIter *parent,int column){
    g_return_val_if_fail(GTK_IS_TREE_STORE(tree),NULL);
    dictionary *children = NULL;
    GtkTreeIter iter;
    if(gtk_tree_model_iter_has_child){
        gtk_tree_model_iter_children(GTK_TREE_MODEL(tree),&iter,parent);
        int valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(tree),&iter);
        for (;valid;valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(tree),&iter)){
            void *result = NULL;
            gtk_tree_model_get(GTK_TREE_MODEL(tree),&iter,column,&result,-1);
            dictionary *child_children = yon_gtk_tree_store_get_children(tree,&iter,column);
            yon_dictionary_add_or_create_if_exists_with_data(children,result,child_children);
        }
        return children;
    }
    return NULL;
}

void yon_gtk_tree_store_fill_children(GtkTreeStore *tree, GtkTreeIter *parent, dictionary *data, int column){
    GtkTreeIter iter;
    dictionary *dict=NULL;
    for_dictionaries(dict,data){
        gtk_tree_store_append(tree,&iter,parent);
        gtk_tree_store_set(tree,&iter,column,data->key,-1);
        if (data->data){
            yon_gtk_tree_store_fill_children(tree,&iter,data->data,column);
        }
    }
}

void yon_gtk_tree_store_copy_recursive(GtkTreeModel *sourceModel, GtkTreeIter *sourceIter, GtkTreeStore *destination, GtkTreeIter *parentIter) {
    GtkTreeIter destIter;

    gtk_tree_store_append(destination, &destIter, parentIter);

    gint nColumns = gtk_tree_model_get_n_columns(sourceModel);
    for (gint col = 0; col < nColumns; col++) {
        GValue value = G_VALUE_INIT;

        gtk_tree_model_get_value(sourceModel, sourceIter, col, &value);

        gtk_tree_store_set_value(destination, &destIter, col, &value);

        g_value_unset(&value);
    }

    if (gtk_tree_model_iter_has_child(sourceModel, sourceIter)) {
        GtkTreeIter childIter;
        gboolean validChild = gtk_tree_model_iter_children(sourceModel, &childIter, sourceIter);
        while (validChild) {
            yon_gtk_tree_store_copy_recursive(sourceModel, &childIter, destination, &destIter);
            validChild = gtk_tree_model_iter_next(sourceModel, &childIter);
        }
    }
}

void yon_gtk_tree_store_copy_full(GtkTreeStore *source, GtkTreeStore *destination) {
    GtkTreeModel *sourceModel = GTK_TREE_MODEL(source);
    GtkTreeIter iter;
    gboolean valid;

    valid = gtk_tree_model_get_iter_first(sourceModel, &iter);

    while (valid) {
        yon_gtk_tree_store_copy_recursive(sourceModel, &iter, destination, NULL);

        valid = gtk_tree_model_iter_next(sourceModel, &iter);
    }
}

gboolean yon_gtk_tree_iter_get_from_combo_box_id(GtkComboBox *combo, GtkTreeModel *model, GtkTreeIter *iter){
    g_return_val_if_fail(GTK_IS_COMBO_BOX(combo),0);
    g_return_val_if_fail(GTK_IS_TREE_MODEL(model),0);
    const char *id = gtk_combo_box_get_active_id(combo);
    if (yon_char_is_empty(id)) return 0;
    gtk_tree_model_get_iter_from_string(model,iter,id);
    return 1;
}

gboolean yon_gtk_tree_model_check_exist(GtkTreeModel *model, GtkTreeIter *iter, char *id, int column){
    g_return_val_if_fail(model&&GTK_IS_TREE_MODEL(model),0);
    g_return_val_if_fail(iter,0);
    for_iter(model,iter){
        char *check_target;
        gtk_tree_model_get(model,iter,column,&check_target,-1);
        if (!yon_char_is_empty(check_target)&&!strcmp(id,check_target)){
            return 1;
        }
    }
    return 0;
}

gboolean yon_gtk_list_store_copy_full(GtkListStore *target, GtkListStore *source){
    gtk_list_store_clear(target);
    GtkTreeIter iter, itar;
    g_return_val_if_fail(GTK_IS_LIST_STORE(target),0);
    g_return_val_if_fail(GTK_IS_LIST_STORE(source),0);
    int columns = gtk_tree_model_get_n_columns(GTK_TREE_MODEL(source));
    int target_columns = gtk_tree_model_get_n_columns(GTK_TREE_MODEL(target));
    if (columns!=target_columns){
        g_log((gchar*)0,G_LOG_LEVEL_WARNING,"%s\n","Target and source models have different number of columns");
        return 0;
    }
    for_iter(source,&iter){
        gtk_list_store_append(target,&itar);
        for(int i=0;i<columns;i++){
            GValue value = G_VALUE_INIT;
            gtk_tree_model_get_value(GTK_TREE_MODEL(source), &iter, i, &value);
            gtk_list_store_set_value(target, &itar, i, &value);

            g_value_unset(&value);
       }
    }
    
}

void yon_gtk_tree_view_column_set_fixed_size(GtkTreeView *target,int column_num){
    g_return_if_fail(GTK_IS_TREE_VIEW(target));
    GtkTreeIter iter;
    GtkTreeModel *model = gtk_tree_view_get_model(target);
    GtkTreeViewColumn *current_column = gtk_tree_view_get_column(target,column_num);
    int column_size = 0;
    
    for_iter(model,&iter){
        GList *list = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(current_column));
        int cur_size=0;
        for (int i=0;i<g_list_length(list);i++){
            int cur_width;
            gtk_cell_renderer_get_preferred_width(g_list_nth_data(list,i),GTK_WIDGET(target),&cur_width,NULL);
            cur_size+=cur_width;
        }
        g_list_free(list);
        if (column_size<cur_size) {
            column_size=cur_size;
        }
    }
            gtk_tree_view_column_set_fixed_width(current_column,column_size+10);
}

int yon_gtk_tree_view_set_fixed_size(GtkTreeView *target,...){
    va_list args;
    va_start(args,target);
    int current;
    int target_columns = gtk_tree_view_get_n_columns(target);
    GtkTreeModel *model = gtk_tree_view_get_model(target);

    while ((current=va_arg(args,int))!=-1){
        if (current>target_columns) return 0;
        yon_gtk_tree_view_column_set_fixed_size(target,current);
    }
    va_end(args);
    return 1;
}

void yon_tree_model_sort_filter_get_child_iter(GtkTreeModelSort *target, GtkTreeIter *iter, GtkTreeIter *converted_iter){
    GtkTreeIter filter_iter;
    GtkTreeModel *filter_model = gtk_tree_model_sort_get_model(target);
    GtkTreeModel *model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(filter_model));
    gtk_tree_model_filter_convert_child_iter_to_iter(GTK_TREE_MODEL_FILTER(filter_model),&filter_iter,iter);
    gtk_tree_model_sort_convert_child_iter_to_iter(target,converted_iter,&filter_iter);
}

void yon_tree_model_sort_filter_get_model_iter(GtkTreeModelSort *target, GtkTreeIter *iter, GtkTreeIter *converted_iter){
    GtkTreeIter filter_iter;
    GtkTreeModel *filter_model = gtk_tree_model_sort_get_model(target);
    GtkTreeModel *model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(filter_model));
    gtk_tree_model_sort_convert_iter_to_child_iter(target,&filter_iter,iter);
    gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(filter_model),converted_iter,&filter_iter);
}



int yon_tree_model_check_boolean_recursive(GtkTreeModel *model, GtkTreeIter *parent, int column, int check_value);
int yon_tree_model_check_boolean_recursive(GtkTreeModel *model, GtkTreeIter *parent, int column, int check_value){
    if (!parent) return 0;
    GtkTreeIter iter;
    gtk_tree_model_iter_children(model,&iter,parent);
    if (gtk_tree_model_get_column_type(model,column)!=G_TYPE_BOOLEAN) return -1;
    for (int valid = 1; valid; valid = gtk_tree_model_iter_next(model,&iter)){
        int status=0;
        gtk_tree_model_get(model,&iter,column,&status,-1);
        if (status==check_value)
            return 1;
        if (gtk_tree_model_iter_has_child(model,&iter)){
            if (yon_tree_model_check_boolean_recursive(model,&iter,column,check_value))
                return 1;
        }
    }
}

int yon_tree_model_check_boolean(GtkTreeModel *model, int column, int check_value){
    GtkTreeIter iter;
    if (gtk_tree_model_get_column_type(model,column)!=G_TYPE_BOOLEAN) return -1;
    for_iter(model,&iter){
        int status=0;
        gtk_tree_model_get(model,&iter,column,&status,-1);
        if (status==check_value)
            return 1;
        if (gtk_tree_model_iter_has_child(model,&iter)){
            if (yon_tree_model_check_boolean_recursive(model,&iter,column,check_value))
                return 1;
        }
    }
    return 0;
}