/*
  Name:
  Lab Section:
  TA:
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HASHSIZE 5
#define MAXSIZE 100

/* basic mapping from text to replace */
typedef struct text_mapping {	/* replacement table entry */
	char *text;		/* text to look for */
	char *replace;		/* text to replace above with */
	struct text_mapping *next; /* points to next mapping in same hash bucket */
} text_mapping;

/* function prototypes */
text_mapping *install(char *text, char *replace);
text_mapping *lookup(char *s);
unsigned int hash(char *s);
int undef(char *s);
void print_rules();
void process_input();
char *strdupe(char *s);

/* master hash table */
static text_mapping *hashtab[HASHSIZE];

/* used to undefine rules
 *
 * Input: s is name of the rule to delete
 * Return values:
 *  -1 if error is encountered; use if you feel you need this
 *   0 on success
 *   1 if name is not found in table
 */
int undef(char *s) {
	/* FILL THIS IN AND TEST IN MAIN */
	printf("I will no longer replace \"%s\" (if rule exists).\n", s);
	return 0;
}

int main() {
	int i;

	/* initialize hash table */
	for (i = 0; i < HASHSIZE; i++) {
		hashtab[HASHSIZE] = NULL;
	}

	/* "install" replacement rules */
	install("hate", "love");
	install("apples", "kiwis");
	install("blue", "green");
	install("sky", "grass");
	install("procrastinated", "work diligently");
	install("proj1", "every day");

	/* print out all replacement rules */
	print_rules();

	/* take input and apply replacement rules */

	/* example inputs: The sky is blue
	 *                 I hate apples!
	 *                 I procrastinated on CS61C proj1 */
	printf("\nRunning replacer with initial rules (hit enter twice to stop)...\n");
	process_input();

	/* FILL IN HERE ANY TEST DELETION CODE YOU WANT */

	/* "undef" replacement rules */
	undef("sky");

	/* print out all replacement rules after deletions */
	print_rules();

	/* process input again */
	printf("\nRunning replacer again after deletion of rules (hit enter twice to stop)...\n");
	process_input();

	return 0;
}

/* used to find in hash table */
text_mapping *lookup(char *s) {
	text_mapping *current;

	for (current = hashtab[hash(s)]; current; current = current->next) {
		if (!strcmp(s, current->text)) {
			return current;			/* the string s was found */
		}
	}
	return NULL;					/* the string s was not found */
}

/* used to add replacement rules */
text_mapping *install(char *text, char *replace) {
	text_mapping *found;
	unsigned hashval;

	if ((found = lookup(text)) == NULL) {		/* not found */
		found = (text_mapping *) malloc(sizeof(text_mapping));
		if (found == NULL || !(found->text = strdupe(text))) {
			return NULL;
		}
		hashval = hash(text);
		found->next = hashtab[hashval];
		hashtab[hashval] = found;
	}
	else {
		free(found->replace);
	}

	if (!(found->replace = strdupe(replace))) {
		return NULL;
	}
	return found;
}

/* hash function to determine which hash "bucket" */
unsigned int hash(char *s) {
	unsigned hashval;

	for (hashval = 0; *s; s++) {
		hashval = *s + 31 * hashval;
	}
	return hashval % HASHSIZE;
}

void print_rules() {
	int i;
	text_mapping *current;

	for (i = 0; i < HASHSIZE; i++) {
		if ((current = hashtab[i])) {
			do {
				printf("I will replace \"%s\" (hash: %u) with \"%s\"\n", current->text,
						                               hash(current->text),
									       current->replace);
				current = current->next;
			} while (current);
		}
	}

}

void process_input() {
	char lbuff[MAXSIZE], *pos;
	text_mapping *current;

	while (fgets(lbuff, MAXSIZE, stdin) && *lbuff != '\n') {
		pos = strtok(lbuff, " \t\n");
		while (pos) {
			if ((current = lookup(pos))) {
				printf("%s ", current->replace);
			}
			else {
				printf("%s ", pos);
			}
			pos = strtok(NULL, " \t\n");
		}
		printf("\n");
	}
	fgets(lbuff, MAXSIZE, stdin);
}

char *strdupe(char *s) {
	char *buff;

	buff = (char *) malloc(strlen(s) * sizeof(char) + 1);
	if (buff) {
		strcpy(buff, s);
	}
	return buff;
}
