#ifndef HASH_TABLE_H
#define HASH_TABLE_H
#include "list.h"
#include <stdlib.h>

#define DEFAULT_HT_SIZE 500

typedef struct PAIR_STRUCT {
  union {
    char *key;
    int ikey;
  };
  void *v;
} pair_t;

typedef struct {
  list_t **buckets;
  size_t size;
  bool is_map;
} ht_t;

pair_t *init_pair(char *key, void *value);

void *bucket_get(list_t *b, char *key);

void *bucket_pop(list_t *b, char *key);

void bucket_free(void *x, void (*freefunc)(void *));

pair_t *init_long_pair(unsigned long key, void *value);

void *bucket_get_by_long(list_t *b, unsigned long key);

void *bucket_pop_by_long(list_t *b, unsigned long key);

void bucket_free_with_long(void *x, void (*freefunc)(void *));

ht_t *init_ht(size_t size);

ht_t *init_map(size_t size);

void map_insert(ht_t *ht, unsigned long key, void *value);

void *map_pop(ht_t *ht, unsigned long key);

void *map_get(ht_t *ht, unsigned long key);

void map_free(void *x);

void ht_insert(ht_t *ht, char *key, void *value);

/*! @brief returns the old value, mutates ht state with new value */
void *ht_modify(ht_t *ht, char *key, void *newval);

/*! @brief overwrites old value with new value while freeing the old */
void ht_overwrite(ht_t *ht, char *key, void *newval, void (*freefunc)(void *));

void *ht_pop(ht_t *ht, char *key);

void *ht_get(ht_t *ht, char *key);

void ht_free(void *x, void (*freefunc)(void *));

/* djb2 hash function */
unsigned long hash(char *key);
#endif