/* File: HashExample.m - HashFile Example ('phone number to word translator)
 *
 * By: Christopher Lane
 * Symbolic Systems Resources Group
 * Knowledge Systems Laboratory
 * Stanford University
 *
 * Date: 09 November 1992
 *
 * Copyright: 1990, 1991 & 1992 by The Leland Stanford Junior University.
 * This program may be distributed without restriction for non-commercial use.
 */

#import <stdlib.h>
#import <stdio.h>
#import <string.h>
#import <ctype.h>
#import <getopt.h>

#import "HashFile.h"

#define INTEGER @encode(int)
#define STRING @encode(char *)

#define OPTIONSTRING "bdh:"
#define USAGE "usage: %s [-h database] [-d] [-b < wordlist] \n"

typedef enum { BUILD = 'b', DUMP = 'd', HASHFILE = 'h' } OPTIONS;
typedef enum { PROGRAM } ARGUMENTS;

#define BUFFERSIZE LEAFSIZE
#define DIGITMAX (7)

#ifndef DATABASE
#define DATABASE "PhoneWords"
#endif

const char *letters = "abcdefghijklmnoprstuvwxyABCDEFGHIJKLMNOPRSTUVWXY";
const char *numbers = "222333444555666777888999222333444555666777888999";

char *basename(char *s)
{
	char *pointer;
	
	if((pointer = rindex(s, '/')) == NULL) return s;
	
	return ++pointer;
}

void buildTable(id table)
{		
	unsigned int key;
	char *s, *idx = NULL, value[BUFFERSIZE], buffer[BUFFERSIZE];
		
	[table empty];

	while(gets(value) != NULL) {
		if(strlen(s = value) > DIGITMAX) continue;
		key = 0;
		while(*s)
			if((idx = index(letters, *s++)) == NULL) break;
			else key = (key * 10) + ( numbers[idx - letters] - '0' );
		if(idx == NULL) continue;
#ifdef DEBUG
		printf("<%d\t%s\n", key, value);
#endif
		if([table isKey:(void *) key])
			s = strcat(strcat(strcpy(buffer, (char *) [table valueForKey:(void *) key]), " "), value);
		else s = value;
		
		[table insertKey:(void *) key value:(void *) NXCopyStringBuffer(s)];
		}
}

void dumpTable(id table)
{
	void *key, *value;
	NXHashState state = [table initState];

	while([table nextState:&state key:&key value:&value]) (void) printf("%d\t%s\n", (int) key, (char *) value);
}

void main(int argc, char *argv[])
{
	id table = nil;
	char *database = DATABASE;
	int key, nitems, flag, option = HASHFILE, status = EXIT_SUCCESS;
		
	while((flag = getopt(argc, argv, OPTIONSTRING)) != EOF)
		switch(option = flag) {
			case BUILD : case DUMP : break;
			case HASHFILE : database = optarg; break;
			default : status = EXIT_FAILURE; break;
			}

	if(optind < argc || status == EXIT_FAILURE) {
		(void) fprintf(stderr, USAGE, basename(argv[PROGRAM]));
		exit(EXIT_FAILURE);
		}

	if(option == BUILD || [HashFile isHashFile:database]) {
		if((table = [[HashFile alloc] initFromFile:database keyDesc:INTEGER valueDesc:STRING]) == nil) {
			(void) fprintf(stderr, "%s: Can't open %s.\n", basename(argv[PROGRAM]), database);
			exit(EXIT_FAILURE);
			}
		}
	else if(option != BUILD) {
			(void) fprintf(stderr, "%s: Can't find %s.\n", basename(argv[PROGRAM]), database);
			exit(EXIT_FAILURE);
		}

	switch(option) {
		case BUILD : buildTable(table); break;
		case DUMP : dumpTable(table); break;
		default : 
			while((nitems = scanf("%d", &key)) != EOF && nitems == 1)
				if([table isKey:(void *) key])
					(void) printf("%d\t%s\n", key, (char *) [table valueForKey:(void *) key]);
			break;
		}
	
	[table free];

	exit(status);
}
