#include "libublsettings.h"

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;

yon_config_parameter *yon_config_parameter_new_with_data(char *key, void *data){
    yon_config_parameter *param = yon_remalloc(NULL,sizeof(yon_config_parameter));
    memset(param,0,sizeof(yon_config_parameter));
    param->data=yon_char_new(data);
    param->data_type=DICTIONARY_CHAR_TYPE;
    param->first=param;
    param->flag1=1;
    param->key=yon_char_new(key);
    return param;
}

yon_config_parameter *yon_config_parameter_append_with_data(yon_config_parameter *dict, char *key, void *data){
    yon_config_parameter *param = yon_config_parameter_new_with_data(key,data);
    param->first=dict->first;
    dict = (yon_config_parameter*)yon_dictionary_get_last((dictionary*)dict);
    (param->prev)=dict;
    dict->next=param;
    return param;
}


static yon_config_parameter *__yon__config__strings = NULL;
static yon_config_parameter *__yon__config__default__strings = NULL;
dictionary *__yon_config_ignored = NULL;

#define check_config if(__yon__config__strings)
#define check_default_config if(__yon__config__default__strings)
#define for_config yon_config_parameter *temp = NULL; for_dictionaries(temp,__yon__config__strings)
#define for_default_config dictionary *temp = NULL; for_dictionaries(temp,(dictionary*)__yon__config__default__strings)
#define yon_config_parameter_add_or_create_if_exists_with_data(dict,key,value)   {if (dict){\
                                                                                    yon_config_parameter *dct = (yon_config_parameter *)yon_dictionary_get((dictionary**)&dict,key);\
                                                                                    if (dct) {\
                                                                                        dict=dct;\
                                                                                        dict->data=value;\
                                                                                    }\
                                                                                    else{\
                                                                                    dict=yon_config_parameter_append_with_data(dict,key,value);\
                                                                                    }\
                                                                                }\
                                                                                else dict=yon_config_parameter_new_with_data(key,value);}

char *yon_config_get_type_path(YON_CONFIG_TYPE type){
    switch (type){
        case YON_CONFIG_DEFAULT:
        return "default";
            break;
        case YON_CONFIG_BOTH:
        return "";
            break;
        case YON_CONFIG_GLOBAL:
        return "global";
            break;
        case YON_CONFIG_LOCAL:
        return "system";
            break;
    }
    return NULL;
}

char *yon_config_get_all_info(){
    check_config{
        int size;
        config_str parsed = yon_config_get_all(&size);
        char *full = yon_char_parsed_to_string(parsed,size,"\n");
        yon_char_parsed_free(parsed,size);
        return full;
    }
    return NULL;
}

void yon_config_parameter_set_load_command(char *key, char *command){
    dictionary *found = yon_dictionary_get((dictionary**)&__yon__config__strings,key);
    if (found){
        ((yon_config_parameter*)found)->load_command=yon_char_new(command);
    }
}

void yon_config_parameter_set_save_command(char *key, char *command){
    dictionary *found = yon_dictionary_get((dictionary**)&__yon__config__strings,key);
    if (found){
        ((yon_config_parameter*)found)->save_command=yon_char_new(command);
    }
}

char *yon_config_parameter_get_load_command(char *key){
    dictionary *found = yon_dictionary_get((dictionary**)&__yon__config__strings,key);
    if (found){
        return ((yon_config_parameter*)found)->load_command;
    }
    return NULL;
}

char *yon_config_parameter_get_save_command(char *key){
    dictionary *found = yon_dictionary_get((dictionary**)&__yon__config__strings,key);
    if (found){
        return ((yon_config_parameter*)found)->save_command;
    }
    return NULL;
}

int yon_config_set_ignore(char *key){
    if (!yon_dictionary_get(&__yon_config_ignored,key)){
        yon_dictionary_add_or_create_if_exists_with_data(__yon_config_ignored,key,NULL);
    }
}

int yon_config_set_mask_pattern(const char *key, const char *mask_pattern){
    if (yon_char_is_empty(key)) return 0;
    yon_config_parameter *parameter = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,(char*)key);
    if (!parameter) return 0;

    if (!yon_char_is_empty(parameter->regex_mask_pattern))
        free(parameter->regex_mask_pattern);

    if (yon_char_is_empty(mask_pattern)){
        parameter->regex_mask_pattern = NULL;
    } else {
        parameter->regex_mask_pattern = yon_char_new(mask_pattern);
    }
    return 1;
}

char *yon_config_get_mask_pattern(const char *key){
    if (yon_char_is_empty(key)) return NULL;
    yon_config_parameter *parameter = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,(char*)key);
    if (!parameter) return NULL;

    return yon_char_new(parameter->regex_mask_pattern);
}

int yon_config_remove_ignore(char *key){
    dictionary *dict = yon_dictionary_get(&__yon_config_ignored,key);
    if (dict) {
        __yon_config_ignored=yon_dictionary_rip(dict);
    }
}

int yon_config_get_status(char *key){
    dictionary *dict;
    if ((dict=yon_dictionary_get((dictionary**)&__yon__config__strings,key))){
        return ((yon_config_parameter*)dict)->flag1;
    }
    else return 0;
}

int yon_config_check_ignore(char *key){
    dictionary *dict = yon_dictionary_get(&__yon_config_ignored,key);
    if (dict) return 1;
    else return 0;
}

int yon_config_check_default(char *key){
    check_default_config{
        for_default_config{
            if (!strcmp(temp->key,key)){
                return 1;
            }
        }
    }
    return 0;
}

int yon_config_load_register_no_cleaning(YON_CONFIG_TYPE config_type,char *section,char *parameter, ...){
    if (config_type!=YON_CONFIG_BOTH){
        va_list args;
        va_start(args,parameter);
        dictionary *sections = NULL;
        yon_dictionary_add_or_create_if_exists_with_data(sections,section,parameter);
        char *arg;

        while (arg=va_arg(args,char*)){
            char *key = va_arg(args,char*);
            if (sections&&yon_dictionary_get(&sections,arg)) sections->data=(void*)yon_char_unite(yon_dictionary_get_data(sections,char*)," ",key,NULL);
            else yon_dictionary_add_or_create_if_exists_with_data(sections,arg,key);
        }
        char *command=NULL;
        dictionary *dict;
        for_dictionaries(dict,sections){
            command = yon_char_unite(ubconfig_load_command_old,config_type==YON_CONFIG_GLOBAL ? " global get " : config_type==YON_CONFIG_LOCAL ? " system get " : " default get", dict->key," ", yon_dictionary_get_data(dict,char*),NULL);
            FILE *output = popen(command, "r");
            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);
                    char *final_str=yon_char_divide_search(str,"\n",-1);
                    if ((final_str[0]=='\''&&final_str[strlen(final_str)-1]=='\'')||(final_str[0]=='\"'&&final_str[strlen(final_str)-1]=='\"')){
                        final_str[strlen(final_str)-1] = '\0';
                        free(yon_char_divide(final_str,0));
                    }
                    
                        yon_config_parameter *cur_config = (config_type!=YON_CONFIG_DEFAULT? __yon__config__strings:__yon__config__default__strings);
                    dictionary *dicte = yon_dictionary_get((dictionary**)&cur_config,key);
                    if (!dicte){
                        yon_config_parameter_add_or_create_if_exists_with_data(cur_config,key,yon_char_new(final_str));
                    } else {
                        if (strcmp((char*)dicte->data,final_str)){
                            cur_config->data=final_str;
                        } else {
                            continue;
                        }
                    }
                    cur_config->flag1=0;
                    yon_config_remove_ignore(key);
                    if (config_type==YON_CONFIG_DEFAULT){
                        cur_config->flag1=-2;
                        yon_config_set_ignore(key);
                    }
                    cur_config->data_type=DICTIONARY_CHAR_TYPE;
                    cur_config->section=dict->key;
                }
            }
            free(command);
            fclose(output);
        }
        check_config
            return 1;
        else return 0;
    } else return -1;
}

int yon_config_parse_parameter(char *parameter,char **key, char **value){
    (*key)=NULL;
    (*value)=NULL;
    check_config{
            char *copied = yon_char_new(parameter);
        char *key_temp = yon_char_divide_search(copied,"=",-1);
        if (key_temp!=parameter){
            char *final_str=yon_char_divide_search(copied,"\n",-1);
            if ((final_str[0]=='\''&&final_str[strlen(final_str)-1]=='\'')||(final_str[0]=='\"'&&final_str[strlen(final_str)-1]=='\"')){
                final_str[strlen(final_str)-1] = '\0';
                free(yon_char_divide(final_str,0));
            }
            (*key)=key_temp;
            (*value)=final_str;
            return 1;
        }
    }
    return 0;
}

int yon_char_remove_brackets(char *string){
    int done=0;
    if (strlen(string)>2){
        if (string[0]=='\''||string[0]=='\"'){
            done=1;
            free(yon_char_divide(string,0));}
        if (string[strlen(string)-1]=='\''||
                string[strlen(string)-1]=='\"') {
            done=1;
            string[strlen(string)-1] = '\0';
        }
    }
    return done;
}

char *yon_config_replace_parameter(char *command, char *parameter, int place){
    if (!yon_char_is_empty(command));
    int size=0;
    config_str parsed = yon_char_parse(command,&size," ");
    int firstparameter = yon_config_command_get_section_pos(command)+1;
    if (firstparameter+place<size){
        free(parsed[firstparameter+place]);
        parsed[firstparameter+place]=yon_char_new(parameter);
    }
    char *final = yon_char_parsed_to_string(parsed,size," ");
    yon_char_parsed_free(parsed,size);
    return final;
}

/**Парсит команду на отдельные команды для каждого параметра*/
int yon_config_command_prepare(config_str *commands, int *commands_size,char *command){
    if (!yon_char_is_empty(command)){
        int parsed_size;
        int done=0;
        config_str parsed = yon_char_parse(command,&parsed_size," ");
        int get_place = yon_config_command_get_section_pos(command)-1;
        if (get_place>-1){
            if (parsed_size>get_place+2){
                for (int j=get_place+2;j<parsed_size;j++){
                    int new_size=get_place+2;
                    config_str new_element = yon_char_parsed_cut(parsed,parsed_size,get_place+2);
                    yon_char_parsed_add_or_create_if_exists(new_element,&new_size,parsed[j]);
                    *commands = yon_char_parsed_append(*commands,commands_size,yon_char_parsed_to_string(new_element,new_size," "));
                    done=1;
                }
            }
            return done;
        }
    }
    return 0;
}

/** */
char *yon_config_command_get_full(config_str command, int command_size){
    if (command && command_size>0){
        int final_size;
        config_str final = NULL;
        yon_char_parsed_add_or_create_if_exists(final,&final_size,command[0]);
        for (int i=1;i<command_size;i++){
            int parsed_size;
            config_str parsed = yon_char_parse(command[i],&parsed_size," ");
            int pos = yon_config_command_get_section_pos(command[i]);
            if (pos>-1){
                char *cur_string = "";
                for (int j=pos;j<parsed_size;j++){
                    char *temp = yon_char_unite(cur_string," ",parsed[j],NULL);
                    if (!yon_char_is_empty(cur_string)) free(cur_string);
                    cur_string = temp;
                }
                if (!yon_char_is_empty(cur_string)){
                    yon_char_parsed_add_or_create_if_exists(final,&final_size,cur_string);
                    free(cur_string);
                }
            }
            yon_char_parsed_free(parsed,parsed_size);
        }
        if (final_size>0){
            char *final_command = yon_char_parsed_to_string(final,final_size," -- get ");
            int pos = yon_char_check_element(final_command,"ubconfig", " ");
            if (pos&&yon_char_check_element(final_command,"-ea"," ")==0){
                int size=0;
                config_str parsed = yon_char_parse(final_command,&size," ");
                pos = yon_char_parsed_check_exist(parsed,size,"ubconfig");
                char *tmp = yon_char_unite(parsed[pos]," -ea",NULL);
                free(parsed[pos]);
                parsed[pos] = tmp;
                free(final_command);
                final_command = yon_char_parsed_to_string(parsed,size," ");
            }
            // char *temp = yon_char_replace(final_command,"ubconfig","ubconfig -ea");
            // free(final_command);
            // final_command = temp;
            yon_char_parsed_free(final,final_size);
        return final_command;
        }
    }
    return NULL;
}

config_str yon_config_command_get_parameters(const char *command, int *size){
    (*size)=0;
    if (yon_char_is_empty(command)) return NULL;

    int parsed_size;
    config_str parsed = yon_char_parse(command,&parsed_size," ");
    int pos = yon_config_command_get_section_pos(command);
    if (pos>-1){
        for (int i=0;i<pos+1;i++){
            parsed = yon_char_parsed_rip(parsed,&parsed_size,0);
        }
        if (parsed_size>0){
            (*size)=parsed_size;
            return parsed;
        }
    }
    return NULL;
}

int yon_config_command_check_parameter(const char *command,const char *parameter){
    int size;
    config_str parameters = yon_config_command_get_parameters(command,&size);
    for (int i=0;i<size;i++){
        if (!strcmp(parameters[i],parameter)){
            yon_char_parsed_free(parameters,size);
            return i;
        }
    }

    yon_char_parsed_free(parameters,size);
    return -1;
}

/**Возвращает позицию раздела в команде */
int yon_config_command_get_section_pos(const char *command){
    int size;
    config_str parsed = yon_char_parse(command,&size," ");
    int pos = -1;
    for (int i=0;i<size-1;i++){
        if (!strcmp(parsed[i],"get")||!strcmp(parsed[i],"set")||!strcmp(parsed[i],"remove")){
            pos = i+1;
            break;
        }
    }
    yon_char_parsed_free(parsed,size);
    return pos;
}

/**Возвращает раздел в команде */
char *yon_config_command_get_section(const char *command){
    int size;
    config_str parsed = yon_char_parse((char*)command,&size," ");
    int section_pos = yon_config_command_get_section_pos(command);
    if (section_pos==-1) return NULL;
    char *section = yon_char_new(parsed[section_pos]);
    yon_char_parsed_free(parsed,size);
    return section;
}

/**Возвращает позицию пути в команде */
int yon_config_command_get_path_pos(config_str parsed, int size){
    for (int i=0;i<size-1;i++){
        if (!strcmp(parsed[i],"--source")||!strcmp(parsed[i],"--target")){
            return i+1;
        }
    }
    return -1;
}

/**Возвращает путь из команды */
char *yon_config_command_get_path(const char *command){
    int size;
    config_str parsed = yon_char_parse((char*)command,&size," ");
    int section_pos = yon_config_command_get_path_pos(parsed,size);
    if (section_pos==-1) return NULL;
    char *section = yon_char_new(parsed[section_pos]);
    yon_char_parsed_free(parsed,size);
    return section;
}

char *config_last_load_command = NULL;

char *yon_config_get_last_command(){
    return(config_last_load_command);
}
void yon_config_set_last_command(char *command){
    config_last_load_command=yon_char_new(command);
}

int yon_config_import_string(YON_CONFIG_TYPE config_type, char *string){
    if (!strcmp(string,"(null)\n")) return 0;
    char *section = NULL;
        yon_char_remove_last_symbol(string,'\n');
        char *value = yon_char_new(string);
        char *parameter = yon_char_divide_search(value,"=",-1);
        if (parameter[0]=='['){
            section = yon_char_divide_search(parameter," ",-1);
            free(yon_char_divide(section,yon_char_find_last(section,'/')));
            yon_char_remove_last_symbol(section,']');
        }
        yon_char_remove_brackets(value);

        char *get_parameter = yon_char_unite("[",section,"]"," ", value,NULL);
        char *get_command = ubconfig_load_command_full("system",get_parameter);


        char *cur_data = config(parameter);
        int cur_ignore = yon_config_check_ignore(parameter);

        if (config_type==YON_CONFIG_DEFAULT){
            yon_config_register_default(parameter, get_command,value);
        }
        if ((cur_ignore&&value)||(!cur_ignore)){
            yon_config_register(parameter,get_command,value);
            // yon_config_set_section(parameter,section);
        }

        if (config_type==YON_CONFIG_DEFAULT){
            yon_config_set_ignore(parameter);
            yon_config_set_status(parameter,-2);
        } else {
            yon_config_default_remove(parameter);
            yon_config_set_status(parameter,0);
        }
}

int yon_config_load_config(YON_CONFIG_TYPE config_type, ...){
    if (config_type == YON_CONFIG_BOTH) return 0;

    char *current;
    va_list args;
    va_start(args,config_type);

    int commands_size;
    config_str commands = NULL;
    while ((current=va_arg(args,char*))){
        yon_char_parsed_add_or_create_if_exists(commands,&commands_size,current);
    }

    char *final_command = yon_config_command_get_full(commands,commands_size);
    yon_config_set_last_command(final_command);
    if (yon_char_is_empty(final_command)) return 0;
    int parameters_size;
    config_str parameters = yon_config_load(final_command,&parameters_size);
        // char *section = NULL;
        // if (!strstr(final_command," -ea ")){
        //     section = yon_config_command_get_section(final_command);
        // }
    for (int i=0;i<parameters_size;i++){
        if (!strcmp(parameters[i],"(null)\n")) continue;
        yon_config_import_string(config_type,parameters[i]);

    }
    return 1;
}

int yon_config_load_register(YON_CONFIG_TYPE config_type,char *section,char *parameter, ...){
    if (config_type!=YON_CONFIG_BOTH){
        if (__yon__config__strings){
            yon_dictionary_free_all((dictionary*)__yon__config__strings,NULL);
            __yon__config__strings=NULL;
        }
        va_list args;
        va_start(args,parameter);
        dictionary *sections = NULL;
        yon_dictionary_add_or_create_if_exists_with_data(sections,section,parameter);
        char *arg;

        while (arg=va_arg(args,char*)){
            char *key = va_arg(args,char*);
            if (sections&&yon_dictionary_get(&sections,arg)) sections->data=(void*)yon_char_unite(yon_dictionary_get_data(sections,char*)," ",key,NULL);
            else yon_dictionary_add_or_create_if_exists_with_data(sections,arg,key);
        }
        char *command=NULL;
        dictionary *dict;
        for_dictionaries(dict,sections){
            command = yon_char_unite(ubconfig_load_command_old,config_type==YON_CONFIG_GLOBAL ? " global get " : config_type==YON_CONFIG_LOCAL ? " system get " : " default get", dict->key," ", yon_dictionary_get_data(dict,char*),NULL);
            FILE *output = popen(command, "r");
            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);
                    char *final_str=yon_char_divide_search(str,"\n",-1);
                    if ((final_str[0]=='\''&&final_str[strlen(final_str)-1]=='\'')||(final_str[0]=='\"'&&final_str[strlen(final_str)-1]=='\"')){
                        final_str[strlen(final_str)-1] = '\0';
                        free(yon_char_divide(final_str,0));
                    }
                    
                        yon_config_parameter *cur_config = (config_type!=YON_CONFIG_DEFAULT? __yon__config__strings:__yon__config__default__strings);
                    dictionary *dicte = yon_dictionary_get((dictionary**)&cur_config,key);
                    if (!dicte){
                        yon_config_parameter_add_or_create_if_exists_with_data(cur_config,key,yon_char_new(final_str));
                    } else {
                        if (strcmp((char*)dicte->data,final_str)){
                            cur_config->data=final_str;
                        } else {
                            continue;
                        }
                    }
                    cur_config->flag1=0;
                    yon_config_remove_ignore(key);
                    if (config_type==YON_CONFIG_DEFAULT){
                        cur_config->flag1=-2;
                        yon_config_set_ignore(key);
                    }
                    cur_config->data_type=DICTIONARY_CHAR_TYPE;
                    cur_config->section=dict->key;
                }
            }
            free(command);
            fclose(output);
        }
        check_config
            return 1;
        else return 0;
    } else return -1;
}

void yon_config_compare_ignore_set(char *key, int status){
    dictionary *cur = yon_dictionary_get((dictionary**)&__yon__config__strings,key);
    if (cur){
        ((yon_config_parameter*)cur)->compare_ignore=!!status;
    }
}

int yon_config_compare_ignore_get(char *key){

    dictionary *cur = yon_dictionary_get((dictionary**)&__yon__config__strings,key);
    if (cur){
        return ((yon_config_parameter*)cur)->compare_ignore;
    }
    return 0;
}

int yon_config_remove_by_key(char *key){
    check_config{
        dictionary *dict = yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (dict){
            if (!yon_char_is_empty(dict->data)){
                yon_config_remove_ignore(dict->key);
                ((yon_config_parameter*)dict)->flag1=-1;
                dict->data="";
                return 1;
            }
        }
    }
    return 0;
}

int yon_config_remove_by_list(config_str keys, size_t size){
    int result = 0;
    check_config{
        for (size_t i = 0;i<size;i++){
            dictionary *dict = yon_dictionary_get((dictionary**)&__yon__config__strings,keys[i]);
            if (dict){
                if (!yon_char_is_empty(dict->data)){
                    yon_config_remove_ignore(dict->key);
                    ((yon_config_parameter*)dict)->flag1=-1;
                    dict->data="";
                    result=1;
                }
            }
        }
    }
    return result;
}

int yon_config_remove_by_args(char *key, ...){
    int result = 0;
    check_config{
        va_list args;
        va_start(args,key);
        char *cur_key = key;
        while (!yon_char_is_empty(cur_key)){
            dictionary *dict = yon_dictionary_get((dictionary**)&__yon__config__strings,cur_key);
            if (dict){
                if (!yon_char_is_empty(dict->data)){
                    yon_config_remove_ignore(dict->key);
                    ((yon_config_parameter*)dict)->flag1=-1;
                    dict->data="";
                    result=1;
                }
            }
            cur_key = va_arg(args,char*);
        }
        va_end(args);
    }
    return result;
}

int yon_config_clear_by_key(const char *key){
    check_config{
        dictionary *dict = yon_dictionary_get((dictionary**)&__yon__config__strings,(char*)key);
        if (dict){
            yon_config_remove_ignore((char*)key);
            __yon__config__strings = (yon_config_parameter*)yon_dictionary_rip(dict);
            return 1;
        }
    }
    return 0;
}

char *yon_config_get_by_subkey(const char *key, const char *subkey){
    
}

int yon_config_remove_element(char *key, char *delete_target, char *divider){
    check_config{
        int found = 0;
        yon_config_parameter *dict = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (dict){
            if (yon_char_is_empty(dict->data)) return 0; 
            char *temp = yon_char_remove_element((char*)dict->data,delete_target,divider);
            if (strcmp((char*)dict->data,temp)){
                if (!yon_char_is_empty((char*)dict->data)){
                    free(dict->data);
                }
                dict->data = temp;
                if (yon_char_is_empty(temp)){
                    dict->flag1 = -1;
                } else {
                    dict->flag1 = 1;
                }
            }
            return 1;
        }
        
    } else return 0;
}

int yon_config_remove_elements(char *key, char *delete_target, char *divider){
    check_config{
        int found = 0;
        yon_config_parameter *dict = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (dict){
        if (yon_char_is_empty(dict->data)) return 0; 
            char *temp = yon_char_remove_elements((char*)dict->data,delete_target,divider);
            if (!yon_char_is_empty(temp)){
                if (strcmp((char*)dict->data,temp)){
                    if (!yon_char_is_empty((char*)dict->data)) free(dict->data);
                    dict->data = temp;
                    dict->flag1=1;
                }
            } else {
                dict->data = NULL;
                dict->flag1=-1;
            }
            

            return 1;
        }
        
    } else return 0;
}

int yon_config_remove_elements_all(char *key, char *delete_target, char *divider){
    check_config{
        int found = 0;
        yon_config_parameter *dict = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (dict&&yon_char_is_empty(dict->data)) return 0; 
        if (dict&&yon_char_check_elements((char*)dict->data,delete_target,divider)){
            char *temp = yon_char_remove_elements((char*)dict->data,delete_target,divider);
            if (!yon_char_is_empty(temp)){
                if (strcmp((char*)dict->data,temp)){
                    if (!yon_char_is_empty((char*)dict->data)) free(dict->data);
                    dict->data = temp;
                    dict->flag1=1;
                }
            } else {
                dict->data = NULL;
                dict->flag1=-1;
            }
            

            return 1;
        }
        
    } else return 0;
}

int yon_config_append_element(char *key, char *append, char *divider){
    check_config{
        int found = 0;
        yon_config_parameter *dict = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (dict){
            if (!yon_char_check_elements((char*)dict->data,append,divider)){
                char *temp = yon_char_append_element((char*)dict->data,append,divider);
                if (!yon_char_is_empty((char*)dict->data)) free(dict->data);
                dict->data = temp;
                dict->flag1 = 1;
                yon_config_remove_ignore(key);
                return 1;
            }
        }
        
    }
    return 0;
}

int yon_config_append_elements(char *key, char *append, char *divider){
    check_config{
        int found = 0;
        yon_config_parameter *dict = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (dict){
            if (!yon_char_check_elements((char*)dict->data,append,divider)){
                char *temp = yon_char_append_elements((char*)dict->data,append,divider);
                if (!yon_char_is_empty((char*)dict->data)) free(dict->data);
                dict->data = temp;
                dict->flag1 = 1;
                yon_config_remove_ignore(key);
                return 1;
            }
        }
        
    }
    return 0;
}

int yon_config_force_append_element(char *key, char *append, char *divider){
    check_config{
        int found = 0;
        yon_config_parameter *dict = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (dict){
            char *temp = yon_char_force_append_element((char*)dict->data,append,divider);
            if (!yon_char_is_empty((char*)dict->data)) free(dict->data);
            dict->data = temp;
            dict->flag1 = 1;
            yon_config_remove_ignore(key);
            return 1;
        }
        
    } else return 0;
}

int yon_config_set_status(char *key, int status){
    check_config{
        if (!yon_char_is_empty(key)){
            if(yon_dictionary_get((dictionary**)&__yon__config__strings,key)){
                ((yon_config_parameter*)__yon__config__strings)->flag1=status;
                return 1;
            }
        }
    }
    return 0;
}

void yon_config_set_status_full(int status){
    check_config{
        for_config{
            ((yon_config_parameter*)temp)->flag1=status;
        }
    }
}

void *yon_config_get_by_key(char *key){
    check_config{
        dictionary *dict = NULL;
        for_dictionaries(dict, (dictionary*)__yon__config__strings){
            if (strcmp(dict->key,key)==0&&((yon_config_parameter*)dict)->flag1!=-1){
                return dict->data;
            }
        }
    }
    return NULL;
}

char *yon_config_default_get_by_key(char *key){
    check_default_config{
        dictionary *dict = NULL;
        for_dictionaries(dict, (dictionary*)__yon__config__default__strings){
            if (strcmp(dict->key,key)==0&&((yon_config_parameter*)dict)->flag1!=-1){
                return dict->data;
            }
        }
    }
    return NULL;
}

config_str yon_config_default_get_all_by_key(const char *key, int *size){
    (*size)=0;
    check_config{
        config_str ret_data=NULL;
        dictionary *dict = NULL;
        for_dictionaries(dict, (dictionary*)__yon__config__default__strings){
            if (strstr(dict->key,key)&&((yon_config_parameter*)dict)->flag1!=-1) {
                char *ret_string = yon_char_unite(dict->key,"=",(char*)dict->data,NULL);
                if (ret_data) ret_data = yon_char_parsed_append(ret_data,size,ret_string);
                else ret_data = yon_char_parsed_new(size,ret_string,NULL);
            }
        }
        return ret_data;
    }
    return NULL;
}

char *yon_config_get(char *key){
    check_config{
        char *final = yon_config_get_by_key(key);
        if (!final)
            final = yon_config_default_get_by_key(key);
        return final;
    }
    return NULL;
}

char *yon_config_get_section_for_key(char *key){
    check_config{
        for_config{
            if (!yon_char_is_empty(temp->key)){
                if (!strcmp(temp->key,key)){
                    return yon_char_new(((yon_config_parameter*)temp)->section);
                }
            }
        }
    }
}

char *yon_config_parameter_set_quotes(char *key){
    if (!strstr(key,"[")||strstr(key,"\'")) return yon_char_new(key);
    char *target = yon_char_new(key);
    char *first_part = yon_char_divide(target,strlen(target)-strlen(strstr(target,"[")));
    int end_pos = yon_char_find_last(target,']');
    char *key_str = yon_char_divide(target,end_pos);
    char *final = yon_char_unite(first_part,"['",key_str,"']",NULL);
    free(target);
    free(first_part);
    free(key_str);
    return final;
}

void *yon_config_get_all_by_key(char *key, int *size){
    (*size)=0;
    check_config{
        config_str ret_data=NULL;
        dictionary *dict = NULL;
        for_dictionaries(dict, (dictionary*)__yon__config__strings){
            if (strstr(dict->key,key)&&((yon_config_parameter*)dict)->flag1!=-1) {
                char *ret_string = yon_char_unite(dict->key,"=",(char*)dict->data,NULL);
                if (ret_data) ret_data = yon_char_parsed_append(ret_data,size,ret_string);
                else ret_data = yon_char_parsed_new(size,ret_string,NULL);
            }
        }
        return ret_data;
    }
    return NULL;
}

void *yon_config_get_all_keys_by_key(char *key, int *size){
    (*size)=0;
    check_config{
        config_str ret_data=NULL;
        dictionary *dict = NULL;
        for_dictionaries(dict, (dictionary*)__yon__config__strings){
            if (strstr(dict->key,key)/*&&((yon_config_parameter*)dict)->flag1!=-1*/) {
                char *ret_string = yon_char_new(dict->key);
                if (ret_data) ret_data = yon_char_parsed_append(ret_data,size,ret_string);
                else ret_data = yon_char_parsed_new(size,ret_string,NULL);
            }
        }
        return ret_data;
    }
    return NULL;
}

config_str yon_config_get_selection_by_key(int *size, ...){
    (*size)=0;
    check_config{
        va_list list;
        va_start(list,size);
        config_str ret_data=NULL;
        char *arg = NULL;
        while ((arg = va_arg(list,char*))){
            char *cur = yon_config_get_by_key(arg);
            char *parameter_string=NULL;
            if (!yon_char_is_empty(cur)){
                parameter_string = yon_char_unite(arg,"='",cur,"'",NULL);
                yon_char_parsed_add_or_create_if_exists(ret_data,size,parameter_string);
                free(parameter_string);
            }
        }
        return ret_data;
    }
    return NULL;
}

config_str yon_config_get_selection_by_key_no_ignored(int *size, ...){
    (*size)=0;
    check_config{
        va_list list;
        va_start(list,size);
        config_str ret_data=NULL;
        char *arg = NULL;
        while ((arg = va_arg(list,char*))){
            char *cur = yon_config_get_by_key(arg);
            char *parameter_string=NULL;
            if (!yon_char_is_empty(cur)&&!yon_config_check_ignore(cur)){
                parameter_string = yon_char_unite(arg,"='",cur,"'",NULL);
                yon_char_parsed_add_or_create_if_exists(ret_data,size,parameter_string);
                free(parameter_string);
            }
        }
        return ret_data;
    }
    return NULL;
}

void *yon_config_get_all_by_key_no_ignored(char *key, int *size){
    (*size)=0;
    check_config{
        config_str ret_data=NULL;
        dictionary *dict = NULL;
        for_dictionaries(dict, (dictionary*)__yon__config__strings){
            if (strstr(dict->key,key)&&((yon_config_parameter*)dict)->flag1!=-1&&yon_config_check_ignore(dict->key)==0) {
                char *ret_string = yon_char_unite(dict->key,"=",(char*)dict->data,NULL);
                if (ret_data) ret_data = yon_char_parsed_append(ret_data,size,ret_string);
                else ret_data = yon_char_parsed_new(size,ret_string,NULL);
            }
        }
        return ret_data;
    }
}


config_str yon_config_get_all_keys(int *size){
    *size=0;
    check_config{
        config_str final = NULL;
        for_config{
            if (!final) final = yon_char_parsed_new(size,temp->key,NULL);
            else final = yon_char_parsed_append(final,size,temp->key);
        }
        return final;
    }
    return NULL;
}

config_str yon_config_get_all_keys_no_ignored(int *size){
    *size=0;
    check_config{
        config_str final = NULL;
        for_config{
            if (!yon_config_check_ignore(temp->key)){
                if (!final) final = yon_char_parsed_new(size,temp->key,NULL);
                else final = yon_char_parsed_append(final,size,temp->key);
            }
        }
        return final;
    }
    return NULL;
}

int yon_config_set(char *key, void *data){
    check_config{
    yon_config_parameter *dict = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,key);
    if (!dict) return 0;
    dict->data=yon_char_new(data);
    dict->flag1=1;
    if (yon_dictionary_get(&__yon_config_ignored, dict->key)){
        __yon_config_ignored = yon_dictionary_rip(__yon_config_ignored);
    }
    return 1;
    } else return 0;
}

int yon_config_clean(){
    check_config{
        yon_dictionary_free_all((dictionary*)__yon__config__strings, NULL);
        __yon__config__strings = NULL;
        return 1;
    }
    else return 0;
}

int yon_config_default_remove(char *key){
    check_default_config{
        yon_config_parameter *default_parameter = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__default__strings,key);
        if (default_parameter){
            __yon__config__default__strings = (yon_config_parameter*)yon_dictionary_rip((dictionary*)default_parameter);
            return 1;
        }
        }
    return 0;
}

/// @brief Получение всех параметров отдельного раздела конфигурации
/// @param section_name Название раздела конфигурации
/// @param size размер финального массива
/// @return массив строк со всеми параметрами для запрашиваемого раздела
config_str yon_config_get_parameters_for_section(const char *section_name, int *size){
    (*size)=0;
    check_config{
        int parameters_size;
        config_str parameters = NULL;

        yon_config_parameter *parameter;
        for_dictionaries(parameter,__yon__config__strings){
            if (!strcmp(parameter->section,section_name)){
                yon_char_parsed_add_or_create_if_exists(parameters,&parameters_size,parameter->key);
            }
        }
        (*size)=parameters_size;
        return parameters;
    }
    return NULL;
}

enum YON_CONFIG_SAVED_TYPE yon_config_register(char *key,char *config_load, char *data){
    if (yon_char_is_empty(key)||yon_char_is_empty(config_load)) return YON_CONFIG_SAVED_ERROR;

    enum YON_CONFIG_SAVED_TYPE save_type = YON_CONFIG_SAVED_NEW;

    yon_config_parameter *current = NULL;
    check_config{
        current = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (!current){
            yon_config_parameter_add_or_create_if_exists_with_data(__yon__config__strings,key,data);
            current = (yon_config_parameter*)yon_dictionary_get_last((dictionary *)__yon__config__strings);
        } else if (!yon_char_is_empty(data)&&current->data&&!strcmp((char*)current->data,(char*)data)){
            save_type=YON_CONFIG_SAVED_EXIST;
            yon_config_remove_ignore(key);
            return save_type;
        } else {
            current->data = yon_char_new(data);
        }
    } else {
        yon_config_parameter_add_or_create_if_exists_with_data(__yon__config__strings,key,data);
        current = __yon__config__strings;
    }

    config_load = yon_char_new(config_load);

    current->data_type=DICTIONARY_CHAR_TYPE;
    current->load_command = config_load;
    current->section = yon_config_command_get_section(config_load);

    if (data){
        yon_config_remove_ignore(key);
        current->flag1=1;
    } else {
        yon_config_set_ignore(key);
        current->flag1 = 0;
    }
    switch(current->flag1){
        case -1: save_type = YON_CONFIG_SAVED_REMOVED; break;
        case 1: save_type = YON_CONFIG_SAVED_CHANGED; break;
        default: save_type = YON_CONFIG_SAVED_NEW; break;
    }
    return save_type;
}

enum YON_CONFIG_SAVED_TYPE yon_config_register_default(char *key,char *config_load, char *data){
    if (yon_char_is_empty(key)||yon_char_is_empty(config_load)) return YON_CONFIG_SAVED_ERROR;

    enum YON_CONFIG_SAVED_TYPE save_type = YON_CONFIG_SAVED_NEW;

    yon_config_parameter *current = NULL;
    check_default_config{
        current = (yon_config_parameter*)yon_dictionary_get((dictionary**)&__yon__config__default__strings,key);
        if (!current){
            yon_config_parameter_add_or_create_if_exists_with_data(__yon__config__default__strings,key,data);
            current = (yon_config_parameter*)yon_dictionary_get_last((dictionary *)__yon__config__default__strings);
        } else if (!yon_char_is_empty(data)&&!strcmp((char*)current->data,(char*)data)){
            save_type=YON_CONFIG_SAVED_EXIST;
            return save_type;
        } else {
            current->data = yon_char_new(data);
        }
    } else {
        yon_config_parameter_add_or_create_if_exists_with_data(__yon__config__default__strings,key,data);
        current = __yon__config__default__strings;
    }
    switch(current->flag1){
        case -1: save_type = YON_CONFIG_SAVED_REMOVED;
        case 1: save_type = YON_CONFIG_SAVED_CHANGED;
        default: save_type = YON_CONFIG_SAVED_NEW;
    }
    config_load = yon_char_new(config_load);

    current->data_type=DICTIONARY_CHAR_TYPE;
    current->load_command = config_load;
    current->section = yon_config_command_get_section(config_load);

    if (data){
        yon_config_remove_ignore(key);
        current->flag1=1;
    } else {
        yon_config_set_ignore(key);
        current->flag1 = 0;
    }
    return save_type;
}


config_str yon_config_load(char *command, int *str_len){
    (*str_len) = 0;
    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));
            output_strings[i] = NULL;
            output_strings[i] = yon_char_new(str);
            memset(str, 0, 4096);
            i++;
        }
    }
    if (output) 
        fclose(output);
    if (i>0){
    *str_len = i;
    return output_strings;
    } else{
        *str_len=-1;
        return NULL;
    }
}

config_str yon_config_load_file(FILE *file, int *str_len) {
    FILE *output = file;
    char **output_strings = NULL;
    int i = 0;
    char str[4096];

    output_strings = malloc(sizeof(char *));
    if (!output_strings) {
        *str_len = -1;
        return NULL;
    }

    while (fgets(str, sizeof(str), output)) {
        if (strcmp(str, "") != 0) {
            output_strings[i] = yon_char_new(str);
            if (!output_strings[i]) {
                *str_len = -1;
                for (int j = 0; j < i; j++) {
                    free(output_strings[j]);
                }
                free(output_strings);
                return NULL;
            }
            i++;
            output_strings = realloc(output_strings, sizeof(char *) * (i + 1));
            if (!output_strings) {
                *str_len = -1;
                for (int j = 0; j < i; j++) {
                    free(output_strings[j]);
                }
                free(output_strings);
                return NULL;
            }
        }
    }

    *str_len = i;
    return output_strings;
}

char *yon_config_parameter_wrap(char *parameter_key){
    if (!strstr(parameter_key,"[")) return yon_char_new(parameter_key);
    char *cur = NULL;
    int size;
    char *key = yon_config_parameter_get_key(parameter_key);
    
    char *temp = yon_char_new(parameter_key);
    char *param = yon_char_divide_search(temp,"[",-1);
    char *final = yon_char_unite(param,"['",key,"']",NULL);
    free(temp);
    free(key);
    free(param);
    return final;
}

char *yon_config_parameter_to_string(yon_config_parameter *parameter, int insert_section){
    if (parameter&&!yon_char_is_empty(parameter->key)){
        char *param_string = NULL;
        char *parameter_wrapped = yon_config_parameter_wrap(parameter->key);
        param_string = yon_char_unite(insert_section?parameter->section:"",insert_section?" ":"", parameter_wrapped,parameter->flag1==-1?NULL:"","=\'",yon_char_return_if_exist(parameter->data,""),"\'",NULL);
        return param_string;
    }
    return NULL;
}

config_str yon_config_get_load_parameters_by_list(int *size, config_str parameters, int params_size){
    va_list list;
    (*size)=0;
    config_str updated = NULL;
    int final_size;
    config_str final = NULL;
    char *current_str = NULL;
    for (int i=0;i<params_size;i++){
        current_str=parameters[i];
        for_config{
            if (!strcmp(temp->key,current_str)){
                int position = yon_char_parsed_find_element(final,*size,((yon_config_parameter*)temp)->section);
                if (position>=0){
                    char *quoted = yon_config_parameter_set_quotes(current_str);
                    char *string = yon_char_unite((final)[position]," ",quoted,NULL);
                    free((final)[position]);
                    (final)[position]=string;
                    free(quoted);

                } else {
                    char *quoted = yon_config_parameter_set_quotes(current_str);
                    char *string = yon_char_unite(temp->section," ",quoted,NULL);
                    yon_char_parsed_add_or_create_if_exists(final,size,string);
                    free(quoted);
                }
            }
        }
    }
    return final;
}

config_str yon_config_get_save_parameters_by_list(int *size, config_str parameters, int params_size){
    va_list list;
    (*size)=0;
    int removed_size;
    config_str removed = NULL;
    int updated_size;
    config_str updated = NULL;
    config_str final = NULL;
    char *current_str = NULL;
    for (int i=0;i<params_size;i++){
        int found = 0;
        current_str=parameters[i];
        for_config{
            if (!strcmp(temp->key,current_str)){
                found = 1;
                if (((yon_config_parameter*)temp)->flag1!=-2){
                    char *action = NULL;
                    config_str *current=NULL;
                    int *current_size=NULL;
                    switch (((yon_config_parameter*)temp)->flag1){
                        case -1:
                            action = "remove";
                            current = &removed;
                            current_size = &removed_size;
                            break;
                        case 1:
                            action = "set";
                            current = &updated;
                            current_size = &updated_size;
                            break;
                        default:
                            continue;
                    }
                    int position = yon_char_parsed_find_element(*current,*current_size,((yon_config_parameter*)temp)->section);
                    if (position>=0){
                        char *string = yon_char_unite((*current)[position]," ",yon_config_parameter_to_string((yon_config_parameter*)temp,0),NULL);
                        free((*current)[position]);
                        (*current)[position]=string;

                    } else {
                        char *string = yon_char_unite(action," ",yon_config_parameter_to_string((yon_config_parameter*)temp,1),NULL);
                        yon_char_parsed_add_or_create_if_exists(*current,current_size,string);
                    }
                }
            }
        }
        if (!found){
            if(removed&&temp){
                int position = yon_char_parsed_find_element(removed,removed_size,((yon_config_parameter*)temp)->section);
                if (position>=0){
                    char *string = yon_char_unite((removed)[position]," ",yon_config_parameter_to_string((yon_config_parameter*)temp,0),NULL);
                    free(removed[position]);
                    removed[position]=string;

                }
            } else if (temp){
                char *string = yon_char_unite("remove"," ",yon_config_parameter_to_string((yon_config_parameter*)temp,1),NULL);
                yon_char_parsed_add_or_create_if_exists(removed,&removed_size,string);
            }
        }
    }
    if (updated&&removed){
        final = yon_char_parsed_merge(updated,updated_size,removed,removed_size,size);
    } else if (updated&&!removed){
        final=updated;
        *size=updated_size;
    } else if (!updated&&removed){
        final=removed;
        *size=removed_size;
    }
    return final;
}

config_str yon_config_get_save_parameters_by_key(int *size,...){
    (*size)=0;
    check_config{
    va_list list;
    va_start(list,size);
    int removed_size;
    config_str removed = NULL;
    int updated_size;
    config_str updated = NULL;
    config_str final = NULL;
    char *current_str = NULL;

    yon_va_while(list,char*,current_str){
        for_config{
            if (!strcmp(temp->key,current_str)){
                if (((yon_config_parameter*)temp)->flag1!=-2){
                    char *action = NULL;
                    config_str *current=NULL;
                    int *current_size=NULL;
                    switch (((yon_config_parameter*)temp)->flag1){
                        case -1:
                            action = "remove";
                            current = &removed;
                            current_size = &removed_size;
                            break;
                        case 1:
                            action = "set";
                            current = &updated;
                            current_size = &updated_size;
                            break;
                    }
                    if (!current) continue;
                    int position = yon_char_parsed_find_element(*current,*current_size,((yon_config_parameter*)temp)->section);
                    if (position>=0){
                        char *string = yon_char_unite((*current)[position]," ",yon_config_parameter_to_string((yon_config_parameter*)temp,0),NULL);
                        free((*current)[position]);
                        (*current)[position]=string;

                    } else {
                        char *string = yon_char_unite(action," ",yon_config_parameter_to_string((yon_config_parameter*)temp,1),NULL);
                        yon_char_parsed_add_or_create_if_exists(*current,current_size,string);
                    }
                }
            }
        }
    }
    final = yon_char_parsed_merge(updated,updated_size,removed,removed_size,size);
    return final;
    }
    return NULL;
}

config_str yon_config_find_keys(char *target, int *size){
    (*size)=0;
    check_config{
        config_str final = NULL;
        yon_config_parameter *cur = NULL;
        for_dictionaries(cur,__yon__config__strings){
            if (strstr(cur->key,target)){
                yon_char_parsed_add_or_create_if_exists(final,size,cur->key);
            }
        }
        return final;
    }
    return NULL;
}

config_str yon_config_get_save_parameters(int *size){
    check_config{} else return NULL;
    (*size)=0;
    int removed_size=0;
    config_str removed = NULL;
    int updated_size=0;
    config_str updated = NULL;
    config_str final = NULL;
    for_config{
        if (((yon_config_parameter*)temp)->flag1!=0&&((yon_config_parameter*)temp)->flag1!=-2){
            char *action = NULL;
            config_str *current=NULL;
            int *current_size=NULL;
            switch (((yon_config_parameter*)temp)->flag1){
                case -1:
                    action = "remove";
                    current = &removed;
                    current_size = &removed_size;
                    break;
                case 1:
                    action = "set";
                    current = &updated;
                    current_size = &updated_size;
                    break;
            }
            int position = yon_char_parsed_find_element(*current,*current_size,((yon_config_parameter*)temp)->section);
            if (position>=0){
                char *string = yon_char_unite((*current)[position]," ",yon_config_parameter_to_string((yon_config_parameter*)temp,0),NULL);
                free((*current)[position]);
                (*current)[position]=string;

            } else {
                char *string = yon_char_unite(action," ",yon_config_parameter_to_string((yon_config_parameter*)temp,1),NULL);
                yon_char_parsed_add_or_create_if_exists(*current,current_size,string);
            }
        }
    }
    final = yon_char_parsed_merge(updated,updated_size,removed,removed_size,size);
    return final;
}

char *yon_config_save_simple(YON_CONFIG_TYPE target, char *path){
    int parameters_size=0;
    config_str parameters=yon_config_get_save_parameters(&parameters_size);
    if (parameters){
        yon_char_parsed_prepend_strings(parameters,parameters_size,ubconfig_set_command(path));
        char *final_command = yon_char_parsed_to_string(parameters,parameters_size,";");
        FILE *file = popen(final_command,"r");
        if (file){
                int file_size=0;
                config_str file_output = yon_config_load_file(file,&file_size);
                if (file_output){
                    char *output_string = yon_char_parsed_to_string(file_output,file_size,"");
                    yon_char_parsed_free(file_output,file_size);
                    char *final_string = yon_char_unite(final_command,"\n",output_string,NULL);
                    free(output_string);
                    if (!yon_char_is_empty(final_string)){
                        return final_string;
                    }
                } else {
                    yon_char_parsed_free(file_output,file_size);
                }
                fclose(file);
            }
    }
    return NULL;
}

char *yon_config_save_list_simple(config_str parameters_keys, size_t size, char *path){
    if (yon_char_is_empty(path)) return 0;
    check_config{
        int parameters_size=0;
        config_str parameters = yon_config_get_save_parameters_by_list(&parameters_size,parameters_keys,size);
        if (parameters&&parameters_size){
            char *command_parameters = yon_char_parsed_to_string(parameters,parameters_size," -- ");
            char *command = yon_char_unite(ubconfig_dull_command,"--target ",path," ", command_parameters,NULL);
            FILE *file = popen(command,"r");
            if (file){
                int file_size=0;
                config_str file_output = yon_config_load_file(file,&file_size);
                if (file_output){
                    char *output_string = yon_char_parsed_to_string(file_output,file_size,"");
                    yon_char_parsed_free(file_output,file_size);
                    char *final_string = yon_char_unite(command,"\n",output_string,NULL);
                    free(output_string);
                    if (!yon_char_is_empty(final_string)){
                        return final_string;
                    }
                } else {
                    yon_char_parsed_free(file_output,file_size);
                }
                fclose(file);
            }
            
        }
    }
    return NULL;
}


char *yon_config_save_args_simple(char *path, ...){
    if (yon_char_is_empty(path)) return 0;
    check_config{
        va_list args;
        va_start(args,path);
        int size = 0;
        config_str params = NULL;
        char *cur = NULL;
        while ((cur = va_arg(args,char*))){
            yon_char_parsed_add_or_create_if_exists(params,&size,cur);
        }
        int parameters_size=0;
        config_str parameters = yon_config_get_save_parameters_by_list(&parameters_size,params,size);
        yon_char_parsed_free(params,size);
        if (parameters&&parameters_size){
            char *command_parameters = yon_char_parsed_to_string(parameters,parameters_size," -- ");
            char *command = yon_char_unite(ubconfig_dull_command,"--target ",path," ", command_parameters,NULL);
            FILE *file = popen(command,"r");
            if (file){
                int file_size=0;
                config_str file_output = yon_config_load_file(file,&file_size);
                if (file_output){
                    char *output_string = yon_char_parsed_to_string(file_output,file_size,"");
                    yon_char_parsed_free(file_output,file_size);
                    char *final_string = yon_char_unite(command,"\n",output_string,NULL);
                    free(output_string);
                    if (!yon_char_is_empty(final_string)){
                        fclose(file);
                        return final_string;
                    }
                } else {
                    yon_char_parsed_free(file_output,file_size);
                }
                fclose(file);
            }
        }
    }
    return NULL;
}

int yon_config_update_by_key(char *key){
    if (yon_char_is_empty(key)) return 0;
    check_config{
        dictionary *current = yon_dictionary_get((dictionary**)&__yon__config__strings,key);
        if (!current) return 0;
        if (current->data) free(current->data);
        current->data = NULL;
        int size=0;
        yon_config_remove_by_key(key);
        char *command = yon_config_parameter_get_load_command(key);
        config_str new_param = yon_config_load(command,&size);
        if (size&&!yon_char_is_empty(new_param[0])&&strcmp(new_param[0],"(null)\n")){
            yon_char_remove_last_symbol(new_param[0],'\n');
            current->data = yon_char_new(new_param[0]);
            ((yon_config_parameter*)current)->flag1=0;
            yon_config_set_status(key,0);
            return 1;
        }
    }
    return 0;
}

int yon_config_update_by_list(char *config_path, config_str keys, size_t size){
    if (!size||!keys) return 0;
    check_config{
        int params_size=0;
        yon_config_remove_by_list(keys,size);
        config_str parameters = yon_config_get_load_parameters_by_list(&params_size,keys,size);
        if (params_size&&parameters){
            char *path = config_path;
            char *parameters_str = yon_char_parsed_to_string(parameters,params_size," ");
            char *command = yon_char_unite(ubconfig_load_command(path), parameters_str, NULL);
            yon_config_load_config(YON_CONFIG_CUSTOM,command,NULL);
        }
    }
    return 0;
}

int yon_config_update_by_args(char *config_path, ...){
    check_config{
        int size=0;
        config_str keys = NULL; 
        va_list args;
        va_start(args,config_path);
        char *cur_key = NULL;
        while((cur_key = va_arg(args,char*))){
            yon_char_parsed_add_or_create_if_exists(keys,&size,cur_key);
            yon_config_remove_by_key(cur_key);

        }
        int params_size=0;
        config_str parameters = yon_config_get_load_parameters_by_list(&params_size,keys,size);
        if (params_size&&parameters){
            char *path = config_path;
            char *parameters_str = yon_char_parsed_to_string(parameters,params_size," -- get ");
            char *command = yon_char_unite(ubconfig_load_command(path), parameters_str, NULL);
            yon_config_load_config(YON_CONFIG_CUSTOM,command,NULL);
        }
    }
    return 0;
}

char *yon_config_parameter_prepare_command(char *command, char *path, char *section, char *parameter){
    if (!yon_char_is_empty(command)){
        int size=0;
        config_str parsed = yon_char_parse(command,&size," ");
        int source_pos=yon_char_parsed_check_exist(parsed,size,"--source");
        int get_pos = yon_char_parsed_check_exist(parsed,size,"get");
        if (source_pos==-1) {
            source_pos = yon_char_parsed_check_exist(parsed,size,"--target");
            get_pos = yon_char_parsed_check_exist(parsed,size,"set");
        }
        if (yon_char_is_empty(path)){
            if (source_pos>-1&&size>source_pos+1){
                free(parsed[source_pos]);
                parsed[source_pos]=yon_char_new("");
                free(parsed[source_pos+1]);
                parsed[source_pos+1]=yon_char_new("");
            }
        } else if (path){
            if (source_pos>-1&&size>source_pos+1){
                free(parsed[source_pos+1]);
                parsed[source_pos+1]=yon_char_new(path);
            }
        }
        if (section){
            if (size>get_pos+1){
                free(parsed[get_pos+1]);
                parsed[get_pos+1]=yon_char_new(section);
            }
        }
        if (parameter){
            if (size>=get_pos+2){
                config_str temp = yon_char_parsed_copy(parsed,get_pos+2);
                yon_char_parsed_free(parsed,size);
                parsed = temp;
                size=get_pos+2;
                yon_char_parsed_add_or_create_if_exists(parsed,&size,parameter);
            }
        }
        char *temp = yon_char_new("ubconfig -ea");
        free(parsed[0]);
        parsed[0]=temp;
        char *final = yon_char_parsed_to_string(parsed,size," ");
        yon_char_parsed_free(parsed,size);
        return final;
    }
    return NULL;
}

int yon_config_save_registered(char *path){
    check_config{
        dictionary *dct;
        dictionary *sections_add=NULL;
        dictionary *sections_remove=NULL;
        for_dictionaries(dct,(dictionary*)__yon__config__strings){
            if (((yon_config_parameter*)dct)->flag1==1){
                if (dct->data&&!yon_char_is_empty(yon_dictionary_get_data(dct,char*))){
                    ((yon_config_parameter*)dct)->flag1=0;
                    if (sections_add&&yon_dictionary_get(&sections_add,((yon_config_parameter*)dct)->section)) sections_add->data=(void*)yon_char_unite(yon_dictionary_get_data(sections_add,char*)," ",dct->key,"=\'",yon_dictionary_get_data(dct,char*),"\'",NULL);
                    else yon_dictionary_add_or_create_if_exists_with_data(sections_add,((yon_config_parameter*)dct)->section,yon_char_unite (ubconfig_save_command,path ? yon_char_append(" --target ",path):"", " set ", ((yon_config_parameter*)dct)->section, " ",dct->key,"=\'",yon_dictionary_get_data(dct,char*),"\'",NULL));
                }
            } else if (((yon_config_parameter*)dct)->flag1==-1){
                if (dct->data&&yon_char_is_empty(yon_dictionary_get_data(dct,char*))){
                    ((yon_config_parameter*)dct)->flag1=0;
                    if (sections_remove&&yon_dictionary_get(&sections_remove,((yon_config_parameter*)dct)->section)) sections_remove->data=(void*)yon_char_unite(yon_dictionary_get_data(sections_remove,char*)," ",dct->key,NULL);
                    else yon_dictionary_add_or_create_if_exists_with_data(sections_remove,((yon_config_parameter*)dct)->section,yon_char_unite (ubconfig_save_command,path ? yon_char_append(" --target ",path):"", " remove ", ((yon_config_parameter*)dct)->section, " ",dct->key,NULL));
                    yon_dictionary_rip(dct);
                }
            }
        }
        if (sections_add)
        for_dictionaries(dct,sections_add){
            char *command = yon_dictionary_get_data(dct,char*);
            yon_launch(command);
        }
            yon_dictionary_free_all(sections_add,free);
        if (sections_remove)
        for_dictionaries(dct,sections_remove){
            char *command = yon_dictionary_get_data(dct,char*);
            yon_launch(command);
        }
            yon_dictionary_free_all(sections_remove,free);
        if (sections_add||sections_remove)
            return 1;
        else return 0;
    } else return 0;
}

int yon_config_force_save_registered(char *path){
    check_config{
        dictionary *dct;
        dictionary *sections_add=NULL;
        dictionary *sections_remove=NULL;
        for_dictionaries(dct,(dictionary*)__yon__config__strings){
            if (dct->data&&strcmp(yon_dictionary_get_data(dct,char*),"")!=0){
                if (((yon_config_parameter*)dct)->flag1==1||((yon_config_parameter*)dct)->flag1==0){
                    if (sections_add&&yon_dictionary_get(&sections_add,((yon_config_parameter*)dct)->section)) sections_add->data=(void*)yon_char_unite(yon_dictionary_get_data(sections_add,char*)," ",dct->key,"=\'",yon_dictionary_get_data(dct,char*),"\'",NULL);
                    else yon_dictionary_add_or_create_if_exists_with_data(sections_add,((yon_config_parameter*)dct)->section,yon_char_unite (ubconfig_save_command,path ? yon_char_append(" --target ",path):"", " set ", ((yon_config_parameter*)dct)->section, " ",dct->key,"=\'",yon_dictionary_get_data(dct,char*),"\'",NULL));
                } else if (((yon_config_parameter*)dct)->flag1==-1){
                    if (sections_remove&&yon_dictionary_get(&sections_remove,((yon_config_parameter*)dct)->section)) sections_remove->data=(void*)yon_char_unite(yon_dictionary_get_data(sections_remove,char*)," ",dct->key,NULL);
                    else yon_dictionary_add_or_create_if_exists_with_data(sections_remove,((yon_config_parameter*)dct)->section,yon_char_unite (ubconfig_save_command,path ? yon_char_append(" --target ",path):"", " remove ", ((yon_config_parameter*)dct)->section, " ",dct->key,NULL));
                }
            }
        }
        if (sections_add)
        for_dictionaries(dct,sections_add){
            char *command = yon_dictionary_get_data(dct,char*);
            yon_launch(command);
        }
        if (sections_remove)
        for_dictionaries(dct,sections_remove){
            char *command = yon_dictionary_get_data(dct,char*);
            yon_launch(command);
        }


        return 1;
    } else return 1;
}

config_str yon_config_get_all(int *size){
        *size = 0;
    check_config{
        *size = 1;
        config_str conf = NULL; 
        dictionary *dict = NULL;
        for_dictionaries(dict,(dictionary*)__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));
        conf[*size-1] = NULL;
        (*size)=(*size)-1;
        return conf;
    } else return NULL;
}

config_str yon_config_get_all_modified(int *size){
        *size = 0;
    check_config{
        config_str parameters = NULL;
        dictionary *dict;
        for_dictionaries(dict,(dictionary*)__yon__config__strings){
            yon_config_parameter *param = (yon_config_parameter*)dict;
            if (param->flag1==1||param->flag1==-1){
                char *str = yon_char_unite(param->key,"=",(char*)param->data,NULL);
                yon_char_parsed_add_or_create_if_exists(parameters,size,str);
                free(str);
            }
        }
        return parameters;
    }
    return NULL;
}

config_str yon_config_get_all_no_ignored(int *size){
    check_config{
        *size = 1;
        config_str conf = NULL; 
        dictionary *dict = NULL;
        for_dictionaries(dict,(dictionary*)__yon__config__strings){
            if (yon_config_check_ignore(dict->key)==0){
                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));
        conf[*size-1] = NULL;
        (*size)=(*size)-1;
        return conf;
    } else return 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;
}

int yon_config_change_key(char *target, char *key){
    if (!yon_char_is_empty(target)&&!yon_char_is_empty(key)){
    dictionary *dict = yon_dictionary_get((dictionary**)&__yon__config__strings,target);
    if (!dict) return 0;
    free(dict->key);
    dict->key = yon_char_new(key);
    }
    return 0;
}

char *yon_config_parameter_get_key(char *parameter_string){
    char *key = yon_char_new(parameter_string);
    char *cut_text = strstr(key,"[");
    if (cut_text&&strstr(key,"]")){
        memcpy(key,key+(strlen(key)-strlen(cut_text))+1,strlen(cut_text));
        // free(yon_char_divide_search(key,"[",-1));
        yon_char_remove_last_symbol(key,']');
    }
    return key;
}

int yon_config_move_before(char *parameter, char *target){
    dictionary *parameter_dict = yon_dictionary_get((dictionary**)&__yon__config__strings,parameter);
    dictionary *target_dict = yon_dictionary_get((dictionary**)&__yon__config__strings,target);
    if (!parameter_dict||!target_dict) return 0;
    dictionary *pnext = parameter_dict->next;
    dictionary *pprev = parameter_dict->prev;

    if (pnext)
        pnext->prev = pprev;
    if (pprev)
        pprev->next = pnext;

    dictionary *tprev = target_dict->prev;

    if (tprev)
        tprev->next = parameter_dict;
    target_dict->prev = parameter_dict;
    parameter_dict->next=target_dict;
    parameter_dict->prev=tprev;
    return 1;
}

int yon_config_move_after(char *parameter, char *target){
    dictionary *parameter_dict = yon_dictionary_get((dictionary**)&__yon__config__strings,parameter);
    dictionary *target_dict = yon_dictionary_get((dictionary**)&__yon__config__strings,target);
    if (!parameter_dict||!target_dict) return 0;
    dictionary *pnext = parameter_dict->next;
    dictionary *pprev = parameter_dict->prev;

    if (pnext)
        pnext->prev = pprev;
    if (pprev)
        pprev->next = pnext;

    dictionary *tnext = target_dict->next;

    if (tnext)
        tnext->prev = parameter_dict;
    target_dict->next = parameter_dict;
    parameter_dict->next=tnext;
    parameter_dict->prev=target_dict;
    return 1;
}

void yon_config_to_default(){
    yon_config_clean();
    yon_config_parameter *dict;
    for_dictionaries(dict,__yon__config__default__strings){
        yon_config_register(dict->key,dict->load_command,dict->data);
    }
}

// Custom config


#define yon_config_custom_parameter_add_or_create_if_exists_with_data(dict,key,value)   {if (dict){\
                                                                                    yon_config_parameter *dct = (yon_config_parameter *)yon_dictionary_get((dictionary**)&dict,key);\
                                                                                    if (dct) {\
                                                                                        dict=(yon_config_custom*)dct;\
                                                                                        ((yon_config_parameter *)dict)->data=value;\
                                                                                        }\
                                                                                        else{\
                                                                                            dict=(yon_config_custom*)yon_config_parameter_append_with_data((yon_config_parameter *)dict,key,value);\
                                                                                        }\
                                                                                    }\
                                                                                    else dict=(yon_config_custom*)yon_config_parameter_new_with_data(key,value);}

yon_config_custom *yon_config_custom_new(){
    yon_config_custom *custom = malloc(sizeof(yon_config_custom));
    memset(custom,0,sizeof(yon_config_custom));
    ((yon_config_parameter*)custom)->first = (yon_config_parameter*)custom;
    return custom;
}

int yon_config_custom_import_string(yon_config_custom **target, char *string){
    if (!strcmp(string,"(null)\n")) return 0;
    char *section = NULL;
        yon_char_remove_last_symbol(string,'\n');
        char *value = yon_char_new(string);
        char *parameter = yon_char_divide_search(value,"=",-1);
        if (parameter[0]=='['){
            section = yon_char_divide_search(parameter," ",-1);
            free(yon_char_divide(section,yon_char_find_last(section,'/')));
            yon_char_remove_last_symbol(section,']');
        }
        yon_char_remove_brackets(value);

        char *get_parameter = yon_char_unite("[",section,"]"," ", value,NULL);
        char *get_command = ubconfig_load_command_full("system",get_parameter);


        char *cur_data = config(parameter);

        if (value){
            yon_config_custom_register(target,parameter,get_command,value);
            // yon_config_set_section(parameter,section);
        }
}

int yon_config_custom_load_config(yon_config_custom **target, ...){

    char *current;
    va_list args;
    va_start(args,target);

    int commands_size;
    config_str commands = NULL;
    while ((current=va_arg(args,char*))){
        yon_char_parsed_add_or_create_if_exists(commands,&commands_size,current);
    }

    char *final_command = yon_config_command_get_full(commands,commands_size);
    yon_config_set_last_command(final_command);
    if (yon_char_is_empty(final_command)) return 0;
    int parameters_size;
    config_str parameters = yon_config_load(final_command,&parameters_size);
    for (int i=0;i<parameters_size;i++){
        if (!strcmp(parameters[i],"(null)\n")) continue;
        yon_config_custom_import_string(target,parameters[i]);

    }
    return 1;
}

enum YON_CONFIG_SAVED_TYPE yon_config_custom_register(yon_config_custom **target, char *key,char *config_load, char *data){
    if (yon_char_is_empty(key)||yon_char_is_empty(config_load)) return YON_CONFIG_SAVED_ERROR;

    enum YON_CONFIG_SAVED_TYPE save_type = YON_CONFIG_SAVED_NEW;

    yon_config_parameter *current = NULL;
    if (*target){
        current = (yon_config_parameter*)yon_dictionary_get((dictionary**)target,key);
        if (!current &&*target&&!yon_char_is_empty(((yon_config_parameter*)*target)->first->key)) current=((yon_config_parameter*)target)->first;
        if (!current){
            yon_config_custom_parameter_add_or_create_if_exists_with_data(*target,key,data);
            current = (yon_config_parameter*)yon_dictionary_get_last((dictionary *)*target);
        } else if (!yon_char_is_empty(data)&&current->data&&!strcmp((char*)current->data,(char*)data)){
            save_type=YON_CONFIG_SAVED_EXIST;
            return save_type;
        } else {
            current->data = yon_char_new(data);
        }
    } else {
        yon_config_custom_parameter_add_or_create_if_exists_with_data(*target,key,data);
        current = (yon_config_parameter*)*target;
    }

    config_load = yon_char_new(config_load);

    current->data_type=DICTIONARY_CHAR_TYPE;
    current->load_command = config_load;
    current->section = yon_config_command_get_section(config_load);

    if (data){
        current->flag1=1;
    } else {
        current->flag1 = 0;
    }
    switch(current->flag1){
        case -1: save_type = YON_CONFIG_SAVED_REMOVED; break;
        case 1: save_type = YON_CONFIG_SAVED_CHANGED; break;
        default: save_type = YON_CONFIG_SAVED_NEW; break;
    }
    return save_type;
}

int yon_config_custom_clean(yon_config_custom *target){
    if (target){
        yon_dictionary_free_all((dictionary*)target, NULL);
        return 1;
    }
    return 0;
}

config_str yon_config_get_save_parameters_by_custom_config(yon_config_custom *target, int *size, config_str parameters, int params_size){
    va_list list;
    (*size)=0;
    int removed_size;
    config_str removed = NULL;
    int updated_size;
    config_str updated = NULL;
    config_str final = NULL;
    char *current_str = NULL;
    for (int i=0;i<params_size;i++){
        int found = 0;
        current_str=parameters[i];
        yon_config_parameter *temp;
        for_dictionaries(temp,((yon_config_parameter*)target)){
            if (!strcmp(temp->key,current_str)){
                found = 1;
                if (((yon_config_parameter*)temp)->flag1!=-2){
                    char *action = NULL;
                    config_str *current=NULL;
                    int *current_size=NULL;
                    switch (((yon_config_parameter*)temp)->flag1){
                        case -1:
                            action = "remove";
                            current = &removed;
                            current_size = &removed_size;
                            break;
                        case 1:
                            action = "set";
                            current = &updated;
                            current_size = &updated_size;
                            break;
                        default:
                            continue;
                    }
                    int position = yon_char_parsed_find_element(*current,*current_size,((yon_config_parameter*)temp)->section);
                    if (position>=0){
                        char *string = yon_char_unite((*current)[position]," ",yon_config_parameter_to_string((yon_config_parameter*)temp,0),NULL);
                        free((*current)[position]);
                        (*current)[position]=string;

                    } else {
                        char *string = yon_char_unite(action," ",yon_config_parameter_to_string((yon_config_parameter*)temp,1),NULL);
                        yon_char_parsed_add_or_create_if_exists(*current,current_size,string);
                    }
                }
            }
        }
        if (!found){
            if(removed&&temp){
                int position = yon_char_parsed_find_element(removed,removed_size,((yon_config_parameter*)temp)->section);
                if (position>=0){
                    char *string = yon_char_unite((removed)[position]," ",yon_config_parameter_to_string((yon_config_parameter*)temp,0),NULL);
                    free(removed[position]);
                    removed[position]=string;

                }
            } else if (temp){
                char *string = yon_char_unite("remove"," ",yon_config_parameter_to_string((yon_config_parameter*)temp,1),NULL);
                yon_char_parsed_add_or_create_if_exists(removed,&removed_size,string);
            }
        }
    }
    if (updated&&removed){
        final = yon_char_parsed_merge(updated,updated_size,removed,removed_size,size);
    } else if (updated&&!removed){
        final=updated;
        *size=updated_size;
    } else if (!updated&&removed){
        final=removed;
        *size=removed_size;
    }
    return final;
}

int yon_config_custom_swap(yon_config_custom **target){
    yon_config_clean();
    yon_config_parameter *temp = __yon__config__strings;
    __yon__config__strings = (yon_config_parameter *)*target;
    *target = (yon_config_custom *)__yon__config__strings;
}

int yon_config_custom_apply(yon_config_custom **target){
    yon_config_clean();
    if (*target){
        __yon__config__strings = ((yon_config_parameter *)*target)->first;
    }
    *target=NULL;
}