#include <sys/types.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <stdio.h>
#include <syslog.h>
#include "hash.h"

extern char *malloc(), *realloc();
extern short hash();

static Hash_Struct *tables = NULL;
static char min_letters;
static char max_letters;

char *worddir = WORDDIR;

/*
 * read_hash_table takes a number of letters and returns a pointer to
 * a hash table.  It also returns as a parameter the size of the
 * table.  It assumes that the space for this parameter has already
 * been allocated.
 */

short int *read_hash_table(word_dir, letters, size)
char *word_dir;
char letters;
short int *size; /* RETURN */
{
     char filename[MAXPATHLEN];
     FILE *infile;
     short int *indices;
     short int *ptr;
     
     sprintf(filename, HASH_TMPLT, word_dir, letters);
     if (! (infile = fopen(filename, "r")))
	  return(NULL);
     indices = (short int *) malloc(sizeof(short int) * MAXTABLESIZE);
     if (! indices)
	  return(NULL);

     *size = fread(indices, sizeof(short int), MAXTABLESIZE, infile);
     if (! *size)
	  return(NULL);
     fclose(infile);

     ptr = indices;
     while (ptr - indices < *size) {
	  *ptr = ntohs(*ptr);
	  ptr++;
     }

     indices = (short int *) realloc(indices, sizeof(short int) * *size);
     if (! indices)
	  return(NULL);

     return(indices);
}




/*
 * read_hash_tables takes a minimum number of letters and a maximum
 * number of letters.  It then reads in the hash tables for those
 * numbers of letters and returns a pointer to an array of
 * Hash_Struct.  A return value of NULL signifies failure.
 */
Hash_Struct *read_hash_tables(word_dir)
char *word_dir;
{
     char loop;
     Hash_Struct *tables;
     
     tables = (Hash_Struct *) malloc(sizeof(Hash_Struct) *
				     (max_letters - min_letters + 1));
     if (! tables)
	  return(NULL);

     for (loop = min_letters; loop <= max_letters; loop++) {
	  char filename[MAXPATHLEN];
	  
	  (tables + loop - min_letters)->indices =
	       read_hash_table(word_dir, loop,
			       &((tables + loop - min_letters)->size));
	  sprintf(filename, WORD_TMPLT, word_dir, loop);
	  (tables + loop - min_letters)->text_file =
	       fopen(filename, "r");
	  if (! (tables + loop - min_letters)->text_file)
	       return(NULL);
     }
     return(tables);
}




/*
 * initialize_hash_tables reads them in and does other frobbing
 */
int initialize_hash_tables(min_let, max_let)
char min_let, max_let;
{
     return(initialize_hash_tables_dir(worddir, min_let, max_let));
}



/*
 * initialize_hash_tables reads them in and does other frobbing
 */
int initialize_hash_tables_dir(word_dir, min_let, max_let)
char *word_dir;
char min_let, max_let;
{
     min_letters = min_let;
     max_letters = max_let;
     
     tables = read_hash_tables(word_dir);
     if (! tables)
	  return(-1);
     else
	  return(0);
}




/*
 * check_word_in_table sees if a word exists in a particular table
 */
check_word_in_table(word, length, table)
Hash_Struct *table;
char *word;
char length;
{
     short int hashval;
     int is_word = 0;
     long int filepos;
     static char word_read[MAX_LETTERS];

     if (! table->size)
	  return(0);
     
     hashval = hash(word, table->size);
     while (1) {
	  filepos = table->indices[hashval] * length;
	  if (! filepos)
	       break;
	  fseek(table->text_file, filepos, 0);
	  fread(word_read, 1, length, table->text_file);
	  if (! strncasecmp(word, word_read, length)) {
	       is_word++;
	       break;
	  }
	  hashval = ((hashval + 1) % (table->size));
     }
     return(is_word);
}

     


/*
 * check_word takes a word, a minimum number of letters and a maximum
 * number of letters.  It assumes that the hash tables have been read
 * in properly (it exits if the pointer to them is null, but doesn't
 * deal otherwise.)
 */
int check_word(word)
char *word;
{
     int len = strlen(word);
     char *ptr = word;
     static char the_word[MAX_LETTERS + 1];
     char *ptr2 = the_word;
     
     if (len < min_letters || len > max_letters)
	  return(0);

     /* convert word to upper case */
     while (*ptr) {
	  *ptr2 = *ptr & 0xDF;
	  ptr2++;
	  ptr++;
     }
     *ptr2 = '\0';
     
     if (! tables)
	  return(0);
     else
	  return(check_word_in_table(the_word, len, tables + len -
				     min_letters));
}
