#include "elements.h"
#include "life.h"
//lower==more fuzzing
#define FUZZ_RATE 1024
//return the element from the list, allocating it as needed
static element_list_t* get_element_key(element_list_head_t* list, int key, int default_value);

void init_elements(element_list_head_t* list, int max_size){
    
    list->head = NULL;
    list->tail = NULL;
    if (max_size == 0){
        list->max_size = INT_MAX;
    } else {
        list->max_size = max_size;
    }
    list->list_size = 0;
    
}

static element_list_t* get_element_key(element_list_head_t* list, int key, int default_value){
    element_list_t* l = list->head;
    element_list_t* smallest = l;
    int i;
    //walk the list
    for (i = 0; i < list->max_size && l != NULL; i++){
        if (key == l->key){
            break;
        }
        if (smallest->value > l->value){
            smallest = l;
        }
        l = l->next;
    }
    
    if (l == NULL){
        //nothing found
        if (list->list_size < list->max_size){
            //allocate it
            l = malloc(sizeof(element_list_t));
            l->key = key;
            l->value = default_value;
            l->next = NULL;
            list->list_size++;
            if (list->head == NULL){//empty list, add it
                list->head = l;
                list->tail = l;
            } else {//stick it at the end
                list->tail->next = l;
                list->tail = l;
            }
        } else {
            //just replace the smallest and return
            smallest->key = key;
            smallest->value = default_value;
            return smallest;
        }
    }
    return l;

}

//returns the value associated with the key in the list
int get_element(element_list_head_t* list, int key, int default_value){
    element_list_t* element;
    element = get_element_key(list, key, default_value);
    return element->value;
}

//frees the list and all resources associated with it
void destroy_elements(element_list_head_t* list){
    element_list_t* l = list->head;
    element_list_t* prev;
    while (l != NULL){
        prev = l;
        l = l->next;
        free(prev);
    }
    list->head = NULL;
    list->tail = NULL;
}

//add an element to the list
int set_element(element_list_head_t* list, int key, int value){
    element_list_t* element;
    element = get_element_key(list, key, value);
    element->value = value;
    return element->value;
}

void copy_element_list(element_list_head_t* dst, element_list_head_t* src){
    destroy_elements(dst);
    element_list_t* s = src->head;
    element_list_t* d;
    dst->max_size = src->max_size;
    dst->list_size = src->list_size;
    dst->head = NULL;
    dst->tail = NULL;
    if (src->head != NULL){
        dst->head = malloc(sizeof(element_list_t));
        dst->tail = dst->head;
        memcpy(dst->head, src->head, sizeof(element_list_t));
        d = dst->head;
        
        //and copy everything   
        while (s->next != NULL){
            d->next = malloc(sizeof(element_list_t));
            dst->tail = d->next;
            memcpy(d->next, s->next, sizeof(element_list_t));
            d = d->next;
            s = s->next;
        }
    }//else, nothing to copy

}

int add_element(element_list_head_t* list, int key, int change){
    element_list_t* element;
    element = get_element_key(list, key, 0);
    element->value += change;
    return element->value;
}

int add_element_max(element_list_head_t* list, int key, int change, int max){
    element_list_t* element;
    element = get_element_key(list, key, 0);
    element->value += change;
    if (element->value > max){
        element->value = max;
    } else if(element->value < -max) {
        element->value = -max;
    }
    return element->value;
}
void fuzz_elements(element_list_head_t* list){
    element_list_t* l = list->head;
    while (l != NULL){
        if (rand_int() % 16 > rand_int() % FUZZ_RATE){
            l->value += rand_int() % 7 - 4 - (rand_int() % 2);
            //printf("Fuzz: %d\n", ( );
            break;
        }
        
        l = l->next;
    }
}
