#include "ubl-settings-repomanager.h"

void yon_arch_sturct_free_full(arch_struct *arch);
void yon_repo_sturct_free_full(repo_struct *repo);

void yon_storage_fill_repos(storage_struct *storage, config_str repos, int repos_size){
    for (int i=0;i<repos_size;i++){
        repo_struct *repo = yon_repo_struct_new();
        repo->name=yon_path_get_name(repos[i]);
        repo->path=yon_char_new(repos[i]);
        repo->storage_path=storage->path;
        yon_repo_fill_archs(repo);
        g_hash_table_insert(storage->repos,repo->name,repo);
    }
}

void yon_storage_sturct_free_full(storage_struct *storage){
    if (!yon_char_is_empty(storage->name)) free(storage->name);
    if (!yon_char_is_empty(storage->path)) free(storage->path);
    GList *repos = g_hash_table_get_values(storage->repos);
    GList *iter;
    for (iter=repos;iter;iter=iter->next){
        yon_repo_sturct_free_full((repo_struct*)iter->data);
    }
    free(storage);
}

storage_struct *yon_storage_struct_new(){
    storage_struct *storage = malloc(sizeof(storage_struct));
    storage->name=NULL;
    storage->path=NULL;
    storage->repos = g_hash_table_new(g_str_hash,g_str_equal);
    storage->sign_status=0;
    return storage;
}

void yon_repo_fill_archs(repo_struct *repo){
    int size;
    config_str folders = yon_file_ls(repo->path,&size);
    for (int i=0;i<size;i++){
        char *full_path = yon_char_unite(repo->path,"/",folders[i],NULL);
        if (yon_file_is_directory(full_path)&&
            (strcmp(folders[i],".")&&
            strcmp(folders[i],".."))){
            arch_struct *arch = yon_arch_struct_new();
            arch->name = yon_char_new(folders[i]);
            arch->path = yon_char_unite(repo->path,"/",arch->name,NULL);
            arch->storage_path=repo->storage_path;
            arch->repo_name=repo->name;
            yon_arch_fill_packages(arch);
            g_hash_table_insert(repo->archs,arch->name,arch);
        }
        free(full_path);
    }
}

void yon_repo_sturct_free_full(repo_struct *repo){
    if (!yon_char_is_empty(repo->name)) free(repo->name);
    if (!yon_char_is_empty(repo->path)) free(repo->path);
    if (!yon_char_is_empty(repo->storage_path)) free(repo->storage_path);
    GList *archs = g_hash_table_get_values(repo->archs);
    GList *iter;
    for (iter=archs;iter;iter=iter->next){
        yon_arch_sturct_free_full((arch_struct*)iter->data);
    }
    free(repo);
}

repo_struct *yon_repo_struct_new(){
    repo_struct *storage = malloc(sizeof(repo_struct));
    storage->name=NULL;
    storage->path=NULL;
    storage->storage_path=NULL;
    storage->archs = g_hash_table_new(g_str_hash,g_str_equal);
    storage->sign_status=NULL;
    return storage;
}

void yon_arch_fill_packages(arch_struct *arch){
    int size;
    char *command = yon_get_packages_command(arch->storage_path, arch->repo_name, arch->name);
    config_str packages = yon_config_load(command,&size);
    for (int i=0;i<size;i++){
        yon_char_remove_last_symbol(packages[i],'\n');
        int parsed_size;
        config_str parsed = yon_char_parse(packages[i],&parsed_size,";");
        g_hash_table_insert(arch->packages,parsed[0],parsed[1]);
        free(parsed);
    }
}

void yon_arch_sturct_free_full(arch_struct *arch){
    if (!yon_char_is_empty(arch->name)) free(arch->name);
    if (!yon_char_is_empty(arch->path)) free(arch->path);
    if (!yon_char_is_empty(arch->storage_path)) free(arch->storage_path);
    GList *archs = g_hash_table_get_values(arch->packages);
    GList *iter;
    for (iter=archs;iter;iter=iter->next){
        free(iter->data);
    }
    free(arch);
}

arch_struct *yon_arch_struct_new(){
    arch_struct *storage = malloc(sizeof(arch_struct));
    storage->name=NULL;
    storage->storage_path=NULL;
    storage->repo_name=NULL;
    storage->path=NULL;
    storage->packages = g_hash_table_new(g_str_hash,g_str_equal);
    return storage;
}

config_str yon_arch_struct_get_packages(arch_struct *arch, int *size){
    char *command = yon_get_packages_command(arch->storage_path,arch->repo_name,arch->name);
    (*size)=0;
    config_str packages = yon_config_load(command,size);
    if (size&&packages){
        for (int i=0;i<(*size);i++){
            yon_char_remove_last_symbol(packages[i],'\n');
        }
    }
    return packages;
}

void yon_package_hash_table_clone(GHashTable *source_hash, GHashTable *target_hash){
    GList *list = g_hash_table_get_keys(source_hash);
    GList *iter;
    for (iter = list;iter;iter=iter->next){
        char *key = (char*)iter->data;
        char *package_name = g_hash_table_lookup(source_hash,key);
        g_hash_table_insert(target_hash,key,yon_char_new(package_name));
    }
}

arch_struct *yon_arch_copy_full(arch_struct *repo){
    arch_struct *copy = yon_arch_struct_new();
    copy->name=yon_char_new(repo->name);
    copy->path=yon_char_new(repo->path);
    copy->storage_path=yon_char_new(repo->storage_path);
    copy->repo_name=yon_char_new(repo->repo_name);
    yon_package_hash_table_clone(repo->packages,copy->packages);
    return copy;
}

void yon_arch_hash_table_clone(GHashTable *source_hash, GHashTable *target_hash){
    GList *list = g_hash_table_get_values(source_hash);
    GList *iter;
    for (iter = list;iter;iter=iter->next){
        arch_struct *storage = (arch_struct*)iter->data;
        arch_struct *storage_copy = yon_arch_copy_full(storage);
        g_hash_table_insert(target_hash,storage_copy->name,storage_copy);
    }
}

repo_struct *yon_repo_copy_full(repo_struct *repo){
    repo_struct *copy = yon_repo_struct_new();
    copy->name=yon_char_new(repo->name);
    copy->path=yon_char_new(repo->path);
    copy->storage_path=yon_char_new(repo->storage_path);
    copy->sign_status=repo->sign_status;
    yon_arch_hash_table_clone(repo->archs,copy->archs);
    return copy;
}

void yon_repo_hash_table_clone(GHashTable *source_hash, GHashTable *target_hash){
    GList *list = g_hash_table_get_values(source_hash);
    GList *iter;
    for (iter = list;iter;iter=iter->next){
        repo_struct *storage = (repo_struct*)iter->data;
        repo_struct *storage_copy = yon_repo_copy_full(storage);
        g_hash_table_insert(target_hash,storage_copy->name,storage_copy);
    }
}

storage_struct *yon_storage_copy_full(storage_struct *storage){
    storage_struct *copy = yon_storage_struct_new();
    copy->name=yon_char_new(storage->name);
    copy->path=yon_char_new(storage->path);
    copy->sign_status=storage->sign_status;
    yon_repo_hash_table_clone(storage->repos,copy->repos);
    return copy;
}

void yon_storage_hash_table_clone(GHashTable *source_hash, GHashTable *target_hash){
    GList *list = g_hash_table_get_values(source_hash);
    GList *iter;
    for (iter = list;iter;iter=iter->next){
        storage_struct *storage = (storage_struct*)iter->data;
        storage_struct *storage_copy = yon_storage_copy_full(storage);
        g_hash_table_insert(target_hash,storage_copy->path,storage_copy);
    }
}

void yon_storage_struct_add_repo(storage_struct *storage,repo_struct *repo){
    char *str = config(STORAGE(storage->path));
    if (!yon_char_is_empty(str)){
        int size;
        config_str parsed = yon_char_parse(str,&size,";");
        
        if (size>1&&!yon_char_is_empty(parsed[1])){
            int added_size;
            config_str added = yon_char_parse(parsed[1],&added_size,",");
            if (yon_char_parsed_check_exist(added,added_size,repo->name)==-1){
                yon_char_parsed_add_or_create_if_exists(added,&added_size,repo->name);
            } else {
                yon_char_parsed_free(added,added_size);
                return;
            }
            if (!yon_char_is_empty(parsed[1])) free(parsed[1]);
            parsed[1] = yon_char_parsed_to_string(parsed,size,",");
        } else if (size>0){
            yon_char_parsed_add_or_create_if_exists(parsed,&size,repo->name);
        } else {
            yon_char_parsed_add_or_create_if_exists(parsed,&size,"");
            yon_char_parsed_add_or_create_if_exists(parsed,&size,repo->name);
            yon_char_parsed_add_or_create_if_exists(parsed,&size,"");

        }
        char *final = yon_char_parsed_to_string_full(parsed,size,";");
        yon_config_register(STORAGE(storage->path),STORAGE_command,final);
        free(final);
        if (parsed&&size) yon_char_parsed_free(parsed,size);
    } else {
        char *final = yon_char_unite(";",repo->name,";",NULL);
        yon_config_register(STORAGE(storage->path),STORAGE_command,final);
        free(final);
    }

}

void yon_storage_struct_remove(storage_struct *storage,repo_struct *repo){

    char *str = config(STORAGE(storage->path));
    if (!yon_char_is_empty(str)){
        int size;
        config_str parsed = yon_char_parse(str,&size,";");
        
        if (size>0&&!yon_char_is_empty(parsed[0])){
            int removed_size;
            config_str removed = yon_char_parse(parsed[0],&removed_size,",");
            if (yon_char_parsed_check_exist(removed,removed_size,repo->name)==-1){
                yon_char_parsed_add_or_create_if_exists(removed,&removed_size,repo->name);
            } else {
                yon_char_parsed_free(removed,removed_size);
                return;
            }
            if (!yon_char_is_empty(parsed[1])) free(parsed[1]);
            parsed[1] = yon_char_parsed_to_string_full(parsed,size,",");
        } else {
            yon_char_parsed_add_or_create_if_exists(parsed,&size,repo->name);
            yon_char_parsed_add_or_create_if_exists(parsed,&size,"");
            yon_char_parsed_add_or_create_if_exists(parsed,&size,"");
        }
        char *final = yon_char_parsed_to_string_full(parsed,size,";");
        yon_config_register(STORAGE(storage->path),STORAGE_command,final);
        free(final);
        if (parsed&&size) yon_char_parsed_free(parsed,size);
    } else {
        char *final = yon_char_unite(repo->name,";;",NULL);
        yon_config_register(STORAGE(storage->path),STORAGE_command,final);
        free(final);
    }
}

void yon_repo_struct_sign(storage_struct *storage, repo_struct *repo,const char *sign){
    char *str = config(STORAGE(storage->path));
    int size;
    config_str parsed = yon_char_parse(str,&size,";");
    if (size>2&&!yon_char_is_empty(parsed[2])){
        int signs_size;
        config_str signs = yon_char_parse(parsed[2],&signs_size,",");
        char *final = yon_char_unite(repo->name,":",sign,NULL);
        yon_char_parsed_add_or_create_if_exists(signs,&signs_size,final);
        free(final);
        yon_char_parsed_free(signs,signs_size);
    } else if (size>1){
        char *final = yon_char_unite(repo->name,":",sign,NULL);
        yon_char_parsed_add_or_create_if_exists(parsed,&size,final);
        free(final);
    } else if (size>0){
        char *final = yon_char_unite(repo->name,":",sign,NULL);
        yon_char_parsed_add_or_create_if_exists(parsed,&size,"");
        yon_char_parsed_add_or_create_if_exists(parsed,&size,final);
        free(final);
    } else if (!size){
        char *final = yon_char_unite(repo->name,":",sign,NULL);
        yon_char_parsed_add_or_create_if_exists(parsed,&size,"");
        yon_char_parsed_add_or_create_if_exists(parsed,&size,"");
        yon_char_parsed_add_or_create_if_exists(parsed,&size,final);
        free(final);
    }
    char *final = yon_char_parsed_to_string_full(parsed,size,";");
    yon_config_register(STORAGE(storage->path),STORAGE_command,final);
    free(final);
    if (parsed&&size) yon_char_parsed_free(parsed,size);
}