#include <stdlib.h>
#include <assert.h>
#include "hash.h"


void hash_init (hashtable *h)
{
	int i;

	h->size = INITSIZE;
	h->buckets = (bucketlist*) calloc(sizeof(bucketlist), INITSIZE);
	for (i = 0; i < INITSIZE; i++)
		bl_init(&(h->buckets[i]));
	h->numEntries = 0;
}

void hash_insert (hashtable *h, int key, int val)
{
	int insertionBucket;
	int status;
	
	insertionBucket = hash(key, h->size);
	status = bl_pushBack(&(h->buckets[insertionBucket]), key, val);
	assert(status);	/* we should be able to insert! */
	if (status == 1) /* new entry */
		h->numEntries++;
	

	if ( (h->numEntries > (3 * h->size) / 2) )
		hash_resize(h);
}

int hash (int key, int numBuckets)
{
	return (key & 0x7FFFFFFF) % numBuckets;
}

int hash_fetch (hashtable *h, int key)
{
	int fetchBucket;
	bucketlistreturnval * fetchStatus;

	fetchBucket = hash(key, h->size);
	fetchStatus = bl_findNodeWithKey(h->buckets[fetchBucket], key);
	if (! fetchStatus->success)
		return -1;
	else
		return fetchStatus->val;

}

int hash_deleteEntry (hashtable *h, int key)
{
	int deleteBucket;
	int success;
	
	deleteBucket = hash(key, h->size);
	success = bl_deleteNodeWithKey(&(h->buckets[deleteBucket]), key);
	if (success)
		h->numEntries--;
}

void hash_resize (hashtable *h)
{
	int i, j;
	bucketlist * newBuckets;
	bucketlist currBucket;
	bucketlistreturnval * status;
	int key, val, hashBucket, success;

	newBuckets = (bucketlist*) calloc(sizeof(bucketlist), h->size * 2);
	for (i = 0; i < h->size * 2; i++)
		bl_init(&(newBuckets[i]));

	for (i = 0; i < h->size; i++)
	{
		currBucket = h->buckets[i];
		for (j = 0; j < currBucket.size; j++)
		{
			status = bl_getNodeAt(currBucket, j);
			assert(status->success);
			key = status->key;
			val = status->val;
			hashBucket = hash(key, h->size * 2);
			success = bl_pushBack(&(newBuckets[hashBucket]), key, val);
			assert(success);
		}
		while (currBucket.head != NULL)
			bl_deleteNodeAt(&currBucket, 0);
	}

	free(h->buckets);
	h->buckets = newBuckets;
	h->size = h->size * 2;
}
