#include "./hashmap.h"

int aoc_hash(const char *string) {
  int len = strlen(string);
  int hash = 1;
  for (int i = 0; i < len; i++) {
    hash *= 7;
    hash += string[i] * 13;
    hash %= AOC_HASHMAP_RADIX;
  }

  return hash;
}

AocHashmapNode *aoc_hashmap_get(AocHashmap *map, char *key) {
  int hash = aoc_hash(key);
  AocHashmapNode *node = map->buckets[hash];
  while (node != NULL && strcmp(node->key, key) != 0) node = node->next;
  return node;
}

void aoc_hashmap_put(AocHashmap *map, char *key, void *value) {
  int hash = aoc_hash(key);
  AocHashmapNode *node = map->buckets[hash];
  if (node == NULL) {
    map->buckets[hash] = malloc(sizeof(AocHashmapNode));
    node = map->buckets[hash];
    node->key = malloc(strlen(key) + 1);
    strcpy(node->key, key);
    node->value = value;
    node->next = NULL;
  } else {
    while (node->next != NULL) {
      node = node->next;
    }
    node->next = malloc(sizeof(AocHashmapNode));
    node->next->key = malloc(strlen(key) + 1);
    strcpy(node->next->key, key);
    node->next->value = value;
    node->next->next = NULL;
  }
}

void aoc_hashmap_free(AocHashmap *map) {
  for (int i = 0; i < AOC_HASHMAP_RADIX; i++) {
    AocHashmapNode *node = map->buckets[i];
    while (node != NULL) {
      AocHashmapNode *next = node->next;
      free(node->key);
      free(node->value);
      free(node);
      node = next;
    }
  }
  free(map);
}