/* hashfunc.c
 *
 * part of the getstats program
 */


#include <stdio.h>
#include <string.h>
#include "hashfunc.h"

#define HASHSIZE       49999

struct hosttable *addrtable[HASHSIZE];
struct sizetable *reqtable[HASHSIZE];
struct requesttable *treetable[HASHSIZE];

unsigned int hash(s)
     char *s;
{
    unsigned int hashval = 0,
		c, range = '~' - '!' + 1;

    for ( ; *s != '\0'; s++) {
	  /* constrain chars to the range '!' to '~' */
	if (*s < '!')
	    c = 0;
	else if (*s <= '~')
	    c = *s - '!';
	else
	    c = '~' - '!';

	hashval = c + hashval * range;
    }
    return hashval % HASHSIZE;
} /* hash */



void addhash(nameaddress, numaddress)
     char *nameaddress;
     char *numaddress;
{
	struct hosttable *hp;
	unsigned hashval;

	hp = (struct hosttable *) emalloc(sizeof(*hp));
	hp->numaddress = e_strdup(numaddress);
	hashval = hash(numaddress);
	hp->next = addrtable[hashval];
	addrtable[hashval] = hp;
	hp->nameaddress = e_strdup(nameaddress);
	return;
} /* addhash */



char *hashlookupnumaddr(numaddress)
     char *numaddress;
{
	struct hosttable *hp;

	for (hp = addrtable[hash(numaddress)]; hp != NULL; hp = hp->next)
		if (strcmp(numaddress, hp->numaddress) == 0)
			return hp->nameaddress;
	return NULL;
}



void addhashsize(filesize, request)
     long int filesize;
     char *request;
{
	struct sizetable *sp;
	unsigned hashval;

	sp = (struct sizetable *) emalloc(sizeof(*sp));
	sp->request = e_strdup(request);
	hashval = hash(request);
	sp->next = reqtable[hashval];
	reqtable[hashval] = sp;
	sp->filesize = filesize;
}



long hashlookupsize(request)
     char *request;
{
	struct sizetable *sp;

	for (sp = reqtable[hash(request)]; sp != NULL; sp = sp->next)
		if (strcmp(request, sp->request) == 0)
			return sp->filesize;
	return -1;
}






/* finds the specified request in the hash table
 * returns pointer to node if the request has not been printed in this
 *    report and marks the node printed
 * returns NULL if the request has been printed
 */
struct requesttable *hashlookupreq(request)
     char *request;
{
	struct requesttable *rt;

	for (rt = treetable[hash(request)];
	     rt != NULL;
	     rt = rt->next)
		if (strcmp(request, rt->request) == 0) {
		    if (rt->printed)
			return NULL;		/* already printed */
		    rt->printed = TRUE;    	/* mark it as printed */
		    return rt;
		}
	return NULL;				/* not found (urk!) */
}



void addhashreq(request, date, filesize, status)
     char *request;
     long int date;
     long int filesize;
     char *status;
{
	struct requesttable *rt;
	unsigned hashval;
	int new_node = TRUE;

	for (rt = treetable[hash(request)]; rt != NULL; rt = rt->next)
	    if (strcmp(request, rt->request) == 0) {
						/* update existing entry */
		if (date > rt->date) {		/* this rec is later */
		    rt->date = date;		/* most recent access date */
		    if (strcmp(rt->status, status)) {
			free(rt->status);
			rt->status = e_strdup(status);
		    }
		}
		rt->requestnum++;		/* number of accesses */
		rt->filesize += filesize;	/* bytes requested */
		new_node = FALSE;
		break;
	    }


	if (new_node) {
	    /* this request not found in the hash table, so add it */
	    rt = (struct requesttable *) emalloc(sizeof(*rt));
	    rt->request = e_strdup(request);
	    rt->status  = e_strdup(status);
	    hashval = hash(request);
	    rt->next = treetable[hashval];	/* insert at head of list */
	    treetable[hashval] = rt;
	    rt->date = date;
	    rt->filesize = filesize;
	    rt->requestnum = 1;
	    rt->printed = FALSE;		/* display it */
	}
} /* addhashreq */
