#include "hm.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static bool is_not_allocated(hm h) {
    return (h.table == NULL || h.capacity < 1 || h.size < 0);
}

static size_t hash(hm h, char key[MAX_LEN]) {
    int index = 0;
    for (size_t i = 0; i < strlen(key); ++i) {
        index = (index + key[i] * 43) % h.capacity;
    }
    return index;
}

static int rehash(char *key) {
    return 1;
}

static int find_index(hm h, char key[MAX_LEN], bool insert) {
    int try   = 0;
    int index = hash(h, key);
    while (try < h.capacity) {
        switch (h.table[index].state) {
            case occupied:
                if (strncmp(h.table[index].key, key, MAX_LEN) == 0) {
                    return index;
                }
                break;
            case empty:
                return index;
                break;
            case deleted:
                if (insert) {
                    return index;
                }
                break;
            default:
                return -1;
                break;
        }
        index = (index + rehash(key)) % h.capacity;
        try += 1;
    }
    return -1;
}

static bool is_empty(hm h) {
    return h.size == 0;
}

void hm_init(hm *h, int capacity) {
    h->capacity = capacity;
    h->size     = 0;
    h->table    = malloc(h->capacity * sizeof(*h->table));
    for (int i = 0; i < h->capacity; ++i) {
        h->table[i].state = empty;
    }
}

void hm_destroy(hm *h) {
    h->capacity = -1;
    h->size     = -1;
    free(h->table);
    h->table = NULL;
}

bool hm_set(hm *h, char *key, char *value) {
    if (is_not_allocated(*h)) {
        return false;
    }

    int index = find_index(*h, key, true);
    if (index < 0) {
        return false;
    }
    /* printf("%d\n", index); */
    strncpy(h->table[index].value, value, MAX_LEN);
    strncpy(h->table[index].key, key, MAX_LEN);
    h->table[index].state = occupied;
    h->size += 1;
    return true;
}

bool hm_get(hm h, char *key, char *value) {
    int index = find_index(h, key, false);
    if (index >= 0 && h.table[index].state == occupied) {
        strncpy(value, h.table[index].value, MAX_LEN);
        return true;
    }
    return false;
}
bool hm_remove(hm *h, char *key, char *value) {
    int index = find_index(*h, key, false);
    if (index >= 0 && h->table[index].state == occupied) {
        h->table[index].state = deleted;
        strncpy(value, h->table[index].value, MAX_LEN);
        h->size -= 1;
        return true;
    }
    return false;
}

bool hm_search(hm h, char *key) {
    int index = find_index(h, key, false);
    return (index >= 0 && h.table[index].state == occupied);
}

void hm_print(hm h) {
    if (is_not_allocated(h)) {
        printf("Well this hashmap is not allocated n00b.\n");
    }
    if (is_empty(h)) {
        printf("The hashmap is empty.\n");
    }
    for (int i = 0; i < h.capacity; ++i) {
        printf("index: %d, key: %s, value: %s\n", i, h.table[i].key,
            h.table[i].value);
    }
}