#include "ubl-settings-repomanager.h"

config main_config;


// // filechooser window section

// // main window 

void on_folder_changed(GtkFileChooser *self, dictionary *dict){
    repo_add_window *window = yon_dictionary_get_data(dict->first,repo_add_window*);
    filechooser_window *dialog = yon_dictionary_get_data(dict->first->next,filechooser_window*);
    const char *current = gtk_file_chooser_get_current_folder(self);

    const char* storage_path = gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->MoveSourceStorageEntry));
    storage_struct *storage = g_hash_table_lookup(main_config.storages,storage_path);
    if (storage){
        const char *repo_name = gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->MoveSourceRepoEntry));
        repo_struct *repo = g_hash_table_lookup(storage->repos,repo_name);
        if (repo){
            if (!strstr(current,repo->path)){
                gtk_file_chooser_set_current_folder(self,repo->path);
            }
        }
    }
}

//     /*      setup functions     */
void config_init(){
    main_config.tree_store=NULL;
    main_config.signs=NULL;
    main_config.signs_size=0;
    yon_sign_list_update();
    main_config.last_selection = NULL;
    main_config.storages = g_hash_table_new(g_str_hash,g_str_equal);
}

char *yon_path_get_name(char *path){
    char *name=NULL;
    char *copy = yon_char_new(path);
    int last = yon_char_find_last(copy,'/');
    if (last>-1)
        free(yon_char_divide(copy,last));
    return copy;
}

void yon_remove_config_storages(char *key,storage_struct *storage,void*){
    yon_storage_sturct_free_full(storage);
}

int yon_storages_load(main_window *widgets){
    g_hash_table_remove_all(main_config.storages);

    gsize size;
    config_str storages = yon_window_config_get_section("storage_info",&size);
    GtkTreeIter storageiter, repoiter, architer;
    for(int i=0;i<size;i++){
        char *repos = NULL;
        if (yon_window_config_get_parameter("storage_info",storages[i],&repos,YON_TYPE_STRING)){
                char *storage_name = yon_path_get_name(storages[i]);
            storage_struct *storage = yon_storage_struct_new();

            storage->name=storage_name;
            storage->path=yon_char_new(storages[i]);
            g_hash_table_insert(main_config.storages,storage->path,storage);

            if (yon_char_is_empty(repos)) continue;
            int repos_size;
            config_str repo_names = yon_char_parse(repos,&repos_size,",");
            qsort(repo_names,repos_size,sizeof(char*),(__compar_fn_t)yon_char_parsed_compare);
            yon_storage_fill_repos(storage,repo_names,repos_size);
            yon_char_parsed_free(repo_names,repos_size);
        }

    }
    if (size) return 1;
    return 0;
}

void yon_repo_tree_build_storage(char *key, storage_struct *storage, main_window *widgets){
    struct repo_tree_build data;
    data.widgets=widgets;
    gtk_tree_store_append(widgets->RepoList,&data.storageiter,NULL);
    gtk_tree_store_set(widgets->RepoList,&data.storageiter,0,folder_no_edits,2,storage->name,3,storage->path,7,storage,8,0,-1);
    g_hash_table_foreach(storage->repos,(GHFunc)yon_repo_tree_build_repo,&data);
}

void yon_repo_tree_build_repo(char *key, repo_struct *repo, struct repo_tree_build *data){
    gtk_tree_store_append(data->widgets->RepoList,&data->repoiter,&data->storageiter);
    gtk_tree_store_set(data->widgets->RepoList,&data->repoiter,2,repo->name,3,repo->path,7,repo,8,1,-1);
    g_hash_table_foreach(repo->archs,(GHFunc)yon_repo_tree_build_arch,data);
}

void yon_repo_tree_build_arch(char *key, arch_struct *arch, struct repo_tree_build *data){
    int arch_status = system(yon_repo_get_signature_status_arch(arch->storage_path,arch->repo_name,arch->name));
    int package_status = system(yon_repo_get_signature_status_packages(arch->storage_path,arch->repo_name,arch->name));
    arch_status = WEXITSTATUS(arch_status);
    char *image_name = NULL;
    char *image_tooltip = NULL;
    if (!arch_status&&!package_status){
        image_name = key_icon_name;
        image_tooltip = SIGN_LABEL;
    } else if (arch_status != 2 || package_status != 2){
        image_name = warning_icon_name;
        image_tooltip = UNSIGNED_LABEL;
    }
    
    gtk_tree_store_append(data->widgets->RepoList,&data->architer,&data->repoiter);
    gtk_tree_store_set(data->widgets->RepoList,&data->architer,0,image_name,2,arch->name,3,arch->path,7,arch,8,2,9,image_tooltip,-1);
}

void yon_interface_update(main_window *widgets){
    GtkTreeIter iter;
    GtkTreeModel *model;
    GtkTreePath *path = NULL;
    yon_sign_list_update();
    if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->ReposTree)),&model,&iter)){
        path = gtk_tree_model_get_path(model,&iter);
    }
    gtk_tree_store_clear(widgets->RepoList);
    gtk_list_store_clear(widgets->RepoFileList);
    gtk_list_store_clear(widgets->RepoPackagesList);

    yon_storages_load(widgets);
    g_hash_table_foreach(main_config.storages,(GHFunc)yon_repo_tree_build_storage,widgets);
    if (path){
        gtk_tree_view_expand_to_path(GTK_TREE_VIEW(widgets->ReposTree),path);
        gtk_tree_selection_select_path(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->ReposTree)),path);
        gtk_tree_path_free(path);
    }
    on_main_tree_selection_changed(widgets->Window,widgets);
}


// char *yon_signature_get(GtkTreeView *target, GtkTreeIter *iter){
//     GtkTreeIter itar;
//     GtkTreeModel *model = gtk_tree_view_get_model(target);
//     char *full_path = gtk_tree_model_get_string_from_iter(GTK_TREE_MODEL(model),iter);
//     int size;
//     config_str parsed = yon_char_parse(full_path,&size,":");
//     if (size==2){
//         char *storage_path = parsed[0];
//         char *repo_path = yon_char_unite(parsed[0],":",parsed[1],NULL);
//         gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model),&itar,storage_path);
//         char *path;
//         gtk_tree_model_get(GTK_TREE_MODEL(model),&itar,3,&path,-1);
//         char *repo;
//         gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model),&itar,repo_path);
//         gtk_tree_model_get(GTK_TREE_MODEL(model),&itar,2,&repo,-1);
//         int status_size;
//         config_str status = yon_config_load(yon_repo_get_signature(path,repo),&status_size);
//         char *final_string = NULL;
//         if (status_size>4){
//             final_string = yon_char_unite(status[0],status[1],status[2],status[3],NULL);
//         }
//         free(full_path);
//         free(path);
//         free(repo);
//         yon_char_parsed_free(parsed,size);
//         yon_char_parsed_free(status,status_size);
        
//         return final_string;
//     }
//     return NULL;
// }


// void yon_sublist_build(char *key, storage_struct *storage, main_window *widgets){
// }

void yon_sublist_packages_build(char *key, char *file, main_window *widgets){
    GtkTreeIter iter;
    gtk_list_store_append(widgets->RepoFileList,&iter);
    gtk_list_store_set(widgets->RepoFileList,&iter,1,key,-1);
}

void on_main_tree_selection_changed(GtkWidget *, main_window *widgets){
    gtk_list_store_clear(widgets->RepoFileList);
    gtk_list_store_clear(widgets->RepoPackagesList);
    GtkTreeIter iter;
    GtkTreeModel *model;
    if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->ReposTree)),&model,&iter)){
        char *path;
        enum YON_REPO_DATA_TYPE data_type;
        storage_struct *data_struct;
        gtk_tree_model_get(model,&iter,7,&data_struct,8,&data_type,-1);
        
        if (data_type!=YON_REPO_DATA_ARCH){
            int size;
            config_str repos = (config_str)g_hash_table_get_keys_as_array(data_struct->repos,&size);
            qsort(repos,size,sizeof(char*),(__compar_fn_t)yon_char_parsed_compare);
            GtkTreeIter iter;
            for (int i=0;i<size;i++){
                gtk_list_store_append(widgets->RepoFileList,&iter);
                gtk_list_store_set(widgets->RepoFileList,&iter,1,repos[i],-1);
            }
        } else {
            int size;
            config_str packages = yon_arch_struct_get_packages((arch_struct*)data_struct, &size);
            for (int i=0;i<size;i++){
                int parsed_size;
                config_str parsed = yon_char_parse(packages[i],&parsed_size,";");
                if (size){
                    if (strcmp(parsed[0],"-")){
                        int sign_status = system(yon_repo_get_signature_status(((arch_struct*)data_struct)->storage_path,((arch_struct*)data_struct)->repo_name,((arch_struct*)data_struct)->name,parsed[1]));
                        char *sign_icon = "";
                        char *sign_tooltip = "";
                        if (!sign_status){
                            sign_icon = package_signature_icon_name;
                            sign_tooltip = SIGNED_LABEL;
                        } else {
                            sign_icon = package_signature_error_icon_name;
                            sign_tooltip = UNSIGNED_LABEL;
                        }
                        GtkTreeIter itar;
                        gtk_list_store_append(widgets->RepoFileList,&itar);
                        gtk_list_store_set(widgets->RepoFileList,&itar,0,sign_icon,1,parsed[0],2,parsed[1],3,sign_tooltip,-1);
                    }
                    yon_char_parsed_free(parsed,parsed_size);
                }
            }
            yon_char_parsed_free(packages,size);
        }
    }
}

void yon_package_info_set_markup(config_str parsed, int size){
    for (int i=0;i<size;i++){
        if (strstr(parsed[i],":")){
            char *escaped = g_markup_escape_text(parsed[i],strlen(parsed[i]));
            char *temp = yon_char_divide_search(escaped,":",-1);
            char *temp2 = yon_char_unite("<b>",temp,":</b>",escaped,NULL);
            free(parsed[i]);
            free(escaped);
            free(temp);
            parsed[i]=temp2;
        }
    }
}

void on_package_selection_changed(GtkWidget *self, main_window *widgets){
    GtkTreeIter iter;
    GtkTreeModel *model;
    if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->ReposTree)),&model,&iter)){
        GtkTreeIter subiter;
        GtkTreeModel *submodel;
        if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->RepoFileTree)),&submodel,&subiter)) return;
        char *target, *filename;
        gtk_tree_model_get(submodel,&subiter,1,&target,2,&filename,-1);
        enum YON_REPO_DATA_TYPE data_type;
        gtk_tree_model_get(model,&iter,8,&data_type,-1);
        switch (data_type){
            case YON_REPO_DATA_STORAGE:{
                storage_struct *storage;
                gtk_tree_model_get(model,&iter,7,&storage,-1);
                repo_struct *repo = g_hash_table_lookup(storage->repos,target);
                if (repo){
                    int size;
                    config_str archs = (config_str)g_hash_table_get_keys_as_array(repo->archs,&size);
                    char *archs_str = yon_char_parsed_to_string(archs,size,",");
                    char *info_label = get_repo_info_label(repo->name,archs_str,"");
                    gtk_label_set_markup(GTK_LABEL(widgets->InformationLabel),info_label);
                }
                } break;
            case YON_REPO_DATA_REPO: {
                repo_struct *repo;
                gtk_tree_model_get(model,&iter,7,&repo,-1);
                int size;
                config_str archs = (config_str)g_hash_table_get_keys_as_array(repo->archs,&size);
                char *archs_str = yon_char_parsed_to_string(archs,size,",");

                char *info_label = get_arch_info_label(repo->name,archs_str);
                gtk_label_set_markup(GTK_LABEL(widgets->InformationLabel),info_label);
            } break;
            case YON_REPO_DATA_ARCH: {
                arch_struct *arch;
                gtk_tree_model_get(model,&iter,7,&arch,-1);

                char *path = yon_char_unite(arch->storage_path,"/",arch->repo_name,"/",arch->name,"/",filename,NULL);
                char *command = get_package_info_command(path);
                int size;
                config_str parsed = yon_config_load(command,&size);
                yon_package_info_set_markup(parsed,size);
                char *info_label = yon_char_parsed_to_string(parsed,size,"");

                gtk_label_set_markup(GTK_LABEL(widgets->InformationLabel),info_label);
                yon_char_parsed_free(parsed,size);
                if (!yon_char_is_empty(info_label)) free(info_label);

            } break;
        }
    }
}

void yon_combo_box_text_set_signs(GtkComboBoxText *target){
    g_return_if_fail(GTK_IS_COMBO_BOX_TEXT(target));
    gtk_combo_box_text_remove_all(target);
    gtk_combo_box_text_append_text(target,DO_NOT_SIGN_LABEL);
    for (int i=0;i<main_config.signs_size;i++){
        char *temp = main_config.signs[i];
        int size;
        config_str parsed = yon_char_parse(temp,&size,";");
        char *text = yon_char_wrap_to_length_str(parsed[0],50);
        gtk_combo_box_text_append(target,parsed[1],text);
        yon_char_parsed_free(parsed,size);
    }
}

void yon_sign_list_update(){
    if (main_config.signs&&main_config.signs_size) yon_char_parsed_free(main_config.signs,main_config.signs_size);
    main_config.signs = yon_config_load(yon_debug_output("%s\n",get_gpg_keys_command),&main_config.signs_size);
    for (int i=0;i<main_config.signs_size;i++){
        yon_char_remove_last_symbol(main_config.signs[i],'\n');
    }
}

int yon_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer ){
    char *str_a, *str_b;
    gtk_tree_model_get(model, a, 2, &str_a, -1);
    gtk_tree_model_get(model, b, 2, &str_b, -1);

    if (!str_a) str_a = "";
    if (!str_b) str_b = "";

    return g_utf8_collate(str_a, str_b);
}

void on_ubl_settings_update_launch(){
    yon_launch_app_with_arguments(ubl_settings_update_command,NULL);
}


void on_tree_view_activate(GtkWidget *self, GtkTreePath* path, GtkTreeViewColumn* column, main_window *widgets){
        gtk_tree_view_expand_to_path(GTK_TREE_VIEW(widgets->ReposTree),path);

}

void on_repo_item_activate(GtkWidget *self, GtkTreePath *path, GtkTreeViewColumn *column, main_window *widgets){
    GtkTreeModel *model;
    GtkTreeIter iter;
    GtkTreeSelection *tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->ReposTree));
    gtk_tree_selection_get_selected(tree_selection,&model,&iter);
    if (gtk_tree_store_iter_depth(GTK_TREE_STORE(widgets->RepoList),&iter)<2){
        char *path_id = gtk_tree_model_get_string_from_iter(model,&iter);
        char *target_id = gtk_tree_path_to_string(path);
        char *selection = yon_char_unite(path_id,":",target_id,NULL);
        GtkTreePath *new_selection = gtk_tree_path_new_from_string(selection);
        gtk_tree_view_expand_to_path(GTK_TREE_VIEW(widgets->ReposTree),new_selection);
        gtk_tree_selection_select_path(tree_selection,new_selection);
        // on_package_selection_changed(NULL,widgets);
        g_signal_emit_by_name(G_OBJECT(widgets->ReposTree),"cursor-changed",widgets,G_TYPE_NONE,NULL);
    }
}

void on_update_clicked(GtkWidget *self, main_window *widgets){
    yon_interface_update(widgets);
}

int yon_tree_is_selected(void *widget){
    main_window *widgets = (main_window*)widget;
    GtkTreeModel *model;
    GtkTreeIter iter, itar;
    if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->RepoFileTree)),&model,&iter)){
        gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(widgets->ReposTree)),NULL,&itar);
        if (gtk_tree_store_iter_depth(widgets->RepoList,&itar)==2){
            return 1;
        }
    }
    return 0;
}

main_window *yon_main_window_complete(main_window *widgets){ 
    widgets = yon_remalloc(widgets,sizeof(main_window)); 
    GtkBuilder *builder = gtk_builder_new_from_resource(glade_path); 
    gtk_box_pack_start(GTK_BOX(widgets->InterfaceBox),yon_gtk_builder_get_widget(builder,"BoxMain"),1,1,0); 
    // Custom widgets configuration 
    {
        widgets->UpdateButton = yon_gtk_builder_get_widget(builder,"UpdateButton");
        widgets->DBConfigurationButton = yon_gtk_builder_get_widget(builder,"DBConfigurationButton");
        widgets->AddButton = yon_gtk_builder_get_widget(builder,"AddButton");
        widgets->MoveButton = yon_gtk_builder_get_widget(builder,"MoveButton");
        widgets->RemoveButton = yon_gtk_builder_get_widget(builder,"RemoveButton");
        widgets->CloudButton = yon_gtk_builder_get_widget(builder,"CloudButton");

        widgets->ReposTree = yon_gtk_builder_get_widget(builder,"ReposTree");
        widgets->SearchEntry = yon_gtk_builder_get_widget(builder,"SearchEntry");
        widgets->RepoFileTree = yon_gtk_builder_get_widget(builder,"RepoFileTree");
        widgets->RepoPackagesTree = yon_gtk_builder_get_widget(builder,"RepoPackagesTree");
        widgets->InformationLabel = yon_gtk_builder_get_widget(builder,"InformationLabel");

        widgets->RepoList = GTK_TREE_STORE(gtk_builder_get_object(builder,"RepoStore"));
        widgets->RepoFileList = GTK_LIST_STORE(gtk_builder_get_object(builder,"RepoFileList"));
        widgets->RepoPackagesList = GTK_LIST_STORE(gtk_builder_get_object(builder,"RepoPackageList"));
        {
            gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(widgets->RepoList),2,(GtkTreeIterCompareFunc)yon_sort_func,NULL,NULL);
            gtk_tree_view_column_clicked(gtk_tree_view_get_column(GTK_TREE_VIEW(widgets->ReposTree),0));
            widgets->KeyMenuItem = gtk_menu_item_new();
            gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_widget_get_parent(widgets->AboutMenuItem)),widgets->KeyMenuItem);
            GtkWidget *icon = gtk_image_new_from_icon_name(key_icon_name,GTK_ICON_SIZE_BUTTON);
            GtkWidget *label = gtk_label_new(KEY_LABEL);
            GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0);
            gtk_box_pack_start(GTK_BOX(box),icon,0,0,5);
            gtk_box_pack_start(GTK_BOX(box),label,0,0,5);
            gtk_container_add(GTK_CONTAINER(widgets->KeyMenuItem),box);
            gtk_widget_show_all(widgets->KeyMenuItem);
            gtk_style_context_add_class(gtk_widget_get_style_context(widgets->KeyMenuItem),"menuitemtop");
            gtk_style_context_remove_class(gtk_widget_get_style_context(widgets->DocumentationMenuItem),"menuitemtop");
            gtk_style_context_add_class(gtk_widget_get_style_context(widgets->DocumentationMenuItem),"menuitemmiddle");
            g_signal_connect(G_OBJECT(widgets->KeyMenuItem),"activate",G_CALLBACK(on_key_clicked),widgets);
        }
        main_config.tree_store = widgets->RepoList;

        rmb_menu_window *rmb = yon_rmb_menu_setup(widgets->RepoFileTree, yon_tree_is_selected,widgets,
        SIGN_LABEL,lib_key_icon_name,G_CALLBACK(on_packages_sign),widgets,
        MOVE_PACKAGES_TITLE_LABEL,move_icon,G_CALLBACK(on_move_clicked),widgets,
        REMOVE_PACKAGES_TITLE_LABEL,remove_icon,G_CALLBACK(on_remove_clicked),widgets,
        NULL);

        g_signal_connect(G_OBJECT(widgets->DBConfigurationButton),"clicked",G_CALLBACK(on_storage_configure_clicked),widgets);
        g_signal_connect(G_OBJECT(widgets->AddButton),"clicked",G_CALLBACK(on_add_clicked),widgets);
        g_signal_connect(G_OBJECT(widgets->MoveButton),"clicked",G_CALLBACK(on_move_clicked),widgets);
        g_signal_connect(G_OBJECT(widgets->RemoveButton),"clicked",G_CALLBACK(on_remove_clicked),widgets);
        g_signal_connect(G_OBJECT(widgets->ReposTree),"cursor-changed",G_CALLBACK(on_main_tree_selection_changed),widgets);
        g_signal_connect(G_OBJECT(widgets->CloudButton),"clicked",G_CALLBACK(on_ubl_settings_update_launch),widgets);
        g_signal_connect(G_OBJECT(widgets->RepoFileTree),"cursor-changed",G_CALLBACK(on_package_selection_changed),widgets);
        g_signal_connect(G_OBJECT(widgets->ReposTree),"row-activated",G_CALLBACK(on_tree_view_activate),widgets);
        g_signal_connect(G_OBJECT(widgets->RepoFileTree),"row-activated",G_CALLBACK(on_repo_item_activate),widgets);
        g_signal_connect(G_OBJECT(widgets->UpdateButton),"clicked",G_CALLBACK(on_update_clicked),widgets);
        yon_calendar_set_date_orientation(1);
        gtk_window_set_title(GTK_WINDOW(widgets->Window),TITLE_LABEL);

        gtk_tree_view_set_search_entry(GTK_TREE_VIEW(widgets->RepoFileTree),GTK_ENTRY(widgets->SearchEntry));

        /* Widget registration for config monitoring | Регистрация виджетов для мониторинга конфига */
        /* Localisation | Локализация */
        return widgets;
    }
}

int main(int argc, char *argv[]){ 
    setlocale(LC_ALL, "");
    textdomain (LocaleName);
    yon_ubl_connect_config((_template_config*)&main_config); 
    config_init();
    
    yon_ubl_window_init(TITLE_LABEL,TITLE_INFO_LABEL,LocaleName,CssPath,LocaleName,version_application,WIKI_LINK);
	config_str unfound = NULL;
	int size=0;
	yon_ubl_setup_arguments(argc,argv,&unfound,&size,NULL);
    gtk_init(&argc,&argv);
    template_main_window *widgets = yon_ubl_window_setup(); 
    gtk_widget_hide(gtk_menu_get_attach_widget(GTK_MENU(gtk_widget_get_parent(widgets->SaveMenuItem))));
    gtk_widget_hide(gtk_menu_get_attach_widget(GTK_MENU(gtk_widget_get_parent(widgets->LoadGlobalMenuItem))));
    widgets = (template_main_window*)yon_main_window_complete((main_window*)widgets);
        yon_window_remove_exit_config_check(widgets);
    char *path = yon_char_unite(yon_ubl_user_get_home_directory(),"/.config/",LocaleName,"/",LocaleName,".conf",NULL);
    yon_window_config_load(path);
    // yon_config_load_update((main_window*)widgets);
        yon_interface_update((main_window*)widgets);
        yon_ubl_status_box_render(DATA_LOADED_LABEL,BACKGROUND_IMAGE_SUCCESS_TYPE);
    gtk_main();
    return 0;
}