#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#include "hash.h"

#define CHUNK 4

struct hash_table *new_table(int size)
{
    struct hash_table *res;
    int i = 0;

    res = malloc(sizeof(struct hash_table));
    res->bucket = malloc(sizeof(struct bucket) * size);
    res->size = size;

    while (i < size) {
	res->bucket[i].data = malloc(CHUNK * sizeof(char *));
	res->bucket[i].allocated = CHUNK;
	res->bucket[i].firstFree = 0;
	i++;
    }
    
    return res;
}

void hash_stats(struct hash_table *t)
{
    int i = 0;
    int entries = 0;
    int empty = 0;

    while (i < t->size) {
	if (t->bucket[i].firstFree != 0) {
	    /*printf("Bucket %d used %d\n", i, t->bucket[i].firstFree);*/
	    entries += t->bucket[i].firstFree;
	} else {
	    empty++;
	}
	i++;
    }

    printf("Total Buckets : %d\n", t->size);
    printf("Empty Buckets : %d\n", empty);
    printf("Total Entries : %d\n", entries);
    printf("Avergage Depth: %f\n", (double)entries / (double)t->size);
}

unsigned int hash_string(char *s)
{
    unsigned int res = 0;

    while (*s)
	res = ((res<<1) + (int)(*(s++)));

    return res;
}

char *in_table_aux(struct hash_table *t, int hash, char *s)
{
    int x;

    x = 0;
    while (x < t->bucket[hash].firstFree) {
	if (! strcmp(t->bucket[hash].data[x], s)) {
	    return t->bucket[hash].data[x];
	}
	x++;
    }
    
    return NULL;
}

char *in_table(struct hash_table *t, char *s)
{
    int hash;

    hash = hash_string(s) % t->size;
    return in_table_aux(t, hash, s);
}

void add_to_table(struct hash_table *t, char *s)
{
    int hash;

    hash = hash_string(s) % t->size;
    if (in_table_aux(t, hash, s)) {
	return;
    }

    if (t->bucket[hash].firstFree == t->bucket[hash].allocated) {
	t->bucket[hash].allocated += CHUNK;
	t->bucket[hash].data =
	    realloc(t->bucket[hash].data,
		    t->bucket[hash].allocated * sizeof(char *));
	/*printf("Bucket %d grew to %d\n", hash, t->bucket[hash].allocated);*/
    }
    /*printf("Adding to bucket %d, item %d\n", hash, t->bucket[hash].firstFree); */
    t->bucket[hash].data[t->bucket[hash].firstFree++] = strdup(s);
}
