#include "hashtable.h"

htable_t* ht_init(int num_buckets, int(*hashcode)(void *obj), 
		int(*compare)(void *obj1, void *obj2)){
	int i;
	htable_t *ht = (htable_t*)malloc(sizeof(htable_t));
	ht->table=(ht_list_t**)malloc(sizeof(ht_list_t*)*num_buckets);
	memset(ht->table, 0, sizeof(ht_list_t*)*num_buckets);
	ht->num_buckets=num_buckets;
	ht->size=0;
	ht->hashcode = hashcode;
	ht->compare = compare;
	return ht;
}

void ht_reset(htable_t *ht){
	int i;
	ht_list_t *cur,*next;
	if(ht){
		for(i=0;i<ht->num_buckets;i++){
			cur=ht->table[i];
			if(cur){
				next=cur->lptr;	
				free(cur);
				cur=next;
			}
		}
		free(ht->table);
	}
	ht->table=(ht_list_t**)malloc(sizeof(ht_list_t*)*ht->num_buckets);
	memset(ht->table, 0, sizeof(ht_list_t*)*ht->num_buckets);
	ht->size=0;
}

void *ht_find(void *obj, htable_t *ht){
	ht_list_t *chain=ht->table[(ht->hashcode(obj)%ht->num_buckets)];
	void *info_to_return=NULL;

	while(chain) {
		if(ht->compare(obj, chain->info)==0){
			info_to_return=chain->info;
			break;
		} else chain = chain->lptr;
	}
	return info_to_return;
}

void ht_insert(void *obj, htable_t *ht){
	int hc=(ht->hashcode(obj)%ht->num_buckets);
	ht_list_t *new_entry=NULL,*old_chain=ht->table[hc];

	if(!ht_find(obj, ht)){ 
		new_entry=(ht_list_t*)malloc(sizeof(ht_list_t));
		new_entry->info=obj;
		new_entry->lptr=old_chain;
		ht->table[hc]=new_entry;
		ht->size++;
	}
	return;
}

void ht_remove(void *obj, htable_t *ht){
	int hc=(ht->hashcode(obj)%ht->num_buckets);
	ht_list_t *chain=ht->table[hc];
	ht_list_t *oldchain=chain;
	while(chain){
		if(ht->compare(obj, chain->info)==0){
			if(oldchain==chain){	// i.e first list entry
				ht->table[hc]=chain->lptr;
				free(chain);
			} else {
				oldchain->lptr=chain->lptr;
				free(chain);
			}
			ht->size--;
			break;
		} 
		oldchain=chain;	
		chain=chain->lptr; 
	}	
}

ht_list_t *ht_iter(htable_t *ht){
	int i;
	ht_list_t *prev=NULL, *cur=NULL, *next=NULL;

	if(!ht || !ht->table) return NULL;
	for(i=0;i<ht->num_buckets;i++){
		next=ht->table[i];	
		while(next){
			cur=(ht_list_t*)malloc(sizeof(ht_list_t));
			cur->info=next->info;
			cur->lptr=prev;
			prev=cur;
			next=next->lptr;
		}
	}
	return cur;
}

void ht_free_iter(ht_list_t *l){
	ht_list_t *next;
	while(l){
		next=l->lptr;
		free(l);
		l=next;
	}
}
