/* 
 * File:   arraylist.c
 * Author: Arthur Brandao
 *
 * Created on 14 novembre 2018
 */

#include <stdio.h>
#include <stdlib.h>
#include "str.h"
#include "arraylist.h"

/* --- Fonctions publiques --- */
void arraylist_ini(arraylist* al){
    al->first = NULL;
    al->last = NULL;
    al->size = 0;
}

al_node* arraylist_add(arraylist* al, char* key, int(*handler)(char*)){
    int length;
    al_node* aln;
    //Regarde si la clef existe
    if((aln = arraylist_search(al, key)) != NULL){
        arraylist_delete(al, aln);
    }
    //Ajout des valeurs
    aln = malloc(sizeof(al_node));
    length = strlen(key);
    aln->key = malloc(sizeof(char) * (length + 1));
    memset(aln->key, 0, length + 1);
    strncpy(aln->key, key, length);
    aln->handler = handler;
    //Lien entre les noeuds
    aln->next = NULL;
    if (al->first == NULL) {
        aln->prev = NULL;
        al->first = aln;
        al->last = aln;
    } else {
        aln->prev = al->last;
        al->last->next = aln;
        al->last = aln;
    }
    al->size++;
    return aln;
}

al_node* arraylist_search(arraylist* al, char* key){
    //Liste vide
    if(al->first == NULL){
        return NULL;
    }
    //Cherche dans la liste
    al_node* aln = al->first;
    int length = strlen(aln->key) + 1;
    while (aln != NULL) {
        if (strncmp(aln->key, key, length) == 0) {
            return aln;
        }
        aln = aln->next;
    }
    return NULL;
}

int arraylist_call(arraylist* al, char* key, char* arg){
    al_node* aln = arraylist_search(al, key);
    if(aln == NULL){
        return -1;
    }
    return aln->handler(arg);
}

void arraylist_delete(arraylist* al, al_node* aln){
    //Liste vide
    if(al->first == NULL){
        return;
    }
    //Si 1er et seul
    if (aln->prev == NULL && aln->next == NULL) {
        al->first = NULL;
        al->last = NULL;
    }        
    //Si 1er et non seul
    else if (aln->prev == NULL && aln->next != NULL) {
        aln->next->prev = NULL;
        al->first = aln->next;
    }        
    //Si dernier
    else if (aln->next == NULL) {
        aln->prev->next = NULL;
        al->last = aln->prev;
    }        
    //Sinon si il est au milieu
    else {
        aln->prev->next = aln->next;
        aln->next->prev = aln->prev;
    }
    //Free
    free(aln->key);
    free(aln);
    al->size--;
}

boolean arraylist_remove(arraylist* al, char* key){
    al_node* aln = arraylist_search(al, key);
    if(aln == NULL){
        return false;
    }
    arraylist_delete(al, aln);
    return true;
}

void arraylist_clean(arraylist* al){
    //Liste vide
    if(al->first == NULL){
        return;
    }
    //Vide liste
    al_node* tmp, * aln = al->first;
    while (aln != NULL) {
        tmp = aln->next;
        arraylist_delete(al, aln);
        aln = tmp;
    }
    al->first = NULL;
    al->last = NULL;
    al->size = 0;
}