#ifndef UBL_UTILS
#define UBL_UTILS
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <locale.h>
#include <time.h>
#include <sys/select.h>
#include <fcntl.h>

#define DesktopPath "/usr/share/applications/"

/**
 * @brief Works like for, but is used to enumerate dictionary elements.
 * 
 * Работает как for, но нужен для перечисления элементов словаря.
 * 
 * @param iterator Type: dictionary*
 * 
 * dictionary element iterator.
 * @param stack Type: dictinoary*
 * 
 * dictionary pointer.
 */
#define for_dictionaries(iterator, stack) for (iterator = stack->first; iterator != NULL; iterator = iterator->next)

#define new(type) malloc(sizeof(type))
#define new_arr(type,size) malloc(sizeof(type)*size)

#define get_home_dir_command yon_char_unite("getent passwd \"",yon_ubl_root_user_get(),"\" | cut -d: -f6",NULL)

#define yon_va_while(list,type,target) while ((target=va_arg(list,type)))

typedef enum
{
    DICTIONARY_GTK_WIDGETS_TYPE,
    DICTIONARY_OTHER_TYPE=0,
    DICTIONARY_CHAR_TYPE,
    DICTIONARY_INT_TYPE,
    DICTIONARY_BOOL_TYPE,

} DICT_TYPE;

#define dictionary_fields(type_name) char *key;\
    void *data;\
    struct type_name *next;\
    struct type_name *prev;\
    struct type_name *first;\
    DICT_TYPE data_type;

/**
 * @brief Named dictionary structure.
 * 
 * Структура именованого списка.
 * @param key dictionary element key.
 * 
 * Ключ элемента словаря.
 * @param data dictionary element value.
 * 
 * Значение элемента словаря.
 * @param next next dictionary element.
 * 
 * Следующий элемент словаря.
 * @param prev previous dictionary element.
 * 
 * Предыдущий элемент словаря.
 * @param first first dictionary element.
 * 
 * Следующий элемент словаря.
 * @param data_type value type.
 * 
 * Тип значения.
 */
typedef struct dictionary
{
    char *key;
    void *data;
    struct dictionary *next;
    struct dictionary *prev;
    struct dictionary *first;
    DICT_TYPE data_type;
} dictionary;

typedef char** config_str;

/**
 * @brief Get configuration parameter value.
 * 
 * Получение значения параметра конфигурации.
 * @param key Key of configuration parameter.
 * 
 * Ключ параметра конфигурации.
 * @return Type: char*
 * 
 * Value of configuration parameter or NULL.
 * 
 * Значение парамерта конфигурации или NULL.
 */
#define config(key) yon_config_get(key) 

/**
 * @brief Allocates or reallocates memory.
 * 
 * Выделение или перевыделение памяти.
 * @param pointer If NULL, uses malloc(), otherwise uses realloc().
 * 
 * Если NULL, используется malloc(), иначе realloc().
 * @param size Size of memory allocation. 
 * 
 * Размер выделенной памяти.
 * @return Type: void*
 * Newly allocated memory.
 * 
 * Новая выделенная память.
 */
#define yon_remalloc(pointer, size) (!pointer) ? malloc(size) : realloc(pointer, size)


// dictionary functions

/**
 * @brief Gets data from dictionary element.
 * 
 * Получение значения элемента словаря.
 * @param dictionary dictionary element.
 * 
 * Элемент словаря.
 * @param type type of value, dictionary element contains.
 * 
 * Тип значения, содержащегося в элементе словаря.
 * @return Type: void*
 * Value, dictionary element contains.
 * 
 * Значение, которое содержит элемент словаря.
 */
#define yon_dictionary_get_data(dictionary, type) ((type)dictionary->data)

/**
 * @brief Creates new or appends new element to dictionary.
 * 
 * Создаёт новый элемент словаря.
 * 
 * ---
 * 
 * @param dict dictionary*, where new element will be added to.
 * 
 * Словарь в который будет добавлен новый элемент.
 * 
 * ---
 * 
 * @param key char*, new allocated element's key.
 * 
 * Ключ нового элемента.
 * 
 * ---
 * 
 * @param data void*, data of any type.
 * 
 * Данные любого типа
 * 
 */
#define yon_dictionary_add_or_create_if_exists_with_data(dict,key,data) {if (!dict) dict=yon_dictionary_new_with_data(key,data); \
                                                                        else dict=yon_dictionary_append_with_data(dict,key,data);}

/**
 * @brief Creates and returns empty dictionary.
 * 
 * Создаёт и возвращает пустой словарь. 
 * 
 * ---
 * 
 * @return A newly allocated dictionary.
 * 
 * The caller of the method takes ownership of the returned data, and is responsible for freeing it.
 * 
 * Новый выделенный dictionary*.
 * 
 * Вызывающий метод берёт на себя ответственность за возвращаемые данные и отвечает за их освобождение. 
 */
dictionary *yon_dictionary_new();

/**
 * @brief copies dictionary.
 * 
 * Копирует словарь.
 * 
 * ---
 * @param dict dictionary to copy.
 * 
 * словарь для копирования.
 * 
 * ---
 * @return A new allocated dictionary*
 * 
 * The caller of the method takes ownership of the returned data, and is responsible for freeing it.
 * 
 * Новый выделенный dictionary*
 * 
 * Вызывающий метод берёт на себя ответственность за возвращаемые данные и отвечает за их освобождение. 
 */
dictionary *yon_dictinoary_copy(dictionary *dict);

/**
 * @brief Creates a deep copy of the dictionary and returns the first element.
 * 
 * Создаёт полную копию словаря и возвращает первый элемент.
 * 
 * ---
 * @param dict first element of dictionary to copy.
 * 
 * Первый элемент копируемого словаря.
 * 
 * ---
 * @return A new allocated dictionary* 
 * 
 * The caller of the method takes ownership of the returned data, and is responsible for freeing it.
 * 
 * Новый выделенный dictionary*
 * 
 * Вызывающий метод берёт на себя ответственность за возвращаемые данные и отвечает за их освобождение. 
 */
dictionary *yon_dictionary_copy_deep(dictionary *dict);

/**
 * @brief Set a data to dictionary element. 
 * 
 * Установить элементу словаря значение.
 * 
 * ---
 * @param dict dictionary element to set data.
 * 
 * Элемент словаря в который устанавливается новое значение.
 * @param data new value for dictionaty
 * 
 * Новое значение словаря.
 * 
 * ---
 * @return 0 if failed, 1 if succeeded.
 * 
 * 0 при провале, 1 при успехе
 */
int yon_dictionary_set_data(dictionary *dict, void *data);

/**
 * @brief Change dioctionary element's key.
 * 
 * Изменяет ключ элемента словаря.
 * 
 * ---
 * @param dict dictionary element for key change.
 * 
 * Элемент словаря для изменения ключа.
 * @param key 
 * @return 0 if failed, 1 if succeeded.
 * 
 * 0 при провале, 1 при успехе
 */
int yon_dictionary_set_key(dictionary *dict, char *key);

/**
 * @brief Sets dictionary element's key and data 
 * 
 * Устанавливает значение ключа элемента словаря и его данные
 * 
 * ---
 * @param dict dictionary element for change.
 * 
 * Элемент словаря для изменения.
 * @param key new key for dictionary element.
 * 
 * Новый ключ для элемента словаря.
 * @param data new value for dictionary element.
 * 
 * Новое значение элемента словаря.
 * 
 * ---
 * @return 0 if failed, 1 if succeeded.
 * 
 * 0 при провале, 1 при успехе.
 */
int yon_dictionary_set(dictionary *dict, char *key, void *data);

/**
 * @brief Cleans dictionary element.
 * 
 * Очищает элемент словаря.
 * @param dict target dictionary element.
 * 
 * Очищаемый элемент словаря.
 * @return 0 if failed, 1 if succeeded.
 * 
 * 0 при провале, 1 при успехе.
 */
int yon_dictionary_empty(dictionary *dict);

/**
 * @brief Switch dictionary to last element.
 * 
 * Переключает словарь на последний элемент.
 * 
 * ---
 * @param dict Dictionary to pointer.
 * 
 * Указатель на словарь.
 */
void yon_dictionary_switch_to_last(dictionary **dict);

/**
 * @brief Appends dictionary with new element.
 * 
 * Дополнить словарь новым элементом.
 * 
 * ---
 * @param targetdict dictionary to append.
 * 
 * Словарь для дополнения.
 * @return A new allocated dictionary*, element of dictionary.
 * 
 * Новый выделенный dictionary*, элемент словаря. 
 */
dictionary *yon_dictionary_append(dictionary *targetdict);


/**
 * @brief Returns the last element of the dictionary.
 * Unlike yon_dictionary_switch_to_last()
 * the dictionary remains at its previous element.
 * 
 * Возвращает последний элемент словаря.
 * В отличае от yon_dictionary_switch_to_last()
 * словарь остаётся на прежнем элементе.
 * @param dict The dictionary whose last element will be retrieved.
 * 
 * Словарь, последний элемент которого будет получен.
 * @return Type: dictionary*
 * 
 *  The last element of dictionary. 
 */
dictionary *yon_dictionary_get_last(dictionary *dict);

/**
 * @brief iterate dictionary element position.
 * 
 * Меняет элемент словаря местами с другим элементом.
 * @param dict The moving dictionary element.
 * 
 * Перемещаемый элемент словаря.
 * @param aim if <0, element switches with left element;
 * if >0, element switches with right element;
 * 
 * если <0 элемент меняется местами с левым элементом;
 * если >0 элемент меняется местами с правым элементом;
 * @return Type: dictionary*
 * 
 * dictionary element, swapped with current.
 * 
 * Элемент словаря с которым текущий поменялся местами. 
 */
dictionary *yon_dictionary_swap(dictionary *dict, int aim);

/**
 * @brief Sets the first element pointer of the dictionary
 * to the current element. Do not use
 * 
 * Устанавливает указатель первого элемента словаря
 * на текущий элемент. Не использовать
 * @param dict 
 */
void yon_dictionary_make_first(dictionary *dict);

/**
 * @brief Moves dictionary element to new position.
 * 
 * Перемещает элемент словаря на новую позицию.
 * @param dict dictionary element to move.
 * 
 * Перемещаемый элемент словаря.
 * @param nth new position for dictionary element.
 * 
 * новоя позиция для элемента словаря.
 */
void yon_dictionary_make_nth(dictionary *dict, int nth);

/**
 * @brief Create new dictionary element with key and value.
 * 
 * Создать новый элемент словаря с ключом и значением.
 * @param key new dictionary element's key.
 * 
 * Ключ нового элемента словаря.
 * @param data new dictionary element's value.
 * 
 * Значение нового элемента словаря.
 * @return Type: dictionary*
 * 
 * New dictionary element.
 * 
 * Новый элемент словаря.
 */
dictionary *yon_dictionary_new_with_data(char *key, void *data);

/**
 * @brief Create and append dictionary element to dictionary with key and value.
 * 
 * Создать новый элемент словаря, присоединяемый в конец словаря
 * с ключом и значением.
 * @param dict dictionary to append with new element.
 * 
 * Словарь к которому добавляется элемент.
 * @param key new dictionary element's key;
 * 
 * Ключ нового элемента словаря.
 * @param data New dictionary element's value.
 * 
 * Значение нового элемента словаря.
 * @return Type: dictionary*
 * 
 * New allocated dictionary element.
 * 
 *  Новый выделенный элемент словаря.
 */
dictionary *yon_dictionary_append_with_data(dictionary *dict, char *key, void *data);

/**
 * @brief Connect dictionary element to the end of dictionary.
 * 
 * Присоединение элемента словаря в конец словаря.
 * @param target Dictionary to connect element.
 * 
 * Словарь для присоединения элемента.
 * @param append An appendable dictionary element.
 * 
 * Присоединяемый элемент словаря.
 * @return Type: int.
 * 
 * 0 if failed, 1 if success. 
 * 
 * 0 при провале, 1 при успехе.
 */
int yon_dictionary_connect(dictionary *target, dictionary *append);

/**
 * @brief Merge second dictionary into first.
 * 
 * Объединить два словаря в один.
 * @param dict1 Dictionary which other dictionary connects to.
 * 
 * Словарь с которым объединяется другой словарь.
 * @param dict2 Dictionary to connect.
 * 
 * Присоединяемый словарь.
 * @return Type: int
 * 
 * 0 if failed, 1 if success.
 * 
 * 0 при провале, 1 при успехе.
 */
int yon_dictionary_merge(dictionary *dict1,dictionary *dict2);

/**
 * @brief Get dictionary element by key.
 * 
 * Возвращает элемент словаря с ключом.
 * @param dict dictionary link.
 * 
 * Ссылка на словарь.
 * @param key key of requested dictionary element.
 * 
 * Ключ запрашиваемого элемента словаря.
 * @return Type: dictionary*
 * 
 * Dictionary element with requested key or NULL.
 * 
 * "Элемент словаря с разыскиваемым ключом или NULL."
 */
dictionary *yon_dictionary_get(dictionary **dict, char *key);

/**
 * @brief Free dictionary element.
 * 
 * Освобождает элемент словаря.
 * @param dict Dictionary element to free.
 * Освобождаемый элемент списка.
 * @return Type: dictionary*
 * 
 * Closest valid dictionary element.
 * 
 * Ближайший валидный элемент словаря.
 */
dictionary *yon_dictionary_rip(dictionary *dict);

/**
 * @brief Get dictionary element of specific position.
 * 
 * Получить элемент списка на конкретной позиции.
 * @param dict First dictionary element.
 * 
 * Первый элемент словаря.
 * @param place Desired dictionary element position.
 * 
 * Желаемая позиция элемента словаря.
 * @return Type: dictionary* 
 * 
 * Dictionary element on desired position or NULL.
 * 
 * Элемент словаря на желаемой позиции или NULL.
 */
dictionary *yon_dictionary_get_nth(dictionary *dict, int place);

/**
 * @brief Frees memory of dictionary element.
 * 
 * Освобождает память элемента словаря.
 * @param dictionary_to_free 
 * @return Type: void*
 * Value, freed dictionary element was containing.
 * 
 * Значение, которое содержалось в освобождённом словаре.
 */
void *yon_dictionary_free(dictionary *dictionary_to_free);

/**
 * @brief Frees whole dictionary.
 * 
 * Освобождает память для всех элементов словаря.
 * @param dictionary 
 * @param data_manipulation Function, activated, if not NULL, for every dictionary element in dictionary.
 * 
 * Функция, активируемая, если не NULL, для каждого элемента словаря в словаре. 
 */
void yon_dictionary_free_all(dictionary *dictionary,void (data_manipulation)(void*));

// [[ deprecated ]]
// dictionary *yon_dictionary_sort(dictionary *dict);


// [[__warnattr("Function is yon_dictionary_check_loops() is untested")]];
dictionary *yon_dictionary_check_loops(dictionary *target);

// char functions

/**
 * @brief Macros for yon_char_divide_search function to get right part from string, freeing left part.
 * 
 * Макросы для функции yon_char_divide_search для извлечения правой части из строки, освобождая левую часть.
 * @param str string
 * @param find string to find
 * @param delete_divider
 */
#define yon_char_divide_search_self(str,find,delete_divider) {char *temp = str; str = yon_char_divide_search(str,find,delete_divider); free(temp);}

/**
 * @brief check if string is empty.
 * 
 * Проверить пустая ли строка.
 * @param string
 */
#define yon_char_is_empty(string) !(string&&strcmp(string,""))

/**
 * @brief Macros. If string is not empty, returns string, otherwise returns other string.
 * 
 * @param string String to check. If string is empty, returns other string.
 * 
 * @param opposite If main shring is empty, returns this string.
 * 
 */
#define yon_char_return_if_exist(string,opposite) string&&strcmp(string,"")?string:opposite

/**
 * @brief Macros. Removes last string symbol.
 * 
 * Макрос. Удаление последнего символа строки.
 * @param string
 * @param symbol If last string symbol is same, removes it, otherwise does nothing.
 * 
 * Если последний символ строки совпадает, он удаляется, иначе ничего не происходит
 */
#define yon_char_remove_last_symbol(string,symbol) {if (string[strlen(string)-1]==symbol) string[strlen(string)-1]='\0';}

/**
 * @brief Find last symbol in sting.
 * 
 * Найти последний символ в строке.
 * @param find Symbol to find.
 * 
 * Искомый символ.
 * @return Type: int
 * 
 * The location of the last character being searched for.
 * 
 * Местоположение последнего искомого символа.
 */
int yon_char_find_last(char *source, char find);

/**
 * @brief Create new string by combining two strings.
 * 
 * Создать новую строку, состоящую из двух входящих.
 * @param append Appending string.
 * 
 * Присоединяемая строка.
 * @return Type: char* 
 * A new allocated string, containing both input strings.
 * 
 * Новая выделенная строка, состоящая из обеих входящих строк.
 */
char *yon_char_append(const char *source, const char *append);

/**
 * @brief Create new string by appending string with symbol.
 * 
 * Создать новую строку соединением строки и символа
 * @param append Appending symbol.
 * 
 * Прибавляемый символ.
 * @return Type: char*
 * 
 * A new allocated string.
 * 
 * Новая выделенная строка. 
 */
char *yon_char_append_c(const char *source, char append);

/**
 * @brief Append string with another string, inserting another string between
 * 
 * Добавляет к строке другую строку, добавляя между ними разделитель. 
 * @param target Appending string.
 * 
 * Добавляемая строка.
 * @param divider Divider. A string, which divides source string into substrings.
 * 
 * Разделитель. Строка, разделяющая основную строку на подстроки.
 * @return Type: char*
 * 
 * A newly allocated string.
 * 
 * Новая выделенная строка. 
 */
char *yon_char_append_element(char *source,char *target, char *divider);

/// @brief Append string of elements with another string of elements
/// @param source sSource string of elements.
/// @param target Appended string of elements.
/// @param separator String, separating elements within parameter's value
/// @return A newly allocated string of elements
char *yon_char_append_elements(char *source,char *target, char *separator);

char *yon_char_force_append_element(char *source,char *target, char *divider);
/**
 * @brief Remove substring from string.
 * 
 * Удалить подстроку из строки.
 * @param target Substring to remove.
 * 
 * Удаляемая подстрока. 
 * @param divider Divider. Main string divides into substrings to compare.
 * @return Type: char*
 * 
 * A newly allocated string with reniver substing.
 * 
 * Новая выделенная строка с удалённой подстрокой. 
 */
char *yon_char_remove_element(char *source,char *target, char *divider);

/// @brief Remove elements from elements string
/// @param source source elements string
/// @param target string of elements to remove
/// @param separator string, separating elements within parameter's value
/// @return a newly allocated string of elements, or NULL if removed elements was last
char *yon_char_remove_elements(char *source,char *target, char *separator);

/**
 * @brief Copy string.
 * 
 * Копировать строку.
 * @return Type: char* 
 * 
 * A newly allocated string.
 * 
 * Новая выделенная строка.
 */
char *yon_char_new(const char *chr);

/**
 * @brief Unite multiple strings.
 * 
 * Объединить несколько строк.
 * @param source First string to unite.
 * 
 * Первая объединяемая строка.
 * @param ... Multiple strings, edning with NULL.
 * 
 * Произвольное количество строк, заканчивающееся NULL.
 * @return Type: char*
 * 
 * A newly allocated string.
 * 
 * Новая выделенная строка. 
 */
char *yon_char_unite(const char *source, ...);

char *yon_cut(char *source, int size, int startpos);

/// @brief Check if elements string contains string
/// @param source Source element string for search
/// @param element The checked string
/// @param separator String, separating elements within parameter's value
/// @return 
int yon_char_check_element(char *source, char *element, char *separator);

/// @brief Check if elements string contains another elements string
/// @param source_string Source element string for search
/// @param target_string Target element string, which compares with source string
/// @param separator String, separating elements within parameter's value
/// @return 
int yon_char_check_elements(char *source_string, char *target_string, char *separator);

/// @brief Swap 2 substrings.
/// @param source Source string
/// @param a First substring to swap 
/// @param b Second substring to swap
/// @param divider String divider
/// @return Type: char*. String with swapped substrings. The data is owned by the caller of the method.
char *yon_char_swap_element(const char *source, const char *a, const char *b, const char *divider);

/**
 * @brief Check if string begins with substring.
 * 
 * Проверить начинается ли строка с подстроки.
 * @param haystack String to check.
 * 
 * Проверяемая строка.
 * @param needle Substring searched in the beginning of main string.
 * 
 * Подстрока, искомая в начале основной строки.
 * @return Type: boolean
 */
int yon_char_check_begins_with(char *haystack, char *needle);

/**
 * @brief Check if string array has string, beginning with substring.
 * 
 * Проверить есть ли в массиве строк строка, начинающаяся с подстроки.
 * @param target String array to check.
 * 
 * Проверяемый массив строк.
 * @param size Pointer to size of string array.
 * 
 * Указатель на размер массива строк
 * @param compare String to search in string array.
 * 
 * Искомая строка.
 * @return Type: char* 
 * 
 * If substring was found, full string is returned, otherwise, NULL.
 * 
 * Если подстрока была найдена возвращается полная строка, иначе NULL.
 */
char *yon_char_parsed_check_exist_begins_with(char **target, int size, char *compare);

/**
 * @brief Split a string into a given number of lines.
 * 
 * Разделить строку на заданное количество строк.
 * @param line_count Number of lines.
 * 
 * Количество строк.
 * @param final_size Pointer to return the size of the string array.
 * 
 * Указатель для возврата размера массива строк.
 * @return Type: config_str 
 * 
 * Newly allocated string array with splitted input string.
 * 
 * Новый выделенный массив строк с разделённой входной строкой.
 */
config_str yon_char_wrap_to_lines(char *target, unsigned int line_count, unsigned int *final_size);

/**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.
 */

/**
 * @brief Divide a sting at position.
 * 
 * @param source 
 * @param dividepos 
 * @return char* 
 */
char *yon_char_divide(char *source, int dividepos);

/**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);

/**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);

/**yon_char_from_float(int int_to_convert)
 * [EN]
 * converts float to char*.
 * 
 * [RU]
 * Конвертирует float в char*
 */
char *yon_char_from_float(float int_to_convert);

char *yon_char_from_double(double int_to_convert);

/// @brief Convert long to char *
/// @param int_to_convert 
/// @return A newly allocated string with a text representation of a long number
char *yon_char_from_long(long int_to_convert);

/// @brief Replace all substrings with another string.
/// @param source An initial string to replace.
/// @param find The string to be replaced.
/// @param replace The string that replaces the search string.
/// @return A newly allocated string, with all successfull replacements applied.
/// @example  yon_char_replace(string, "find", "replace")
char *yon_char_replace(char *source, char *find, char*replace);

// __attribute_deprecated_msg__("Use yon_char_replace instead")
char *yon_char_replace_single(char *source, char *find, char *replace);

/// @brief Replace all substrings inside string.
/// @param source An initial string to replace.
/// @param ... List of find and replace strings to apply to string. Must end with NULL.
/// @return A newly allocated string, with all successfull replacements applied.
/// @example  yon_char_replace_valist(string, "find1", "string1", "find2", "string2", NULL)
char* yon_char_replace_valist(const char *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(const char *parameters, int *size, char *divider);

#define yon_char_parsed_add_or_create_if_exists(parsed,size,data) {if (!parsed) parsed = yon_char_parsed_new(size,data,NULL);\
                                                                    else parsed = yon_char_parsed_append(parsed,size,data);}

/**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);

/**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);

int yon_char_parsed_strstr(char **parameters, int size, char *param);

/**yon_char_parsed_check_repeats(char **parameters, int size)
 * [EN]
 * Checks if [parameters] string array of length [size]
 * has repeated elements;
 * [RU]
 * Проверяет есть ли в массиве строк [parameters], размера [size]
 * повторения
*/
int yon_char_parsed_check_repeats(char **parameters, int size, int *first_overlap, int *second_overlap);

/**yon_char_find_count(char *source, char *find)
 * [EN]
 * 
 * [RU]
 * Считает количество символов [find] в строке [source]
*/
[[ deprecated("Use yon_char_count instead") ]]
int yon_char_find_count(char *source, char *find);

int yon_char_count(char *source, char *find);

/**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);

/**yon_char_parsed_new (config_str old, int *old_size, ...)
 * [EN]
 * 
 * [RU]
 * Создаёт новый массив строк. В [size] выгружается его размер
 * [...] - неограниченное количество строк.
*/
config_str yon_char_parsed_new (int *size, ...);

void yon_char_parsed_free(config_str source, int size);

/**config_str yon_char_parsed_copy(config_str to_copy, int size)
 * [EN]
 * 
 * [RU]
 * Возвращает копию массива строк [to_copy] размера [size]
*/
config_str yon_char_parsed_copy(config_str to_copy, int size);

/**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 yon_char_parsed_prepend(config_str parsed, int *size, char *string);

void yon_char_parsed_append_strings (config_str array, int size, char *prepend);

void yon_char_parsed_prepend_strings (config_str array, int size, char *prepend);

/**yon_char_parsed_merge(config_str array1, int size1, config_str array2, int size2, int *final_size)
 * [EN]
 * 
 * [RU]
 * Объединяет два массива строк в один.
 * [array1] - первый массив строк размера [size1]
 * [array2] - второй массив строк размера [size2]
 * [final_size] - указатель на целочисленную переменную в которую должен вернуться размер нового массива
*/
config_str yon_char_parsed_merge(config_str array1, int size1, config_str array2, int size2, int *final_size);

/// @brief Merge multiple char* arrays with va_list
/// @param final_size pointer, where to final size of string array should be returned 
/// @param ... A list of int-char** pairs of string arrays and sizes, terminated by -1
/// @example yon_char_parsed_merge_stack(&final_size, (int)array1_size, (char**)array1, (int)array2_size, (char**)array2, (int)array3_size, (char**)array3, NULL)
/// @return A newly allocated string array, containing all arrays elements
config_str yon_char_parsed_merge_stack(int *final_size, ...);

/**yon_char_parsed_merge_no_repeats(config_str array1, int size1, config_str array2, int size2, int *final_size)
 * [EN]
 * 
 * [RU]
 * Объединяет два массива строк в один с предотвращением дублей.
 * [array1] - первый массив строк размера [size1]
 * [array2] - второй массив строк размера [size2]
 * [final_size] - указатель на целочисленную переменную в которую должен вернуться размер нового массива
*/
config_str yon_char_parsed_merge_no_repeats(config_str array1, int size1, config_str array2, int size2, int *final_size);

int yon_char_parsed_divide_full(config_str parsed,int size,int divide_pos);

int yon_char_parsed_divide_search_full(config_str parsed,int size,char *divide_pos, int delete_divider);

/**yon_char_parsed_convert_to_dictionary(config_str parsed, int size)
 * [EN]
 * 
 * [RU]
 * Конвертирует массив строк [parsed] размера [size] в словарь типа dictionary*
 */
dictionary *yon_char_parsed_convert_to_dictionary(config_str parsed, int size);

/**yon_char_parsed_convert_copy_to_dictionary(config_str parsed, int size)
 * [EN]
 * 
 * [RU]
 * Копирует массив строк [parsed] размера [size] в словарь типа dictionary*
 */
dictionary *yon_char_parsed_convert_copy_to_dictionary(config_str parsed, int size);

/**yon_char_parsed_convert_copy_to_dictionary(config_str parsed, int size)
 * [EN]
 * 
 * [RU]
 * Конвертирует массив строк [parsed] размера [size] в строку, вставляя в местах соединений строку [divider_replace]
 */
char *yon_char_parsed_to_string(config_str parsed, int size, char *divider_replace);
char *yon_char_parsed_to_string_full(config_str parsed, int size, char *divider_replace);

/**yon_char_parsed_to_string_for_iters(config_str parsed, int size, char *divider_replace,int iterations)
 * [EN]
 * 
 * [RU]
 * Конвертирует [iterations] первых элементов массива строк [parsed] размера [size] в строку,
 * вставляя в местах соединений строку [divider_replace] 
 */
char *yon_char_parsed_to_string_for_iters(config_str parsed, int size, char *divider_replace,int iterations);

/**yon_char_parsed_cut(config_str parsed, int size, int pos)
 * [EN]
 * 
 * [RU]
 * Создаёт новый массив строк из первых [pos] элементов массива строк [parsed] размера [size]
 */
config_str yon_char_parsed_cut(config_str parsed, int size, int pos);

int yon_char_parsed_find_element(config_str parsed, int size, char *target);

/// @brief Checks if two config_str elements are equal or not for sort functions
/// @param a pinter for first compared element;
/// @param b pointer for second compared element;
/// @return -1 if a<b; 0 if a=b; 1 if a>b
int yon_char_parsed_compare(const config_str a, const config_str b);

int yon_char_find_last_symbol_before_length(char *string, char target, int length);

/**yon_char_wrap_to_length(char *target, unsigned int length, int *size)
 * [EN]
 * 
 * [RU]
 * Разделяет строку [target] на отрезки длиной до [length] символов каждый и возвращает массив длиной [size]
 */
config_str yon_char_wrap_to_length(char *target, unsigned int length, int *size);

char *yon_char_wrap_to_length_str(char *target, unsigned int length);

/**yon_ubl_check_root()
 * [EN]
 * 
 * [RU]
 * Возвращает 1 если приложение было запущено от root
*/
int yon_ubl_check_root();

/**yon_ubl_root_user_get()
 * [EN]
 * 
 * [RU]
 * Возвращает имя пользователя.
 * Если пользователь запустил приложение через root, выводится имя пользователя, запустившего приложение через root 
*/
char *yon_ubl_root_user_get();

/** yon_ubl_user_get_home_directory()
 * [EN]
 * 
 * [RU]
 * Возвращает домашний каталог пользователя.
 * Если пользователь открыл утилиту с правами суперпользователя, всё равно возвращает каталог пользователя, а не root
*/
char *yon_ubl_user_get_home_directory();

/** yon_ubl_get_all_users(int *user_size)
 * [EN]
 * 
 * [RU]
 * Возвращает массив всех пользователей в системе и записывает его размер в [user_size]
*/
config_str yon_ubl_get_all_users(int *user_size);

// parsing functions

int yon_password_get_min_len();

/// @brief Converts bytes amount to kilobytes, megabytes gigabytes or terabytes (K, M, G, T)
/// @param bytes bytes to convert
/// @param size pointer for conversion iteration number. use it with yon_size_get_mod() to get text string of conversion
/// @return converted to kilobytes, megabytes gigabytes or terabytes vaue
float yon_size_convert_automatic(int bytes, int *size);

/// @brief Convert size from kilobytes, megabytes gigabytes or terabytes (K, M, G, T) to bytes
/// @param size initial size to convert
/// @param size_mod size modifier. Use yon_get_size_get_from_letter() to get.
/// @return converted to bytes value
long yon_size_to_bytes(long size, int size_mod);

/**yon_get_size_get_from_letter(char size)
 * [EN]
 * 
 * [RU]
 * Функция для работы с конфигурацией ubconfig.
 * Конвертировать символ размера (K, M, G, T) в множитель для перевода размера в байты
 */
int yon_get_size_get_from_letter(char size);

/**yon_size_get_mod(int size)
 * [EN]
 * 
 * [RU]
 * Функция для работы с конфигурацией ubconfig.
 * Конвертировать числовое представление размера из yon_get_size_get_from_letter() в символьное
 */
char *yon_size_get_mod(int size);

double yon_size_long_convert_to_mod(double size, char mod);

double yon_size_long_convert_automatic(unsigned long bytes, char *size);

/// @brief Wrap all spaces in paths for proper handling in commands 
/// @return A newly allocated string or NULL if path was empty.
char *yon_file_path_proceed_spaces(char *path);

/// @brief Read file and return its contents as string array, separated by new line symbols.
/// @param file_path Path to file.
/// @param size Size of returned list.
/// @return A newly allocated array of strings containing the entire contents of the file.
config_str yon_file_open(char *file_path, int *size);

/// @brief Save string to file
/// @param file_path File where text will be saved.
/// @param text Text to save.
/// @return TRUE if successful, FALSE otherwise
int yon_file_save(char *file_path, char *text);

/// @brief Create a file for path.
/// @param path Path to create file.
/// @param name File name.
/// @param rules Rules for all created directories and file (from 0000 to 0777).
/// @return TRUE if file were successfully created, FALSE if file exist/invalid path/error occured while creating file.
int yon_file_create(char *path, char *name, int rules);

/// @brief Create a file and any missing directories for path.
/// @param rules Rules for all created directories and file (from 0000 to 0777).
/// @return TRUE if file were successfully created, FALSE if file exist/invalid path/error occured while creating file.
int yon_file_create_full_path(char *path, mode_t rules);


/// @brief Get a list of directory names for path.
/// @param size Size of returned list.
/// @return A newly allocated string array or NULL.
config_str yon_file_list_dirs (char *path, int *size);

/// @brief Get a list of file/directory names for path.
/// @param path Path string.
/// @param size Size of returned list.
/// @return A newly allocated string array or NULL.
config_str yon_file_ls(char *path, int *size);

/// @brief Get parent directory from path.
/// @return Newly allocated string with parent path or NULL.
char *yon_file_get_parent(const char *path);

/// @brief Check if path points to directory.
/// @return TRUE if path is pointing to directory, 0 otherwise.
int yon_file_is_directory(const char *path);


/// @brief Removes directory for path. If path is not directory, nothing happens.
void yon_dir_remove(const char *path);

/** yon_dir_get_contents(char *dir_path, int *size)
 * [EN]
 * [DEPRECATED]
 * 
 * [RU]
 * [УСТАРЕЛО]
 * Проверяет существует ли папка [dir_path] и
 * возвращает список всех вложенных файлов и папок,
 * передавая в [size] длину списка.
*/
__attribute__((deprecated("Use yon_file_ls() instead"))) config_str yon_dir_get_contents(char *dir_path, int *size);

config_str yon_dir_get_by_mask(char *path, char *mask, int *size);

//config functions

#define ubconfig_save_command "ubconfig "

#define ubconfig_load_command_old "ubconfig --source"

#define ubconfig_dull_command "ubconfig "
#define ubconfig_set_command(target) yon_char_unite("ubconfig ",!yon_char_is_empty(target)?"--target ":"",target," ",NULL)
#define ubconfig_set_command_full(target, section, data) yon_char_unite("ubconfig ",!yon_char_is_empty(target)?"--target ":"",!yon_char_is_empty(target)?target:""," set ",section," ",data,NULL)
#define ubconfig_load_command(target) yon_char_unite("ubconfig --source ",target," get ",NULL)
#define ubconfig_load_command_full(target, data) yon_char_unite("ubconfig --source ",target," get ",data,NULL)
#define ubconfig_remove_command_full(target, section, data) yon_char_unite("ubconfig ",!yon_char_is_empty(target)?"--target ":"",!yon_char_is_empty(target)?target:""," remove ",!yon_char_is_empty(section)?section:"",!yon_char_is_empty(section)?" ":"",data,NULL)

/**
 * Типы конфигураций ubconfig-а
*/
typedef enum {
    YON_CONFIG_LOCAL=0,
    YON_CONFIG_GLOBAL,
    YON_CONFIG_BOTH,
    YON_CONFIG_DEFAULT,
    YON_CONFIG_CUSTOM
} YON_CONFIG_TYPE;

char *yon_config_get_all_info();

void yon_config_parameter_set_load_command(char *key, char *command);

void yon_config_parameter_set_save_command(char *key, char *command);

char *yon_config_parameter_get_load_command(char *key);

char *yon_config_parameter_get_save_command(char *key);

char *yon_config_get_type_path(YON_CONFIG_TYPE type);

/**yon_config_load(char *command, int *str_len)
 * [EN]
 * 
 * [RU]
 * Выполняет команду [command] и возвращает результат выполнения команды, разделяя на строки.
 * В [str_len] возвращается длина возвращаемого массива
*/
config_str yon_config_load(char *command, int *str_len);

config_str yon_config_load_file(FILE *file, int *str_len);

config_str yon_config_get_load_parameters_by_list(int *size, config_str parameters, int params_size);

config_str yon_config_get_save_parameters_by_list(int *size, config_str parameters, int params_size);

config_str yon_config_get_save_parameters_by_key(int *size, ...);

config_str yon_config_get_save_parameters(int *size);

char *yon_config_parameter_wrap(char *parameter_key);

/**yon_config_parameter_prepare_command(char *command, char *path, char *section, char *parameter)
 * 
*/
char *yon_config_parameter_prepare_command(char *command, char *path, char *section, char *parameter);

/**int yon_config_save_registered(char *path)
 * [EN]
 * Saves config at [path] config. 
 * [path] can be:
 * system
 * global
 * [RU]
 * Сохраняет конфигурацию в [path] конфиг.
 * [path] может быть
 * system - локальный конфиг
 * global - глобальный конфиг
*/
[[ deprecated ( "Use yon_config_save_simple for simple saving instead (full-controlled saving is provided with libublsettingsui-gtk3 library)" ) ]]
int yon_config_save_registered(char *path);

/**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);

int yon_config_set_ignore(char *key);

int yon_config_remove_ignore(char *key);

int yon_config_get_status(char *key);

int yon_config_check_ignore(char *key);

int yon_config_check_default(char *key);

int yon_config_parse_parameter(char *parameter,char **key, char **value);

int yon_char_remove_brackets(char *string);

char *yon_char_get_element(char *target, unsigned int position, char *divider);

int yon_config_command_get_section_pos(const char *);
char *yon_config_command_get_section(const char *command);

int yon_config_command_get_path_pos(config_str parsed, int size);
char *yon_config_command_get_path(const char *command);

config_str yon_config_command_get_parameters(const char *command, int *size);

char *yon_config_get_last_command();
void yon_config_set_last_command(char *command);

/// @brief Import string to config
/// @param config_type configuration type
/// @param string parameter string. A line from ubconfig command output
/// @return 1 if successful, 0 otherwise.
int yon_config_import_string(YON_CONFIG_TYPE config_type, char *string);

/// @brief Load configuration
/// @param config_type Configuration type.
/// @param ... NULL-terminated List of commands.
/// @return 0 if failed, id for specific action type otherwise
int yon_config_load_config(YON_CONFIG_TYPE config_type, ...);

int yon_config_change_key(char *target, char *key);

/**yon_config_load_register_no_cleaning(YON_CONFIG_TYPE config_type,char *section,char *parameter, ...)
 * [EN]
 * 
 * [RU]
 * Считывает параметры [parameter] из раздела [section] ubconfig'а.
 * ... - пара из [section], [parameter], позволяющих загружать параметры из разных разделов конфига, оканчивающихся NULL.
 * Полученные данные парсятся и регистрируются в конфиг без удаления старых данных.
*/
[[ deprecated ( "Use yon_config_load_config instead" ) ]]
int yon_config_load_register_no_cleaning(YON_CONFIG_TYPE config_type,char *section,char *parameter, ...);

/**yon_config_load_register(YON_CONFIG_TYPE config_type,char *section,char *parameter, ...)
 * [EN]
 * 
 * [RU]
 * Считывает параметры [parameter] из раздела [section] ubconfig'а.
 * ... - пара из [section], [parameter], позволяющих загружать параметры из разных разделов конфига, оканчивающихся NULL.
 * Полученные данные парсятся и регистрируются в конфиг, удаляя старые значения.
*/
[[ deprecated ( "Use yon_config_load_config instead" ) ]]
int yon_config_load_register(YON_CONFIG_TYPE config_type,char *section,char *parameter, ...);

/// @brief Set configuration parameter ignore status. Determines whether the parameter will be compared with the value from the configuration or the old value will be ignored when saving.
/// @param key Key of parameter.
/// @param status New status
void yon_config_compare_ignore_set(char *key, int status);

/// @brief Get configuration parameter ignore status
/// @param key Key of parameter.
/// @return TRUE if parameter is ignored, FALSE otherwise
int yon_config_compare_ignore_get(char *key);

/// @brief Mark parameter from configuration for remove. It will be removed from target configuration at save.
/// @param key Key of parameter.
/// @return TRUE if parameter was successfully removed, FALSE otherwise.
int yon_config_remove_by_key(char *key);

/// @brief Mark list of parameters from configuration for remove. It will be removed from target configuration at save.
/// @param keys string array of parameters removing parameter keys.
/// @param size size of string array.
/// @return TRUE if parameter was successfully removed, FALSE otherwise.
int yon_config_remove_by_list(config_str keys, size_t size);

/// @brief Mark list of parameters from configuration for remove. It will be removed from target configuration at save.
/// @param key First of parameter keys to remove.
/// @param ... A null-terminated list of remaining parameter keys.
/// @return TRUE if parameter was successfully removed, FALSE otherwise.
int yon_config_remove_by_args(char *key, ...);

/// @brief Clear a configuration parameter. Remove it completely, as if it had never been added - a parameter removed this way will not be compared when saving.
/// @param key Key of parameter.
/// @return TRUE if parameter was successfully removed, FALSE otherwise.
int yon_config_clear_by_key(const char *key);

/// @brief Remove substring from registered parameter value string
/// @param key parameter key
/// @param delete_target substring to delete 
/// @param separator string, separating elements within parameter's value
/// @return 1 if element was successfully removed, 0 otherwise 
int yon_config_remove_element(char *key, char *delete_target, char *separator);

/// @brief Remove elements string from registered parameter value string of elements
/// @param key parameter key
/// @param delete_target substring to delete 
/// @param separator string, separating elements within parameter's value
/// @return 1 if element was successfully removed, 0 otherwise 
int yon_config_remove_elements(char *key, char *delete_target, char *separator);

/// @brief Remove elements string from registered parameter value string of elements if all of requested parameters exist
/// @param key parameter key
/// @param delete_target substring to delete 
/// @param separator string, separating elements within parameter's value
/// @return 1 if element was successfully removed, 0 otherwise 
int yon_config_remove_elements_all(char *key, char *delete_target, char *divider);

/// @brief Append registered parameter value string
/// @param key parameter key
/// @param append string to append
/// @param separator string, separating elements within parameter's value 
/// @return 1 if element was successfully added, 0 otherwise
int yon_config_append_element(char *key, char *append, char *separator);

/// @brief Append registered parameter value string of elements with another string of elements
/// @param key parameter key
/// @param append string to append
/// @param separator string, separating elements within parameter's value 
/// @return 1 if element was successfully added, 0 otherwise
int yon_config_append_elements(char *key, char *append, char *divider);

/// @brief Append parameter value string event if appended string already exists in parameter value or empty
/// @param key parameter key
/// @param append string to append
/// @param separator string, separating elements within parameter's value
/// @return 1 if element was successfully added, 0 otherwise
int yon_config_force_append_element(char *key, char *append, char *separator);

/// @brief Set status for registered configuration parameter
/// @param key parameter key
/// @param status Status to set. -1 for deletion; 0 for unchanged; 1 for created/changed
/// @return 1 if parameter's status was successfully set, 0 otherwise
int yon_config_set_status(char *key, int status);

/// @brief Set status for whole list of configuration parameters exist
/// @param status Status to set. -1 for deletion; 0 for unchanged; 1 for created/changed
void yon_config_set_status_full(int status);

/// @brief Get value of specific registered parameter
/// @param key parameter key
/// @return parameter value or NULL if parameter doesn't exist
void *yon_config_get_by_key(const char *key);

/// @brief Get value of specific registered parameter from default list
/// @param key parameter key
/// @return parameter value or NULL if parameter doesn't exist
char *yon_config_default_get_by_key(const char *key);

/// @brief Find all parameters from the default configuration by string
/// @param key the search string
/// @param size Size of the returned parameter list
/// @return A newly allocated list of all found parameters or NULL
config_str yon_config_default_get_all_by_key(const char *key, int *size);

/// @brief Get value of specific registered parameter from both registered and default lists
/// @param key parameter key
/// @return parameter value or NULL if parameter doesn't exist
char *yon_config_get(char *key);

/// @brief Get value of specific registered parameter from both registered and default lists. Default configuration parameter is requested by different string.
/// @param key parameter key
/// @return parameter value or NULL if parameter doesn't exist
char *yon_config_get_separate_default(const char *key, const char *default_param);

/// @brief Get first existing value from list of parameters from registered list.
/// @param parameter The first parameter key.   
/// @param ... A list of parameter keys, ending with NULL. List is searched from first to last, returning first existing value (PARAMETER=something)
/// @return A newly allocated string with parameter's value
/// @example yon_config_seek_in_parameters("DOMAIN","DEFAULTPASSWD","USERADD[user]",NULL);
char *yon_config_seek_in_parameters(const char *parameter, ...);

/// @brief Get configuration section for registered parameter
/// @param key parameter key
/// @return A newly allocated string with configuration section or NULL
char *yon_config_get_section_for_key(char *key);

/// @brief Get all registered parameter keys for specific configuration section
/// @param section_name section name
/// @param size Pointer to size of string array 
/// @return A newly allocated string array containing parameter keys 
config_str yon_config_get_parameters_for_section(const char *section_name, int *size);

// config_str yon_config_get_parameters_for_all_sections(int *size);
// config_str yon_config_get_parameters_for_all_sections_saved(int *size);
// config_str yon_config_get_parameters_for_all_sections_removed(int *size);

/// @brief Find all parameters from the configuration by string
/// @param key the search string
/// @param size Size of the returned parameter list
/// @return A newly allocated list of all found parameters or NULL
void *yon_config_get_all_by_key(char *key, int *size);

/// @brief Find all parameter keys from the configuration by string
/// @param key the search string
/// @param size Size of the returned parameter list
/// @return A newly allocated list of all found parameter keys or NULL
void *yon_config_get_all_keys_by_key(char *key, int *size);

/// @brief Find all parameter keys from the default configuration by string
/// @param key the search string
/// @param size Size of the returned parameter list
/// @return A newly allocated list of all found parameter keys or NULL
void *yon_default_config_get_all_by_key(char *key, int *size);

/// @brief Find all parameters from the configuration by string, excluding ignored parameters
/// @param key the search string
/// @param size Size of the returned parameter list
/// @return A newly allocated list of all found parameters or NULL
void *yon_config_get_all_by_key_no_ignored(char *key, int *size);

/// @brief Get all requested configuration parameters in the order requested
/// @param size Size of the returned parameter list
/// @param ... List of parameter keys, ending with NULL
/// @return A newly allocated list of all found parameters or NULL if nothing were found
config_str yon_config_get_selection_by_key(int *size, ...);

/// @brief Get all requested configuration parameters in the order requested, but exclude ignored parameters
/// @param size Size of the returned parameter list
/// @param ... List of parameter keys, ending with NULL
/// @return A newly allocated list of all found parameters or NULL if nothing were found
config_str yon_config_get_selection_by_key_no_ignored(int *size, ...);

/// @brief Get a list of all parameter keys
/// @param size Size of the returned list
/// @return A newly allocated list of all parameter keys or NULL if configuration is empty
config_str yon_config_get_all_keys(int *size);

config_str yon_config_get_all_keys_no_ignored(int *size);

/**yon_config_set(char *key, void *data)
 * [EN]
 * 
 * [RU]
 * Производит поиск по конфигу и заменяет значение параметра с ключом [key] на новое значение [data];
*/
int yon_config_set(char *key, void *data);


/// @brief Set a regex pattern as a compare mask for saving window
/// @param key Parameter's key
/// @param mask_pattern regex pattern;
/// @return 1 if successful, 0 otherwise
int yon_config_set_mask_pattern(const char *key, const char *mask_pattern);

/// @brief Get a compare mask for saving window as a regex pattern
/// @param key Parameter's key
/// @return newly allocated string of regex pattern or NULL
char *yon_config_get_mask_pattern(const char *key);

/// @brief Clear configuration parameters
/// @return 1 if any parameters were removed, 0 if configuratino was empty
int yon_config_clean();

/// @brief Remove 'default' flag from parameter
/// @param key parameter key
/// @return 1 if 'default' flag were removed, 0 if parameter wasn't found
int yon_config_default_remove(char *key);

enum YON_CONFIG_SAVED_TYPE{
    YON_CONFIG_SAVED_NEW,
    YON_CONFIG_SAVED_EXIST,
    YON_CONFIG_SAVED_REMOVED,
    YON_CONFIG_SAVED_UNCHANGED,
    YON_CONFIG_SAVED_CHANGED,
    YON_CONFIG_SAVED_ERROR
};

/// @brief Register new or change existing parameter inside configuration system
/// @param key key for new or existing parameter
/// @param config_load command to load a parameter from the system configuration
/// @param data parameter value
/// @return the type of action performed by the configuration system with the parameter
enum YON_CONFIG_SAVED_TYPE yon_config_register(char *key,char *config_load, char *data);

/// @brief Register new or change existing parameter inside configuration system into default parameters list.
/// @param key key for new or existing parameter
/// @param config_load command to load a parameter from the system configuration
/// @param data parameter value
/// @return the type of action performed by the configuration system with the parameter
enum YON_CONFIG_SAVED_TYPE yon_config_register_default(char *key,char *config_load, char *data);

/// @brief 
/// @param target 
/// @param path 
/// @return 
char *yon_config_save_simple(YON_CONFIG_TYPE target, char *path);

/// @brief Save list of parameters into configuration.
/// @param parameters_keys List of parameter keys.
/// @param size size of parameter keys list.
/// @param path Path to configuration .ini.
/// @return TRUE if successful, FALSE otherwise.
char *yon_config_save_list_simple(config_str parameters_keys, size_t size, char *path);


/// @brief Save list of parameters into configuration.
/// @param path Path to configuration .ini.
/// @param ... A NULL-terminated list of parameter keys.
/// @return TRUE if successful, FALSE otherwise.
char *yon_config_save_args_simple(char *path, ...);

/// @brief Update parameter's value from configuration.
/// @param key Parameter's key.
/// @return TRUE if parameter successfully updated, FALSE if parameter doesn't registered in configuration
int yon_config_update_by_key(char *key);

/// @brief Update parameter's value from configuration.
/// @param key Parameters key list.
/// @param size size of parameters keys list.
/// @return TRUE if parameter successfully updated, FALSE if parameter doesn't registered in configuration
int yon_config_update_by_list(char *config_path,config_str keys, size_t size);

/// @brief Update parameters value from configuration.
/// @param config_path Configuration path where from to update parameter.
/// @param ... NULL-terminated list of parameter keys.
/// @return TRUE if parameter successfully updated, FALSE if parameter doesn't registered in configuration
int yon_config_update_by_args(char *config_path, ...);

/**int yon_config_force_save_registered(char *path, char *section)
 * [EN]
 * Force config to save at [path] config ignoring parameter save status. 
 * [path] can be:
 * system
 * global
 * [RU]
 * Принудительно сохраняет конфигурацию в [path] конфиг игнорируя статус параметра.
 * [path] может быть
 * system - локальный конфиг
 * global - глобальный конфиг
*/
[[ deprecated ( "Will be removed soon" ) ]]
int yon_config_force_save_registered(char *path);

config_str yon_config_find_keys(char *target, int *size);

/// @brief Get all configuration parameters list
/// @param size A pointer for returning list's size
/// @return A newly allocated list of parameter keys;
config_str yon_config_get_all(int *size);

/// @brief Get all modified configuration parameters
/// @param size A pointer for returning list's size
/// @return A newly allocated list of parameter keys;
config_str yon_config_get_all_modified(int *size);

/// @brief Get all configuration parameters, which were not marked as ignored.
/// @param size A pointer for returning list's size
/// @return A newly allocated list of parameter keys;
config_str yon_config_get_all_no_ignored(int *size);

/*Возвращает ключ из параметра, или сам параметр если ключ не был найден*/
char *yon_config_parameter_get_key(char *parameter_string);

/// @brief Move configuration parameter to be before another parameter. Used to sort parameters for saving if a precise saving order is required
/// @param parameter Moved configuration parameter;
/// @param target Parameter to which the required parameter will be moved
/// @return TRUE if succeeded, FALSE otherwise
int yon_config_move_before(char *parameter, char *target);

/// @brief Move configuration parameter to be after another parameter. Used to sort parameters for saving if a precise saving order is required
/// @param parameter Moved configuration parameter;
/// @param target Parameter to which the required parameter will be moved
/// @return TRUE if succeeded, FALSE otherwise
int yon_config_move_after(char *parameter, char *target);

/// @brief Revert configuration to default values.
void yon_config_to_default();

typedef struct yon_config_parameter
{
    char *key;
    void *data;
    struct yon_config_parameter *next;
    struct yon_config_parameter *prev;
    struct yon_config_parameter *first;
    DICT_TYPE data_type;
    int flag1;
    char *section;
    int ignore;
    char *save_command;
    char *load_command;
    int compare_ignore;
    char *regex_mask_pattern;
} yon_config_parameter;

typedef struct {
    yon_config_parameter *param;
} yon_config_custom;

/// @brief Create a custom configuration storage
/// @return A newly allocated custom configuration storage 
yon_config_custom *yon_config_custom_new();

/// @brief Load custom configuration
/// @param ... NULL-terminated List of commands.
/// @return 0 if failed, id for specific action type otherwise
int yon_config_custom_load_config(yon_config_custom *target, ...);

/// @brief Import string to custom config
/// @param config_type configuration type
/// @param string parameter string. A line from ubconfig command output
/// @return 1 if successful, 0 otherwise.
int yon_config_custom_import_string(yon_config_custom *target, char *string);

/// @brief Register new or change existing parameter inside custom configuration
/// @param key key for new or existing parameter
/// @param config_load command to load a parameter from the system configuration
/// @param data parameter value
/// @return the type of action performed by the configuration system with the parameter
enum YON_CONFIG_SAVED_TYPE yon_config_custom_register(yon_config_custom *target, char *key,char *config_load, char *data);

/// @brief Clear custom configuration parameters
/// @return 1 if any parameters were removed, 0 if configuratino was empty
int yon_config_custom_clean(yon_config_custom *target);

/// @brief Get a list with pairs of parmaeter=value strings for saving from custom config
/// @param size Pointer for final size of list
/// @param parameters list of parameters to request from custom config
/// @param params_size size of requested parameters list
/// @return 
config_str yon_config_get_save_parameters_by_custom_config(yon_config_custom *target, int *size, config_str parameters, int params_size);

/// @brief Swap internal and custom config
/// @return TRUE if swapped successfully, FALSE otherwise
int yon_config_custom_swap(yon_config_custom *target);

/// @brief Apply custom config to internal config. Remove all parameters and insert custom configuration;
/// @return TRUE if applied successfully, FALSE otherwise
int yon_config_custom_apply(yon_config_custom *target);


char *yon_config_custom_get(yon_config_custom *target, char *key);
void *yon_config_custom_get_all_by_key(yon_config_custom *target,char *key, int *size);

// terminal-using functions

/// @brief Execute command in separate thread
/// @param command Command to execute
/// @param args arguments, adding to command, can be NULL;
/// @return returned status of command execution.
int yon_launch_app_with_arguments(char *command, char *args);

/// @brief Execute a command
/// @param command Command to execute
void yon_launch(char *command);

/// @brief Get cuurent OS name
/// @return Newly allocated string or NULL
char *yon_ubl_get_os_name();

// // Trash collector functions
// int yon_trash_collector_append(void *pointer, char group_key);

// int yon_trash_collector_free(char *group_key);

// void *yon_malloc(int size, char *group_key);

#define LOCALES_DOMAIN_NAME "libublsettings"

enum YON_LOCALE_PARAMETER{
    YON_LOCALE_LANGUAGE,
    YON_LOCALE_LANG_NAME,
    YON_LOCALE_TERRITORY,
    YON_LOCALE_LANG_AB,
    YON_LOCALE_TITLE,
    YON_LOCALE_CODE,
    YON_LOCALE_CODESET
};

typedef struct yon_hash_element{
    dictionary_fields(yon_hash_element);
} yon_hash_element;

typedef struct {
    yon_hash_element **data;
    unsigned int size;
    unsigned int(*hash_func)(const char *);
} yon_hash;

unsigned int yon_str_hash(const char *str);

yon_hash *yon_hash_new(int size, unsigned int(*hash_func)(const char *));
int yon_hash_insert(yon_hash *target, const char *key, void *data);
int yon_hash_remove(yon_hash *target, const char *key);
void *yon_hash_lookup(yon_hash *target, const char *key);
int yon_hash_add(yon_hash *target,const char *key);
int yon_hash_contains(yon_hash *target, const char *key);
void yon_locale_init();
config_str yon_locale_get_all_codes(int *size);
char *yon_locale_get_parameter(char *code,enum YON_LOCALE_PARAMETER type);

typedef struct {
    pthread_t tid;
    FILE *file;
    volatile int stop_on_timeout;
} yon_channel_data;

/// @brief Start asnchronous reading of command output.
/// @param command The command to execute
/// @param callback The callback, activated every time command sends new data
/// @param data An additional data for callback of any type
/// @return A newly alloceted channel data structure for opened channel
yon_channel_data *yon_config_channel_start(const char *command, void (*callback)(config_str, unsigned int, void *), void *data);

/// @brief Stop channel reading
/// @param channel Channel data structure of opened channel
void yon_config_channel_stop(yon_channel_data *channel);

#endif