#include "ubl-utils.h"

// dictionary functions

/**yon_dictionary_new():
 * [EN]
 * Creates and returns empty dictionary
 * [RU]
 * Создаёт и возвращает пустой словарь.
 */
dictionary *yon_dictionary_new()
{
    dictionary *dict = malloc(sizeof(dictionary));
    dict->data = NULL;
    dict->key = NULL;
    dict->next = NULL;
    dict->prev = NULL;
    dict->first = dict;
    dict->data_type = DICTIONARY_OTHER_TYPE;
    return dict;
}

/**yon_dictionary_copy(dictionary *dict)
 * [EN]
 * 
 * [RU]
 * Создаёт и возвращает копию элемента словаря [dict]
*/
dictionary *yon_dictinoary_copy(dictionary *dict){
    dictionary *dct = yon_dictionary_new_with_data(dict->key,dict->data);
    dct->data_type= dict->data_type;
    return dct;
}

/**yon_dictionary_copy_deep(dictionary *dict)
 * [EN]
 * 
 * [RU]
 * Создаёт полную копию словаря [dict] и возвращает первый элемент
*/
dictionary *yon_dictionary_copy_deep(dictionary *dict){
    dictionary *dct = NULL;
    dictionary *newone=NULL;
    for_dictionaries(dct,dict){
        yon_dictionary_add_or_create_if_exists_with_data(newone,dct->key,dct->data);
        newone->data_type=dct->data_type;
    }
    return newone->first;
}

/**int yon_dictionary_set_data(dictionary *dict, void *data)
 * [EN]
 * 
 * [RU]
 * Установить элементу словаря [dict] значение [data]
*/
int yon_dictionary_set_data(dictionary *dict, void *data){
    dict->data=data;
}

/**int yon_dictionary_set_key(dictionary *dict, char *key)
 * [EN]
 * 
 * [RU]
 * Изменяет ключ элемента словаря [dict] на [key]
*/
int yon_dictionary_set_key(dictionary *dict, char *key){
    dict->key=key;
    return 1;
}

/** int yon_dictionary_set(dictionary *dict, char *key, void *data)
 * [EN]
 * 
 * [RU]
* Устанавливает значение ключа элемента словаря [dict] на [key] и его данные на [data] 
*/
int yon_dictionary_set(dictionary *dict, char *key, void *data){
    dict->key=key;
    dict->data=data;
    return 1;
}

/**int yon_dictionary_empty(dictionary *dict)
 * [EN]
 * 
 * [RU]
 * Очищает элемент словаря [dict] от данных
*/
int yon_dictionary_empty(dictionary *dict){
    dict->data=NULL;
    dict->data_type=DICTIONARY_OTHER_TYPE;
    return 1;
}

/**yon_dictionary_switch_to_last(dictionary **dict)
 * [EN]
 * 
 * [RU]
 * Переключает словарь [dict] на последний элемент.
*/
void yon_dictionary_switch_to_last(dictionary **dict)
{
    dictionary *dct=NULL, *dact=*dict;
    for_dictionaries(dct,dact);
}

/**yon_dictionary_create_conneced(dictionary *targetdict)
 * [EN]
 * 
 * [RU]
 * Создаёт новый элемент словаря [targetdict]
*/
dictionary *yon_dictionary_append(dictionary *targetdict)
{
    targetdict = yon_dictionary_get_last(targetdict);
    targetdict->next = yon_dictionary_new();
    targetdict->next->prev = targetdict;
    targetdict->next->first = targetdict->first;
    targetdict->next->data_type = DICTIONARY_OTHER_TYPE;
    return targetdict->next;
}

/**yon_dictionary_get_last(dictionary *dict)
 * [EN]
 * 
 * [RU]
 * Возвращает последний элемент словаря [dict].
 * В отличае от yon_dictionary_switch_to_last()
 * словарь [dict] остаётся на прежнем элементе.
*/
dictionary *yon_dictionary_get_last(dictionary *dict)
{
    if (dict->next){
        dictionary *dct = NULL;
        for_dictionaries(dct,dict);
        return dct;
    } else return dict;
}

/**yon_dictionary_switch_places(dictionary *dict, int aim)
 * [EN]
 * 
 * [RU]
 * Меняет элемент словаря [dict] местами с другим элементом.
 * если [aim]<0 элемент меняется местами с левым элементом;
 * если [aim]>0 элемент меняется местами с правым элементом;
*/
dictionary *yon_dictionary_swap(dictionary *dict, int aim)
{
    if (aim < 0)
    {
        if (dict->prev)
        {
            if (dict->prev->prev)
            {
                dictionary *next = dict->next, *prev = dict->prev, *preprev = prev->prev;
                if (next)
                {
                    preprev->next = dict;
                    dict->prev = preprev;
                    dict->next = prev;
                    prev->prev = dict;
                    prev->next = next;
                    next->prev = prev;
                }
                else
                {
                    preprev->next = dict;
                    dict->prev = preprev;
                    dict->next = prev;
                    prev->prev = dict;
                    prev->next = NULL;
                }
                return prev;
            }
            else
            {
                dictionary *next = dict->next, *prev = dict->prev;
                if (next)
                {
                    yon_dictionary_make_first(dict);
                    dict->prev = NULL;
                    dict->next = prev;
                    prev->prev = dict;
                    prev->next = next;
                    next->prev = prev;
                }
                else
                {
                    dict->prev = NULL;
                    dict->next = prev;
                    prev->prev = dict;
                    prev->next = NULL;
                }
                return prev;
            }
        }
    }
    else if (aim > 0)
    {
        if (dict->next)
        {
            if (dict->next->next)
            {
                dictionary *next = dict->next, *prev = dict->prev, *afnext = next->next;
                if (prev)
                {
                    prev->next = next;
                    next->prev = prev;
                    next->next = dict;
                    dict->prev = next;
                    dict->next = afnext;
                    afnext->prev = dict;
                }
                else
                {
                    yon_dictionary_make_first(next);
                    next->prev = NULL;
                    next->next = dict;
                    dict->prev = next;
                    dict->next = afnext;
                    afnext->prev = dict;
                }
                return next;
            }
            else
            {
                dictionary *next = dict->next, *prev = dict->prev;
                if (prev)
                {
                    prev->next = next;
                    next->prev = prev;
                    next->next = dict;
                    dict->prev = next;
                    dict->next = NULL;
                }
                else
                {
                    next->prev = NULL;
                    next->next = dict;
                    dict->prev = next;
                    dict->next = NULL;
                }
            }
        }
    }
}

/**yon_dictionary_make_first(dictionary *dict)
 * [EN]
 * 
 * [RU]
 * Устанавливает указатель первого элемента словаря [dict]
 * на текущий элемент. Не использовать.
*/
void yon_dictionary_make_first(dictionary *dict)
{
    for (dictionary *dct = dict->first; dct != NULL; dct = dct->next)
    {
        dct->first = dict;
    }
}

/**yon_dictionary_make_nth(dictionary *dict, int nth)
 * [EN]
 * 
 * [RU]
 * Перемещает элемент словаря [dict] на позицию [nth].
*/
void yon_dictionary_make_nth(dictionary *dict, int nth)
{
    dictionary *dct = dict->first;
    for (int i = 0; i < nth; i++)
    {
        if (dct == NULL)
            return;
        else
            dct = dct->next;
    }
    yon_dictionary_rip(dict);
    dictionary *prev = dct->prev;
    prev->next = dict;
    dict->prev = prev;
    dict->next = dct;
    dct->prev = dict;
}

/**yon_dictionary_create_with_data(char *key, void *data)
 * [EN]
 * 
 * [RU]
 * Создаёт новый словарь с ключом [key] и указателем на данные [data] 
*/
dictionary *yon_dictionary_new_with_data(char *key, void *data)
{
    dictionary *dct = yon_dictionary_new();
    dct->key = yon_char_new(key);
    dct->data = data;
    dct->data_type = DICTIONARY_OTHER_TYPE;
    return dct;
}

/** void *yon_dictionary_free_all(dictionary *dictionary,void *data_manipulation)
 * [EN]
 * Frees whole [dictionary] and activates [data_manipulation] function if not NULL with [dictionary]->data argument for each dictionary.
 * [RU]
 * Освобождает память для всех элементов словаря [dictionary] и активирует функцию [data_manipulation], если она была передана, с аргументом [dictionary]->data на каждый элемент словаря.
*/
void *yon_dictionary_free_all(dictionary *dictionary_to_free,void (*data_manipulation)(void*)){
    dictionary *dict=NULL;
    for_dictionaries(dict,dictionary_to_free){
        if(data_manipulation)
            data_manipulation(dict->data);
        if(dict->prev)
            free(dict->prev);
    }
    free(dict);
    return NULL;
}

/**yon_dictionary_create_with_data_connected(dictionary *dict, char *key, void *data)
 * [EN]
 * 
 * [RU]
 * Создаёт новый элемент словаря, присоединяемый в конец словаря [dict]
 * с ключом [key] и указателем на данные [data]
*/
dictionary *yon_dictionary_append_with_data(dictionary *dict, char *key, void *data)
{
    dictionary *dct = yon_dictionary_append(dict);
    dct->key = yon_char_new(key);
    dct->data = data;
    dct->data_type = DICTIONARY_OTHER_TYPE;
    return dct;
}

/**yon_dictionary_connect(dictionary *old, dictionary *toconnect)
 * [EN]
 * 
 * [RU]
 * Присоединяет словарь [toconnect] в конец словаря [old].
*/
dictionary *yon_dictionary_connect(dictionary *old, dictionary *toconnect)
{
    dictionary *dict = yon_dictionary_get_last(old);
    dict->next = toconnect;
    toconnect->prev = dict;
    toconnect->first = dict->first;
    return toconnect;
}

/**yon_dictionary_get(dictionary **dict, char *key)
 * [EN]
 * 
 * [RU]
 * Возвращает элемент словаря [dict] с ключом [key].
 * Если такого элемента не было обнаружено, возвращается NULL 
*/
dictionary *yon_dictionary_get(dictionary **dict, char *key)
{
    dictionary *dct = *dict;
    for (dictionary *pointer = dct->first; pointer != NULL; pointer = pointer->next)
    {
        if (strcmp(pointer->key, key) == 0)
        {
            *dict = pointer;
            return pointer;
        }
    }
    return NULL;
}

/**yon_dictionary_rip(dictionary *dict)
 * [EN]
 * 
 * [RU]
 * Вырезает элемент из словаря и возвращает вырезанный элемент.
*/
dictionary *yon_dictionary_rip(dictionary *dict)
{
    if (!dict->next&&!dict->prev) return NULL;
    else if (!dict->next)
    {
        dictionary *prev = dict->prev;
        if (prev)
        {
            prev->next = NULL;
            return prev;
        }
        else
            return dict;
    }
    else if (!dict->prev)
    {
        dictionary *next = dict->next;
        if (next)
        {
            yon_dictionary_make_first(next);
            next->prev = NULL;
            return next;
        }
        else
            return dict;
    }
    else
    {
        dictionary *next = dict->next, *prev = dict->prev;
        next->prev = prev;
        prev->next = next;
        return next;
    }
}

/**yon_dictionary_get_nth(dictionary *dict, int place)
 * [EN]
 * 
 * [RU]
 * Возвращает [place]-й элемент словаря [dict]
*/
dictionary *yon_dictionary_get_nth(dictionary *dict, int place)
{
    if (dict){
        dict = dict->first;
        int i = 0;
        for (i = 0; i < place; i++)
            if (dict->next)
                dict = dict->next;
            else
                break;
        if (i == place)
            return dict;
        else
            return NULL;
    } else return NULL;
}

// char functions

int yon_char_find_last(char *source, char find){
    int size = strlen(source);
    int i=size;
    for (;source[i]!=find&&i>0;i--);
    return i;
}

/**[EN]
 * 
 * creates new char string by combining two char strings.
 */
char *yon_char_append(char *source, char *append)
{
    if (source && append)
    {
        int size = strlen(source) + strlen(append) + 1;
        char *final = malloc(size);
        memset(final, 0, size);
        if (strstr(source, "%%"))
            sprintf(final, source, append);
        else
            sprintf(final, "%s%s", source, append);
        return final;
    }
    else
        return NULL;
}

/**[EN]
 * 
 * creates new char string by copying another char.
 */
char *yon_char_new(char *chr)
{
    if (chr){
        char *newchar = malloc(strlen(chr) + 1);
        memset(newchar, 0, strlen(chr) + 1);
        memcpy(newchar, chr, strlen(chr));
        return newchar;
    } else
        return NULL;
}

/**yon_char_unite(char *source, ...)
 * [En]
 * 
 * [RU]
 * Объединяет строку [source] со всеми строками, написанными в [...]
*/
char *yon_char_unite(char *source, ...){
    va_list arglist;
    char *new_char=NULL;
    char *unite_char=NULL;
    new_char=yon_char_new(source);
    va_start(arglist,source);
    unite_char = va_arg(arglist,char*);
    while(unite_char){
        new_char = yon_char_append(new_char,unite_char);
        unite_char = va_arg(arglist,char*);
    }
    va_end(arglist);
    return new_char;
}

/**yon_cut(char *source, int size, int startpos)
 * [EN]
 * cuts source string by size length from startpos position.
 */
char *yon_cut(char *source, int size, int startpos)
{
    char *cut = NULL;
    cut = malloc(size + 1);
    memset(cut, 0, size + 1);
    memcpy(cut, source + startpos, size);
    return cut;
}

/**yon_char_divide(char *source, int dividepos)
 * [EN]
 * divides source string in dividepos position,
 * returning left part of divided string and
 * inserting right part to source string.
 */
char *yon_char_divide(char *source, int dividepos)
{
    char *cut = malloc(dividepos + 1);
    memset(cut, 0, dividepos + 1);
    memcpy(cut, source, dividepos);
    char *left = malloc(strlen(source) - strlen(cut));
    memset(left, 0, strlen(source) - strlen(cut));
    memcpy(left, source + dividepos + 1, (strlen(source) - dividepos));
    memset(source, 0, strlen(source));
    memcpy(source, left, strlen(left));
    return cut;
}

/**yon_char_find_count(char *source, char *find)
 * [EN]
 * 
 * [RU]
 * Считает количество символов [find] в строке [source]
*/
int yon_char_find_count(char *source, char *find){
    char *working_string=source;
    int size=0;
    while ((working_string = strstr(working_string, find))) {
        if (working_string) {
            working_string++;
            size++;
        }
    }
    return size;
}

/**yon_char_divide_search(char *source, char *dividepos, int delete_divider)
 * [EN]
 * char *yon_char_divide_search(char *source, char *dividepos, int delete_divider)
 * searches string [dividepos] in [source] string and divides it,
 * returning left part of divided string and
 * inserting right part to [source] string.
 * if [delete_divider] is 0, left part will contain [delete_divider] substring, else
 * if [delete_divider] is 1 it will stay in right part, else
 * if [delete_divider] is -1 it will be deleted from string.
 * 
 * [RU]
 * char *yon_char_divide_search(char *source, char *dividepos, int delete_divider)
 * Ищет строку [dividepos] в строке [source] и делит её в этом месте,
 * возвращая левую часть разделённой строки и устанавливает в [source] правую часть.
 * Если [delete_divider] равен 0, [dividepos] останется в левой строке, иначе
 * если [delete_divider] равен 1, [dividepos] останется в правой строке, иначе
 * если [delete_divider] равен -1, [dividepos] удаляется из строки.
 */
char *yon_char_divide_search(char *source, char *dividepos, int delete_divider)
{
    if (source&&dividepos){
        char *cut = strstr(source, dividepos);
        if (cut)
        {
            int leng = strlen(source) - strlen(cut);
            cut = yon_char_divide(source, leng);
            return cut;
        }
    }
    return source;
}

/**yon_char_from_int(int int_to_convert)
 * [EN]
 * char *yon_char_from_int(int int_to_convert)
 * converts int to char*.
 * 
 * [RU]
 * char *yon_char_from_int(int int_to_convert)
 * Конвертирует int в char*
 */
char *yon_char_from_int(int int_to_convert)
{
    int i = 1;
    float convert_check = (float)int_to_convert;
    for (i = 1; convert_check >= 10; i++)
    {
        convert_check = convert_check / 10;
    }
    char *ch = g_malloc0(i * sizeof(char) + 1);
    sprintf(ch, "%d", int_to_convert);
    return ch;
}

/**yon_char_replace(char *source, char *find, char*replace)
 * [EN]
 * 
 * [RU]
 * Заменяет в строке [source] все вхождения строки [find] на [replace]
*/
char *yon_char_replace(char *source, char *find, char*replace){
    if (!strstr(replace,find)){


        char *final=NULL;
        char *temp=NULL;
        if(!strstr(replace,find)){
            while ((final=strstr(source,find))){
                temp=malloc(strlen(source)-strlen(final));
                memset(temp,0,strlen(source)-strlen(final)+strlen(replace));
                memcpy(temp,source,strlen(source)-strlen(final));
                temp=yon_char_append(temp,replace);
                source=yon_char_append(temp,final+1);
            }
            
        }
    }
    return source;
}

/**yon_char_parse(char *parameters, int *size, char *divider)
 * [EN]
 * Parses string [parameters], divided by [divider],
 * then returns parsed string array and sets [size] to
 * size of returned array
*/
char **yon_char_parse(char *parameters, int *size, char *divider){
    char **string=NULL;
    if (!strstr(parameters, divider)) {
        return NULL;
    }
    int i=1;
    string=malloc(sizeof(char*));
    char *paramline=yon_char_new(parameters);
    char *param;
    while ((param=yon_char_divide_search(paramline,divider,1))){
        if (strcmp(param,paramline)==0) break;
        string=realloc(string,sizeof(char*)*i);
        string[i-1]=yon_char_new(param);
        i++;
    }
    string=realloc(string,sizeof(char*)*i);
        string[i-1]=yon_char_new(paramline);
        i++;
    // printf("%d\n",i);
    *size=i-1;
    return string;

}

/**yon_char_parsed_rip(char **char_string, int *size, int item_to_delete)
 * [EN]
 * 
 * [RU]
 * Удаляет элемент [item_to_delete] из массива строк [char_string], размера [size]
 * Возвращает получившийся массив, в [size] загружается размер нового массива.
*/
char **yon_char_parsed_rip(char **char_string, int *size, int item_to_delete){
    char **new_char_parsed=NULL;
    new_char_parsed=malloc(sizeof(char*)*((*size)-1));
    int flag = 0;
    for (int i=0;i < (*size);i++){
        if (i==item_to_delete) {
            flag = 1;
        }
        if (flag == 0) {
            new_char_parsed[i]=yon_char_new(char_string[i]);
        }
        else if (flag == 1 && i!=item_to_delete) {
            new_char_parsed[i-1]=yon_char_new(char_string[i]);
        }
    }
    (*size)=(*size)-1;
    return new_char_parsed;
}

/**yon_char_parsed_check_exist(char **parameters, int size, char *param)
 * [EN]
 * Checks if [parameters] string array of length [size]
 * has [param] element;
 * [RU]
 * Проверяет есть ли в массиве строк [parameters], размера [size]
 * элемент [param]
*/
int yon_char_parsed_check_exist(char **parameters, int size, char *param){
    
    for (int i=0;i<size;i++){
        if (parameters[i]){
            if (strstr(parameters[i],param))
                return i;
        } else return -1;
    }

    return -1;
}

/**yon_char_parsed_includes_char_parsed (config_str source, config_str to_check, int source_size, int check_size)
 * [EN]
 * 
 * [RU]
 * Проверяет, включает ли в себя [source] размера [source_size]
 * массив строк [to_check] размера [check_size]
*/
int yon_char_parsed_includes_char_parsed (config_str source, config_str to_check, int source_size, int check_size){
    int overall_found=0;
    for (int i=0;i<source_size;i++){
        int found=0;
        for (int j=0;j<check_size;j++){
            if (strcmp(source[i],to_check[j])==0&&found==0) { found=1; overall_found++; }
        }
    }
    if (overall_found==check_size)
        return 1;
    else return 0;
}

/**yon_char_parsed_new (config_str old, int *old_size, ...)
 * [EN]
 * 
 * [RU]
 * Создаёт новый массив строк. В [size] выгружается его размер
 * [...] - неограниченное количество строк.
*/
config_str yon_char_parsed_new (int *size, ...){
    va_list arglist;
    config_str new_parsed=NULL;
        new_parsed=new(char*);
    int new_size=0;
    va_start(arglist,size);
    char *newparse = va_arg(arglist,char*);
    while (newparse){
        new_size++;
        new_parsed=realloc(new_parsed,new_size*sizeof(char*));
        new_parsed[new_size-1]=yon_char_new(newparse);
        newparse=va_arg(arglist,char*);
    }
    va_end(arglist);
    *size=new_size;
    return new_parsed;
}

/**yon_char_parsed_copy(config_str *source, config_str *to_copy)
 * [EN]
 * 
 * [RU]
 * Копирует массив строк [to_copy] в [source] 
*/
void yon_char_parsed_copy(config_str *source, config_str *to_copy){
    if (source&&!*source&&to_copy&&*to_copy){
        int size=0;
        config_str new_char = yon_char_parsed_new(&size,(*to_copy)[0]);
        for (int i=0;(*to_copy)[i];i++){
            new_char = yon_char_parsed_append(new_char,&size,yon_char_new((*to_copy)[i]));
        }
        if (new_char) *source = new_char;
    }
}

/**config_str yon_char_parsed_append(config_str parsed, int *size, char *string)
 * [EN]
 * Adds [string] at the end of [parsed] string array of [size] length.
 * [RU]
 * Добавляет строку [string] в конец массива строк [parsed] с длинной [size].
*/
config_str yon_char_parsed_append(config_str parsed, int *size, char *string){
    config_str new_parsed=realloc(parsed,(*size+1)*sizeof(char*));
    new_parsed[(*size)]=yon_char_new(string);
    (*size)++;
    return new_parsed;
}

/**yon_ubl_check_root()
 * [EN]
 * 
 * [RU]
 * Возвращает 1 если приложение было запущено от root
*/
int yon_ubl_check_root(){
    if (getuid()==0) return 1;
    else return 0;
}

/**yon_ubl_root_user_get()
 * [EN]
 * 
 * [RU]
 * Возвращает имя пользователя.
 * Если пользователь запустил приложение через root, выводится имя пользователя, запустившего приложение через root 
*/
char *yon_ubl_root_user_get(){
    char *user=NULL;
    if (yon_ubl_check_root()){
        user=getenv("SUDO_USER");
        if (user&&strcmp(user,"")!=0){
            return user;
        }else {
            FILE *file = popen("getent passwd $PKEXEC_UID | cut -d: -f1","r");
            user=g_malloc0(4096);
            fgets(user,4096,file);
            user=yon_char_divide_search(user,"\n",-1);
            if (user) return user;
        }
    }
    return getlogin();
}

char *yon_ubl_user_get_home_directory(){
    FILE *path = popen(get_home_dir_command,"r");
    char *ret = g_malloc(4096);
    fgets(ret,4096,path);
    ret=yon_char_divide_search(ret,"\n",-1);
    return ret;
}

// parsing functions


apps *yon_apps_scan_and_parse_desktops(int *sizef)
{
    int size = 0;
    struct apps *applist;
    {
        DIR *directory = opendir(DesktopPath);
        struct dirent *de;
        while ((de = readdir(directory)))
        {
            FILE *file;
            char *path = yon_char_append(DesktopPath, de->d_name);
            file = fopen(path, "r");
            if (strlen(de->d_name) > 9)
            {
                char *extension = strstr(path, ".");
                if (extension != NULL)
                {
                    if (strcmp(extension, ".desktop") == 0)
                    {
                        apps tempapp;
                        GKeyFile *gfile = g_key_file_new();
                        GError *err = NULL;
                        g_key_file_load_from_file(gfile, path, G_KEY_FILE_KEEP_TRANSLATIONS, NULL);
                        char *Type = g_key_file_get_string(gfile, "Desktop Entry", "Type", &err);
                        if (err)
                        {
                            printf("%s\n", err->message);
                        }
                        if (strcmp(Type, "Application") == 0)
                            tempapp.Type = 1;
                        else if (strcmp(Type, "pyApplication") == 0)
                            tempapp.Type = 2;
                        else
                            continue;
                        tempapp.Name = g_key_file_get_locale_string(gfile, "Desktop Entry", "Name", setlocale(LC_ALL, NULL), NULL);
                        if (tempapp.Name == NULL)
                            continue;
                        tempapp.Categories = g_key_file_get_string(gfile, "Desktop Entry", "Categories", NULL);
                        if (tempapp.Categories == NULL)
                            continue;
                        tempapp.Exec = g_key_file_get_string(gfile, "Desktop Entry", "Exec", NULL);
                        if (tempapp.Exec == NULL)
                            continue;
                        tempapp.Icon = g_key_file_get_string(gfile, "Desktop Entry", "Icon", NULL);
                        if (tempapp.Icon == NULL)
                            continue;
                        tempapp.Pluggable = g_key_file_get_boolean(gfile, "Desktop Entry", "Pluggable", NULL);
                        if (!tempapp.Pluggable)
                            tempapp.Pluggable = g_key_file_get_boolean(gfile, "Desktop Entry", "X-XfcePluggable", NULL);
                        if (tempapp.Pluggable)
                            tempapp.DualPluggable = g_key_file_get_boolean(gfile, "Desktop Entry", "X-UBLPluggable", NULL);
                        if (g_key_file_get_boolean(gfile, "Desktop Entry", "X-UBL-SettingsManager-Hidden", NULL) == 0)
                            if (size == 0)
                            {
                                applist = (apps *)malloc(size + 1 * sizeof(apps));
                                applist[0].Name = yon_char_new(tempapp.Name);
                                applist[0].Categories = yon_char_new(tempapp.Categories);
                                applist[0].Exec = yon_char_new(tempapp.Exec);
                                applist[0].Icon = yon_char_new(tempapp.Icon);
                                applist[0].Type = tempapp.Type;
                                applist[0].Pluggable = tempapp.Pluggable;
                                applist[0].DualPluggable = tempapp.DualPluggable;
                                size++;
                            }
                            else
                            {
                                applist = (apps *)realloc(applist, (size + 1) * sizeof(apps));
                                applist[size].Name = yon_char_new(tempapp.Name);
                                applist[size].Categories = yon_char_new(tempapp.Categories);
                                applist[size].Exec = yon_char_new(tempapp.Exec);
                                applist[size].Icon = yon_char_new(tempapp.Icon);
                                applist[size].Pluggable = tempapp.Pluggable;
                                applist[size].DualPluggable = tempapp.DualPluggable;
                                applist[size].Type = tempapp.Type;
                                size++;
                            }
                    }
                }
            }
        }
    }
    *sizef = size;
    return applist;
};

void yon_apps_sort(apps *applist, int size)
{
    apps tmp;
    if (size > 2)
    {
        for (int i = 1; i < size; i++)
        {
            for (int j = 1; j < size; j++)
            {
                if (strcmp(applist[j].Name, applist[j - 1].Name) < 0)
                {
                    tmp = applist[j];
                    applist[j] = applist[j - 1];
                    applist[j - 1] = tmp;
                };
            }
        };
    }
};

apps *yon_apps_get_by_name(apps *applist, char *name, int size)
{
    for (int i = 0; i < size; i++)
    {
        if (strcmp(applist[i].Name, name) == 0)
            return &applist[i];
    }
    return NULL;
};

//config functions

/**yon_config_load_register(char *command)
 * [EN]
 * 
 * [RU]
 * Выполняет команду [command].
 * Полученные данные парсятся и регистрируются в конфиг.
*/
int yon_config_load_register(char *command){
    if (__yon__config__strings){
        __yon__config__strings = yon_dictionary_free_all(__yon__config__strings,NULL);
    }
    FILE *output = popen(command, "r");
    char **output_strings = NULL;
    output_strings = malloc(sizeof(char));
    int i = 0;
    char str[4096];
    memset(str, 0, 4096);
    while (fgets(str, 4096, output))
    {
        if (strcmp(str, "") != 0&& strcmp(str,"(null)\n")!=0)
        {
            char *key = yon_char_divide_search(str,"=",-1);
            yon_dictionary_add_or_create_if_exists_with_data(__yon__config__strings,key,str);
            __yon__config__strings->data_type=DICTIONARY_CHAR_TYPE;
        }
    }
    check_config
        return 0;
    else return 1;
}

/**yon_config_remove_by_key(char *key)
 * [EN]
 * 
 * [RU]
 * Удаляет параметр конфига по ключу [key]
*/
int yon_config_remove_by_key(char *key){
    check_config{
        dictionary *dict = yon_dictionary_get(&__yon__config__strings,key);
        if (dict){
            yon_dictionary_rip(dict);
            return 1;
        }else return 0;
    }
    return 0;
}

/**yon_config_remove_by_data(void *data)
 * [EN]
 * 
 * [RU]
 * Производит поиск по конфигу на наличие параметра со значением [data] и удаляет найденное значение из конфига. 
*/
int yon_config_remove_by_data(void *data){
    check_config{
        dictionary *dict = NULL;
        for_dictionaries(dict,__yon__config__strings){
            if (dict->data==data){
                yon_dictionary_rip(dict);
                return 1;
            }
        }
        return 0;
    }
    return 0;
}

/**yon_config_remove_element(char *key, char *deleted)
 * [EN]
 * 
 * [RU]
 * Удаляет элемент [deleted] из массива параметров с ключом [key] 
*/
int yon_config_remove_element(char *key, char *deleted){
    check_config{
        dictionary *dict = yon_dictionary_get(&__yon__config__strings,key);
        char *data = (char*)dict->data;
        char *found = strstr(data,deleted);
        int size=strlen(data)-strlen(found)+1;
        char *new_data = malloc(size);
        memset(new_data,0,size);
        if (strlen(found)!=strlen(deleted)){
        memcpy(new_data,data,size-1);
        new_data = yon_char_append(new_data,found+strlen(deleted)+1);
        } else {
        memcpy(new_data,data,size-2);
        new_data = yon_char_append(new_data,found+strlen(deleted));
        }
        dict->data=(void*)(new_data);
        free(data);
        dict->flag1=1;
        return 1;
    } else return 0;
}

/**yon_config_get_by_key(char *key)
 * [EN]
 * 
 * [RU]
 * Возвращает значение параметра конфига с ключом [key]
*/
void *yon_config_get_by_key(char *key){
    check_config{
        dictionary *dict = NULL;
        for_dictionaries(dict, __yon__config__strings){
            if (strcmp(dict->key,key)==0){
                return dict->data;
            }
        }
    }
    return NULL;
}

/**yon_config_get_key_by_data(char *data)
 * [EN]
 * 
 * [RU]
 * Возвращает ключ параметра конфига со значением [data].
 * Если параметр с таким значением не найден, возвращается NULL
*/
char *yon_config_get_key_by_data(char *data){
    check_config{
        dictionary *dict = NULL;
        for_dictionaries(dict, __yon__config__strings){
            if (strcmp(((char*)dict->data),data)==0){
                return dict->key;
            }
        }
    }
    return NULL;
}

/**yon_config_set(char *key, void *data)
 * [EN]
 * 
 * [RU]
 * Производит поиск по конфигу и заменяет значение параметра с ключом [key] на новое значение [data];
*/
int yon_config_set(char *key, void *data){
    check_config{
    dictionary *dict = yon_dictionary_get(&__yon__config__strings,key);
    dict->data=data;
    return 1;
    } else return 0;
}

/**yon_config_clean()
 * [EN]
 * Erase all parameters from config;
 * [RU]
 * Удаляет все параметры из конфига;
*/
int yon_config_clean(){
    check_config{
        __yon__config__strings = yon_dictionary_free_all(__yon__config__strings, NULL);
        return 1;
    }
    else return 0;
}

/**yon_config_register(char *key, void *data)
 * [EN]
 * 
 * [RU]
 * Регистрирует новый параметр конфига.
 * [key] - ключ параметра;
 * [data] - значение параметра;
*/
void yon_config_register(char *key, void *data){
    yon_dictionary_add_or_create_if_exists_with_data(__yon__config__strings,key,data);
    __yon__config__strings->data_type=DICTIONARY_CHAR_TYPE;
}

/**yon_config_load(char *command, int *str_len)
 * [EN]
 * 
 * [RU]
 * Выполняет команду [command] и возвращает распаршеный результат выполнения команды.
 * В [str_len] возвращается длина возвращаемого массива
*/
config_str yon_config_load(char *command, int *str_len){
    FILE *output = popen(command, "r");
    char **output_strings = NULL;
    output_strings = malloc(sizeof(char));
    int i = 0;
    char str[4096];
    memset(str, 0, 4096);
    while (fgets(str, 4096, output))
    {
        if (strcmp(str, "") != 0)
        {
            output_strings = realloc(output_strings, sizeof(char *) * (i + 1));
            // printf("%s\n", str);
            output_strings[i] = NULL;
            output_strings[i] = yon_char_new(str);
            memset(str, 0, 4096);
            i++;
        }
    }
    if (i>0){
    *str_len = i;
    return output_strings;
    } else{
        *str_len=-1;
        return NULL;
    }
}

/**int yon_config_save(char *command)
 * [EN]
 * Saves config with [command]
 * [RU]
 * Выполняет команду [command], добавляя в конец все записи конфига в таком виде:
 * [ПАРАМЕТР1]="[значения1]" [ПАРАМЕТР2]="[значения2]"
*/
int yon_config_save_registered(char *command){
    check_config{
        dictionary *dict = NULL;
        for_dictionaries(dict,__yon__config__strings){
            command = yon_char_unite(command, " ", yon_dictionary_get_data(dict,char*), NULL);
        }
        if (popen(command, "r")) return 1;
        else return 0;
    } else return 0;
}

/**yon_config_get_all(int *size)
 * [EN]
 * 
 * [RU]
 * Возвращает массив со всеми параметрами конфига, оканчивающаяся NULL
 * [size] - указатель, в который выгружается длина массива
*/
config_str yon_config_get_all(int *size){
    check_config{
        *size = 1;
        config_str conf = NULL; 
        dictionary *dict = NULL;
        for_dictionaries(dict,__yon__config__strings){
            conf = yon_remalloc(conf,sizeof(char*)*(*size));
            conf[(*size)-1] = yon_char_unite(dict->key,"=",(char*)dict->data,NULL);
            size++;
        }
        conf = yon_remalloc(conf,sizeof(char*)*(*size+1));
        conf[*size] = NULL;
        return conf;
    } else return NULL;
}

/**char *yon_config_get_parameter(config parameters, int size, char *param)
 * [EN]
 * Gets parameter [param] from parameter list [parameters] of size [size];
 * or NULL if nothing were found
 * [RU] 
 * Возвращает параметр [param] из массива строк [parameters] размером [size]
 * или NULL если такой не был найден
*/
char *yon_config_get_parameter(config_str parameters, int size, char *param)
{
    if (param[0]==' ')
        yon_char_divide_search(param," ",-1);
    param=yon_char_divide_search(yon_char_new(param)," ",-1);
    
    char *str = NULL;
    for (int j = 0; j < size; j++)
    {
        char *name = yon_char_divide_search(yon_char_new(parameters[j]), "=", 1);
        if (name)
        {
            if (strcmp(name, param) == 0)
            {
                str = yon_char_divide_search(yon_char_new(parameters[j]), "\n", 1);
                if (strcmp(str, "") != 0 && strcmp(str, "(null)") != 0)
                    return str;
                else
                    return NULL;
            }
        }
    }
    return NULL;
}



// terminal-using functions

/**yon_launch_app_with_arguments(char *name, char *args)
 * [EN]
 * Execute [command] in separate thread;
 * [RU]
 * Выполнить команду [command] в отдельном потоке;
*/
int yon_launch_app_with_arguments(char *name, char *args)
{
    char *path = yon_char_unite("/usr/bin/", name, " ", args,NULL);
    pthread_t thread_id;
    char *command = NULL;
    command = path;
    pthread_create(&thread_id, NULL, (void *)yon_launch, command);
};

/**yon_launch(char *command)
 * [EN]
 * Execute command [command]
 * [RU]
 * Выполнить команду [command]
*/
void yon_launch(char *command)
{
    system(command);
}

// Gtk functions


#ifdef __GTK_H__


static render_data render;

#ifdef VTE_TERMINAL

static void child_ready(VteTerminal *terminal, GPid pid, GError *error, gpointer user_data)
{
    if (!terminal) return;
    if (pid == -1) printf("Error\n\n\n");
    else vte_terminal_feed_child(VTE_TERMINAL(terminal),(char*)user_data,strlen((char*)user_data));
}

/**
 * void yon_terminal_integrated_launch(GtkWidget *place_to_show, void *endwork_function, void* endwork_function_argument)
 * [EN]
 * launches terminal with specific [command],
 * terminal is shown in [place_to_show] container,
 * after terminal done its work [endwork_function] is called with [endwork_function_argument] argument.
 * [RU]
 * Запускает терминал с командой [command],
 * терминал добавляется в контейнер [place_to_show] виджета,
 * после завершения работы терминала вызывается функция [endwork_function] с аргументом [endwork_function_argument].
*/
void yon_terminal_integrated_launch(GtkWidget *place_to_show, char* command, void *endwork_function, void* endwork_function_argument){
    char **commands=new_arr(char*,2);
    gchar **envp = g_get_environ();
    commands[0]=(gchar *)g_strdup(g_environ_getenv(envp, "SHELL"));
    commands[1]=NULL;
    char **env=new_arr(char*,2);
    env[0]="";
    env[1]=NULL;
    GtkWidget *terminal = vte_terminal_new();
    vte_terminal_set_size(VTE_TERMINAL(terminal),10,15);
    VtePty *pty = vte_pty_new_sync(VTE_PTY_DEFAULT,NULL,NULL);
    vte_terminal_set_pty(VTE_TERMINAL(terminal),pty);
    gtk_container_add(GTK_CONTAINER(place_to_show),terminal);
    char *install_command=yon_char_unite("tput cup 0 0 && tput ed; ",command,"  ; sleep 5;exit 0","\n",NULL); 
    printf("%s\n",install_command);
    if(endwork_function)
        g_signal_connect(G_OBJECT(terminal), "child-exited", G_CALLBACK(endwork_function), endwork_function_argument);
     vte_terminal_spawn_async(VTE_TERMINAL(terminal),
        VTE_PTY_DEFAULT,
        NULL,   
        commands,   
        NULL,  
        0,      
        NULL, NULL,
        NULL,   
        -1, 
        NULL, 
        child_ready,    
        install_command); 
    vte_pty_spawn_async(pty,
        NULL,        
        commands,      
        NULL,         
        0,            
        NULL, NULL,   
        NULL,         
        -1,           
        NULL,         
        NULL,           
        NULL);        
        vte_terminal_set_scrollback_lines(VTE_TERMINAL(terminal), -1);
        vte_terminal_set_scroll_on_output(VTE_TERMINAL(terminal), TRUE);
        vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL(terminal), TRUE);
        gtk_widget_show_all(terminal);
    }

/**yon_terminal_integrated_start(GtkWidget *terminal, char* command, void *endwork_function, void* endwork_function_argument)
 * [EN]
 * launches terminal with specific [command],
 * terminal is shown in [place_to_show] container,
 * after terminal done its work [endwork_function] is called with [endwork_function_argument] argument.
 * [RU]
 * Запускает терминал с командой [command],
 * терминал добавляется в контейнер [place_to_show] виджета,
 * после завершения работы терминала вызывается функция [endwork_function] с аргументом [endwork_function_argument].
*/
void yon_terminal_integrated_start(GtkWidget *terminal, char* command, void *endwork_function, void* endwork_function_argument){
    char **commands=new_arr(char*,2);
    gchar **envp = g_get_environ();
    commands[0]=(gchar *)g_strdup(g_environ_getenv(envp, "SHELL"));
    commands[1]=NULL;
    char **env=new_arr(char*,2);
    env[0]="";
    env[1]=NULL;
    vte_terminal_set_size(VTE_TERMINAL(terminal),10,15);
    VtePty *pty = vte_pty_new_sync(VTE_PTY_DEFAULT,NULL,NULL);
    vte_terminal_set_pty(VTE_TERMINAL(terminal),pty);
    char *install_command=yon_char_unite("tput cup 0 0 && tput ed; ",command,"  ; sleep 5;exit 0","\n",NULL); 
    if(endwork_function)
        g_signal_connect(G_OBJECT(terminal), "child-exited", G_CALLBACK(endwork_function), endwork_function_argument);
     vte_terminal_spawn_async(VTE_TERMINAL(terminal),
        VTE_PTY_DEFAULT,
        NULL,   
        commands,   
        NULL,  
        0,      
        NULL, NULL,
        NULL,   
        -1, 
        NULL, 
        child_ready,    
        install_command); 
    vte_pty_spawn_async(pty,
        NULL,        
        commands,      
        NULL,         
        0,            
        NULL, NULL,   
        NULL,         
        -1,           
        NULL,         
        NULL,           
        NULL);        
        vte_terminal_set_scrollback_lines(VTE_TERMINAL(terminal), 100);
        vte_terminal_set_scroll_on_output(VTE_TERMINAL(terminal), TRUE);
        vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL(terminal), TRUE);
        gtk_widget_show_all(terminal);
    }
#endif

    // Window config functions

    #define check_window_config_setup if(__yon_window_config_target_window)

    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(){
            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.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;
            }
        }
        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);
        }
        g_key_file_save_to_file(__yon_window_config_file,__yon_window_config_path,NULL);
    }

    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); 
    }

    /**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{
            yon_get_is_fullscreen();
            yon_window_config_save();
        }
        gtk_main_quit();
    }

    void __yon_window_config_on_resize(){
        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); 
        }
    }

    /**yon_window_config_setup(GtkWindow *window)
     * [EN]
     * 
     * [RU]
     * Устанавливает указатель на окно для отслеживания его положения и размера
    */
    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 *data){
        g_usleep(G_USEC_PER_SEC/10);
        if(__yon_main_window_config.fullscreen ==1) gtk_window_maximize(__yon_window_config_target_window);
    }
    
    /**yon_window_config_load(char *path)
     * [EN]
     * 
     * [RU]
     * Загружает конфиг окна и инициализирует отслеживание его параметров
    */
    int yon_window_config_load(char *path){
        __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;
            config_str conf = yon_char_parse(yon_char_new(__yon_window_config_path),&size,"/");
            char *path = yon_char_unite(conf[0],"/",conf[1],"/",conf[2],"/",conf[3],"/",conf[4],"/",NULL);
            if (stat(path, &st) == -1) {
                mkdir(path, 0777);
            }
            FILE *fp;
            fp=fopen(__yon_window_config_path,"w");
            fclose(fp);
            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:
                    g_value_set_int(val,g_key_file_get_integer(__yon_window_config_file,"window",param->parameter_name, NULL));
                    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==0) __yon_main_window_config.width=800;
        if (__yon_main_window_config.height==0) __yon_main_window_config.height=600;
        gtk_window_resize(__yon_window_config_target_window,__yon_main_window_config.width,__yon_main_window_config.height);
        gtk_window_move(__yon_window_config_target_window,__yon_main_window_config.x,__yon_main_window_config.y);
        pthread_t tid;
        pthread_create(&tid,NULL,(void *)_yon_maximize,NULL);
        return 1;
    }

    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){
        config_str key = g_key_file_get_keys(__yon_window_config_file,section,size,NULL);
        return key;
    }

    /**yon_window_config_add_listener(GtkWidget *widget, char *param_name, char *widget_property, enum YON_TYPE val_type)
     * [EN]
     * 
     * [RU]
     * Добавляет параметр виджета [widget] по названию [widget_property] для отслеживания и сохраняет его в конфиг под ключом [param_name].
    */
    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);
    }

    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);
    }

    int yon_window_config_get_parameter(char *section, char *config_parameter, void *return_value, enum YON_TYPE type){
        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;
        }
    }

GtkWidget *yon_ubl_menu_item_about_new(char *buttonname){
    GtkWidget *menu_item = gtk_menu_item_new();
    gtk_style_context_add_class(gtk_widget_get_style_context(menu_item),"menuitembottom");
    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0);
    GtkWidget *label = gtk_label_new(buttonname);
    GtkWidget *image = gtk_image_new_from_icon_name("dialog-information-symbolic",GTK_ICON_SIZE_BUTTON);
    gtk_label_set_xalign(GTK_LABEL(label),0.0);
    gtk_box_pack_start(GTK_BOX(box),image,0,0,5);
    gtk_box_pack_start(GTK_BOX(box),label,0,0,5);
    gtk_container_add(GTK_CONTAINER(menu_item),box);
    gtk_widget_show_all(menu_item);
    return menu_item;
}

GtkWidget *yon_ubl_menu_item_documentation_new(char *buttonname){
    GtkWidget *menu_item = gtk_menu_item_new();
    gtk_style_context_add_class(gtk_widget_get_style_context(menu_item),"menuitemtop");
    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,0);
    GtkWidget *label = gtk_label_new(buttonname);
    GtkWidget *image = gtk_image_new_from_icon_name("dialog-question-symbolic",GTK_ICON_SIZE_BUTTON);
    gtk_label_set_xalign(GTK_LABEL(label),0.0);
    gtk_box_pack_start(GTK_BOX(box),image,0,0,5);
    gtk_box_pack_start(GTK_BOX(box),label,0,0,5);
    gtk_container_add(GTK_CONTAINER(menu_item),box);
    gtk_widget_show_all(menu_item);
    return menu_item;
}


// other Gtk functions

/**yon_gtk_combo_box_text_fill(GtkWidget *combo, config_str parameters,int size)
 * [EN]
 * 
 * [RU]
 * Добавляет в Комбобокс [combo] все строки из массива строк [parameters] размера [size]
*/
int yon_gtk_combo_box_text_fill(GtkWidget *combo, config_str parameters,int size){
    if (combo&&parameters){
        for (int i=0;i<size;i++){
            gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo),parameters[i]);
        }
        return 1;
    } else
    return 0;
}

/**yon_gtk_combo_box_text_find(GtkWidget *combo_box, char *text_to_find)
 * [EN]
 * 
 * [RU]
 * Проивзодит поиск по GtkComboBoxText [combo_box]
 * возвращает 1 если элемент [text_to_find] найден, иначе возвращает 0 
*/
int yon_gtk_combo_box_text_find(GtkWidget *combo_box, char *text_to_find){
    if (combo_box&&text_to_find){
        int active=gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
        char *str="-1";
        for (int i=0;strcmp(str,"")!=0;i++){
            gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box),i);
            str=gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box));
            if (!str) return -1;
            if (strstr(str,text_to_find)) return i;
        }
    } return -1;
}

void yon_gtk_column_minimal_fixed_size_set(GtkTreeViewColumn *column){
    int width= gtk_tree_view_column_get_width(column);
    gtk_tree_view_column_set_min_width(column,width);
}

/**yon_dictionary_gtk_pack_start_multiple_widgets(GtkBox *destination, gboolean expand, gboolean fill, int padding, ...)
 * [EN]
 * 
 * [RU]
 * Добвляет [destination] все виджеты, прописанные после [padding]. Добавление происходит с начала контейнера.
 * [expand] - расширяемость выделенного для виджетов места
 * [fill] - заполнять ли виджетом всё ему выделенное место 
 * [padding] - отступ од других элементов
*/
int yon_dictionary_gtk_pack_start_multiple_widgets(GtkBox *destination, gboolean expand, gboolean fill, int padding, ...){
        va_list args;
        va_start(args,padding);
        GtkWidget *widget = va_arg(args,GtkWidget*);
        while (widget){
            gtk_box_pack_start(GTK_BOX(destination), widget, expand, fill, padding);
        }
        va_end(args);
    return 1;
}

/**yon_dictionary_gtk_pack_end_multiple_widgets(GtkBox *destination, gboolean expand, gboolean fill, int padding, ...)
 * [EN]
 * 
 * [RU]
 * Добвляет в [destination] все виджеты, прописанные после [padding]. Добавление происходит с конца контейнера.
 * [expand] - расширяемость выделенного для виджетов места
 * [fill] - заполнять ли виджетом всё ему выделенное место 
 * [padding] - отступ од других элементов
*/
int yon_dictionary_gtk_pack_end_multiple_widgets(GtkBox *destination, gboolean expand, gboolean fill, int padding, ...){
        va_list args;
        va_start(args,padding);
        GtkWidget *widget = va_arg(args,GtkWidget*);
        while (widget){
            gtk_box_pack_end(GTK_BOX(destination), widget, expand, fill, padding);
        }
        va_end(args);
    return 1;
}


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);
}

void _yon_ubl_header_setup_resource(GtkWidget *Overlay, GtkWidget *Head, GtkWidget *Image, char *image_path)
{
    gtk_overlay_add_overlay(GTK_OVERLAY(Overlay), Head);
    gtk_image_set_from_resource(GTK_IMAGE(Image), image_path);
}

int yon_ubl_status_box_setup(GtkWidget *icon, GtkWidget *box, GtkWidget *label)
{
    if(icon&&box&&label){
        render.icon=icon;
        render.box=box;
        render.label=label;
        return 1;
    } else return 0;
} 

void _yon_ubl_status_box_render(char *text, BACKGROUND_IMAGE_TYPE type)
{
    render_data data = render;
    GtkIconTheme *ictheme = gtk_icon_theme_get_default();
    GError *err = NULL;
    if (err)
    {
        printf("%s\n", err->message);
        g_error_free(err);
    }
    if (type == BACKGROUND_IMAGE_SUCCESS_TYPE||! type)
    {
        gtk_style_context_remove_class(gtk_widget_get_style_context(data.box), "boxInfoMessError");
        gtk_style_context_add_class(gtk_widget_get_style_context(data.box), "boxInfoMessOK");
        gtk_image_set_from_pixbuf(GTK_IMAGE(data.icon), gtk_icon_theme_load_icon_for_scale(ictheme, "com.ublinux.ubl-settings-video.checked", 25, 1, GTK_ICON_LOOKUP_FORCE_SIZE, &err));
    }
    else if (type == BACKGROUND_IMAGE_FAIL_TYPE)
    {
        gtk_style_context_remove_class(gtk_widget_get_style_context(data.box), "boxInfoMessOK");
        gtk_style_context_add_class(gtk_widget_get_style_context(data.box), "boxInfoMessError");
        gtk_image_set_from_pixbuf(GTK_IMAGE(data.icon), gtk_icon_theme_load_icon_for_scale(ictheme, "com.ublinux.ubl-settings-video.warning", 25, 1, GTK_ICON_LOOKUP_FORCE_SIZE, &err));
    }
    if (text)
        gtk_label_set_text(GTK_LABEL(data.label), text);
}

void yon_ubl_status_box_render(char *text, BACKGROUND_IMAGE_TYPE type){
    _yon_ubl_status_box_render(text,type);
}

/**yon_ubl_setup_sockets(GtkWidget *main_window, GtkWidget *left_window, GtkWidget *right_window, int socket_main_id, int socket_left_id, int socket_right_id)
 * [EN]
 * Set up plugs for using with GtkSockets insine ubl-settings-manager.
 * [main_window] is container widget, which holds main application functionality.
 * [left_window] is container widget, which holds widgets, have to be shown at left part of ubl-settings-manager header.
 * [right_window] is container widget, which holds widgets, have to be shown at right part of ubl-settings-manager header.
 * [socket_main_id] is id of socket for [main_window].
 * [socket_left_id] is id of socket for [left_window].
 * [socket_right_id] is id of socket for [right_window].
 * [RU]
 * Настраивает плаги для работы с сокетами в утилите ubl-settings-manager.
 * [main_window] - контейнер основного интерфейса приложения.
 * [left_window] - контейнер для виджетов которые должны отображаться в левой части шапки ubl-settings-manager.
 * [right_window] - контейнер для виджетов которые должны отображаться в правой части шапки ubl-settings-manager.
 * [socket_main_id] - id сокета для [main_window].
 * [socket_left_id] - id сокета для [left_window].
 * [socket_right_id] - id сокета для [right_window].
*/
void yon_ubl_setup_sockets(GtkWidget *main_window, GtkWidget *left_window, GtkWidget *right_window, int socket_main_id, int socket_left_id, int socket_right_id){
    if (main_window&&socket_main_id>-1){
        gtk_widget_hide(gtk_widget_get_toplevel(main_window));
        GtkWidget *plug_main=gtk_plug_new(socket_main_id);
        GtkWidget *plug_left=NULL;
        GtkWidget *plug_right=NULL;
        GtkWidget *box=NULL;
        g_signal_connect(G_OBJECT(plug_main), "destroy", G_CALLBACK(gtk_main_quit),NULL);
        if (socket_left_id>-1&&left_window){
            plug_left=gtk_plug_new(socket_left_id);
            g_object_ref(left_window);
            gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(left_window)),left_window);
            gtk_container_add(GTK_CONTAINER(plug_left),left_window);
        gtk_style_context_add_class(gtk_widget_get_style_context(plug_left),"primary-toolbar");
        gtk_style_context_add_class(gtk_widget_get_style_context(left_window),"button");
        gtk_style_context_add_class(gtk_widget_get_style_context(left_window),"opacited");
        gtk_style_context_add_class(gtk_widget_get_style_context(left_window),"color");
        gtk_style_context_add_class(gtk_widget_get_style_context(plug_left),"noborder");
            gtk_widget_show(plug_left);
        }
        else if (left_window){
            if (box==NULL){
                box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5);
                gtk_box_pack_start(GTK_BOX(main_window),box,0,0,5);
                gtk_box_reorder_child(GTK_BOX(main_window),box,0);
                gtk_widget_show(box);
            }
            gtk_style_context_add_class(gtk_widget_get_style_context(left_window),"inherited");
            gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(left_window)),left_window);
            gtk_box_pack_end(GTK_BOX(box),left_window,0,0,5);
        }
        if (socket_right_id>-1&&right_window){
            plug_right=gtk_plug_new(socket_right_id);
            g_object_ref(right_window);
            gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(right_window)),right_window);
            gtk_container_add(GTK_CONTAINER(plug_right),right_window);
        gtk_style_context_add_class(gtk_widget_get_style_context(plug_right),"primary-toolbar");
        gtk_style_context_add_class(gtk_widget_get_style_context(right_window),"button");
        gtk_style_context_add_class(gtk_widget_get_style_context(right_window),"opacited");
        gtk_style_context_add_class(gtk_widget_get_style_context(right_window),"color");
        gtk_style_context_add_class(gtk_widget_get_style_context(plug_right),"noborder");
            gtk_widget_show(plug_right);
        }
        else if (right_window){
            if (box==NULL){
                box=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5);
                gtk_box_pack_start(GTK_BOX(main_window),box,0,0,5);
                gtk_box_reorder_child(GTK_BOX(main_window),box,0);
                gtk_widget_show(box);
            }
            gtk_style_context_add_class(gtk_widget_get_style_context(right_window),"inherited");
            gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(right_window)),right_window);
            gtk_box_pack_start(GTK_BOX(box),right_window,0,0,5);
        }
        g_object_ref(main_window);
        gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(main_window)),main_window);
        gtk_container_add(GTK_CONTAINER(plug_main),main_window);
        gtk_widget_show(plug_main);
    }
}

#ifdef WEBKIT_FOUND

/**yon_ubl_browser_window_open(char *link, char *browser_window_name)
 * [EN]
 * Launches integrated browser window, named [browser_window_name] at header with [link].
 * [RU]
 * Открывает встроенный браузер с именем [browser_window_name] и показываемой страницей по ссылке [link]
*/
void yon_ubl_browser_window_open(char *link, char *browser_window_name){
    GtkWidget *browser=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    GtkWidget *web_place=gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
    GtkWidget *header=gtk_header_bar_new();
    GtkWidget *header_label=gtk_label_new(browser_window_name);
    GtkWidget *WebView=webkit_web_view_new();
    gtk_container_add(GTK_CONTAINER(browser),web_place);
    gtk_window_set_titlebar(GTK_WINDOW(browser),header);
    gtk_window_set_title(GTK_WINDOW(browser),browser_window_name);
    gtk_widget_set_size_request(browser,800,600);
    gtk_header_bar_set_custom_title(GTK_HEADER_BAR(header),header_label);
    gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(header),1);
    webkit_web_view_load_uri(WEBKIT_WEB_VIEW(WebView),link);
    gtk_box_pack_start(GTK_BOX(web_place),WebView,1,1,0);
    gtk_widget_show_all(browser);
}
#else

/**yon_ubl_browser_window_open(char *link, char *browser_window_name)
 * [EN]
 * Launches browser with [link].
 * [browser_window_name] is't used. It's needed for compatibility with webkit version of that function.
 * [RU]
 * Открывает браузер со страницей по ссылке [link]
 * [browser_window_name] не используется. Нужна для совместимости с webkit версией этой функции.
*/
void yon_ubl_browser_window_open(char *link,  char *browser_window_name){
        char *user=getenv("SUDO_USER");
        if (!user)
            user=getlogin();
        char *command=yon_char_unite("sudo -u ",user," xdg-open ", link,NULL);
        yon_launch_app(command);
}
#endif

#endif
