#include "libublsettings.h"

unsigned int yon_str_hash(const char *str) {
    unsigned int hash = 5381;
    for (; *str != '\0'; str++) {
        hash = (hash << 5) + hash + (unsigned char)(*str);
    }
    return hash;
}

//\
=====================================================================

yon_hash *yon_hash_new(int size, unsigned int(*hash_func)(const char *)){
    yon_hash *hash = malloc(sizeof(yon_hash));
    memset(hash,0,sizeof(yon_hash));
    hash->data = malloc(sizeof(yon_hash_element)*size);
    memset(hash->data,0,sizeof(yon_hash_element)*size);
    hash->size = size;
    hash->hash_func = hash_func;
    return hash;
}

yon_hash_element *yon_hash_element_new(const char *key, void *data){
    yon_hash_element *element = malloc(sizeof(yon_hash_element));
    memset(element,0,sizeof(yon_hash_element));
    element->key = yon_char_new(key);
    element->data = data;
    element->first = (struct yon_hash_element*)element;
    return element;
}

int yon_hash_insert(yon_hash *target, const char *key, void *data){
    if (target&&target->hash_func&&!yon_char_is_empty(key)&&data){
        unsigned int hash = target->hash_func(key)%target->size;
        if (target->data&&target->data[hash]){
            yon_hash_element *element = yon_hash_element_new(key,data);
            yon_hash_element *last = (yon_hash_element *)yon_dictionary_get_last((dictionary*)target->data[hash]);
            last->next=(struct yon_hash_element*)element;
            element->prev=(struct yon_hash_element*)last;
            element->first=(struct yon_hash_element*)last->first;
            return 1;
        } else {
            // target->data[hash] = malloc(sizeof(yon_hash_element*));
            target->data[hash] = yon_hash_element_new(key,data);
            return 1;
        }
    }
    return 0;
}

int yon_hash_remove(yon_hash *target, const char *key){
    if (target&&target->hash_func&&!yon_char_is_empty(key)){
        unsigned int hash = target->hash_func(key)%target->size;
        if (target->data[hash]){
                dictionary *dict = yon_dictionary_get((dictionary**)&target->data[hash],(char*)key);
                target->data[hash]=(yon_hash_element*)yon_dictionary_rip(dict);
        }
    }
    return 0;
}

void *yon_hash_lookup(yon_hash *target, const char *key){
    if (target&&target->size>0&&!yon_char_is_empty(key)){
        unsigned int hash = target->hash_func(key)%target->size;
        if (target->data[hash]){
            dictionary *dict = yon_dictionary_get((dictionary**)&target->data[hash],(char*)key);
            return yon_dictionary_get_data(dict,void*);
        }
    }
    return NULL;
}

int yon_hash_contains(yon_hash *target, const char *key){
    if (target&&!yon_char_is_empty(key)){
        unsigned int hash = target->hash_func(key)%target->size;
        if (target->data[hash]){
            if (yon_dictionary_get((dictionary**)&target->data[hash],(char*)key)) return 1;
        }
    }
    return 0;
}

int yon_hash_add(yon_hash *target,const char *key){
    if (target&&target->size>0&&!yon_char_is_empty(key)){
        unsigned int hash = target->hash_func(key)%target->size;
        
        if (target->data[hash]){
            yon_hash_element *element = yon_hash_element_new(key,NULL);
            yon_hash_element *last = (yon_hash_element *)yon_dictionary_get_last((dictionary*)target->data[hash]);
            last->next=(struct yon_hash_element*)element;
            element->prev=(struct yon_hash_element*)last;
            element->first=(struct yon_hash_element*)last->first;
            return 1;
        } else {
            target->data = malloc(sizeof(yon_hash_element*));
            target->data[0] = yon_hash_element_new(key,NULL);
            return 1;
        }
    }
}