roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * spelling.cpp
 *	 Spell checker done by David Breitz
 *   ____            _               
 *  |  _ \ ___  __ _| |_ __ ___  ___ 
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *  
 * 	Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include <pspell/pspell.h>
#include "mud.h"

#define SP_MODE_LIST		1
#define SP_MODE_ADVISE		2
#define SP_MODE_HIGHLIGHT	4

static void		check_spelling(Player* player,cmd* cmnd);
static void		learn_spelling(Player* player,cmd* cmnd);
static void		forget_spelling(Player* player,cmd* cmnd);
static void		do_spelling_check(Player* player, int mode, bstring str);
/*static void		do_spelling_learn(Player* player,cmd *cmd);*/
static void		print_word_list(Player* player, const PspellWordList *wl);

PspellCanHaveError	*ret;
PspellManager		*manager;
PspellConfig		*config;
int			 sp_initialized = 0;
char			*sp_language = NULL;
char			*sp_spelling = NULL;
char			*sp_jargon = NULL;
char			*sp_module = NULL;
const char			*sp_delimiters = " !.,:;-\n\t";
const char			*sp_ignores = "'";

const char *spellingSyntax =
    "Syntax: *spell check [-s|-l|-a]\n"
    "        *spell learn <word>\n";

void cleanup_spelling(void) {
	if(manager)
		delete_pspell_manager(manager);
}
void init_spelling(void) {
	config = new_pspell_config();
	if(sp_language != NULL)
		pspell_config_replace(config,"language-tag",sp_language);
	if(sp_spelling != NULL)
		pspell_config_replace(config,"spelling",sp_spelling);
	if(sp_jargon != NULL)
		pspell_config_replace(config,"jargon",sp_jargon);
	if(sp_module != NULL)
		pspell_config_replace(config,"module",sp_module);
	ret = new_pspell_manager(config);
	delete_pspell_config(config);
	if(pspell_error_number(ret) != 0) {
		fprintf(stderr,"%s\n",pspell_error_message(ret));
		return;
	}
	sp_initialized = 1;

	manager = to_pspell_manager(ret);
	config = pspell_manager_config(manager);
}

int dmSpelling(Player* player, cmd* cmnd) {

	if(sp_initialized) {
		if((strcmp(cmnd->str[1],"check") == 0) || (cmnd->num < 2)) {
			check_spelling(player,cmnd);
		} else if(strcmp(cmnd->str[1],"learn") == 0) {
			if(!player->isCt()) {
				player->print("Only CTs and DMs may do that.\n");
				return(0);
			} else
				learn_spelling(player,cmnd);
		} else if(strcmp(cmnd->str[1],"forget") == 0) {
			forget_spelling(player,cmnd);
		} else {
			player->print(spellingSyntax);
			return(0);
		}
	} else {
		player->print("spelling not initialized\n");
	}

	return(0);
}

static void check_spelling(Player* player, cmd* cmnd) {
	int	i=0;
	int	long_desc_seen=0;
	int	short_desc_seen=0;
	int	list_seen=0;
	int	long_desc=1;
	int	short_desc=1;
	int	mode=SP_MODE_LIST;

	if(!needUniqueRoom(player))
		return;
	
	for(i = 2; i < COMMANDMAX; i++) {
		if(strcmp(cmnd->str[i],"-a") == 0 && cmnd->num > 2) {
			mode |= SP_MODE_ADVISE;
		} else if(strcmp(cmnd->str[i],"-h") == 0 && cmnd->num > 2) {
			mode |= SP_MODE_HIGHLIGHT;
			if(!list_seen)
				mode &= ~SP_MODE_LIST;
		} else if(strcmp(cmnd->str[i],"-l") == 0 && cmnd->num > 2) {
			mode |= SP_MODE_LIST;
			list_seen = 1;
		} else if(strcmp(cmnd->str[i],"-L") == 0 && cmnd->num > 2 ) {
			long_desc = 1;
			long_desc_seen = 1;
			if(!short_desc_seen)
				short_desc = 0;
		} else if(strcmp(cmnd->str[i],"-S" ) == 0 && cmnd->num > 2) {
			short_desc = 1;
			short_desc_seen = 1;
			if(!long_desc_seen)
				long_desc = 0;
		}
	}

	if(short_desc) {
		player->print("Checking for misspelled words in short description...\n");
		do_spelling_check(player, mode, player->parent_rom->getShortDescription());
	}

	if(long_desc) {
		player->print("Checking for misspelled words in long description...\n");
		do_spelling_check(player, mode, player->parent_rom->getLongDescription());
	}
}

static void learn_spelling(Player* player,cmd* cmnd) {
	int	i;

	for(i = 2; i < COMMANDMAX && cmnd->str[i][0] != '\0'; i++) {
		pspell_manager_add_to_personal(manager,cmnd->str[i], strlen(cmnd->str[i]));
		player->print("%s is now added to the RoH dictionary.\n", cmnd->str[i], strlen(cmnd->str[i]));
	}

	pspell_manager_save_all_word_lists(manager);
}

static void forget_spelling(Player* player,cmd* cmnd) {
	int	i=0;

	/* Well, pspell doesn't seem to have a function for removing
	   a word from a personal word list, so we'll need to get
	   the path of the personal wordlist file, open the file, 
	   lock the file for reading and writing, remove each line
	   containing one of the words we're forgetting, save the
	   file, unlock the file, and force pspell to reload the
	   wordlist. Somehow... Does pspell cache these wordlists,
	   or does it read them each time it accesses them? Can
	   we iterate over the personal wordlist, removing items
	   as we go, without hosing the entire spellchecker?
	   Are commands in Realms re-entrant?  (Can multiple
	   instances of the spelling function be running at once?)
	   If not, pspell will never be reading a wordlist while
	   we're trying to modify it, so we shouldn't have a 
	   problem so long as we can iterate over the personal
	   wordlist. */

	for(i = 2; i < COMMANDMAX && cmnd->str[i][0] != '\0'; i++) {
		/* This should check if the word appears in any of our
		   wordlists.  If it doesn't, we should tell the player
		   that we never knew how to spell that in the first place. */
		player->print("Oh, no!  I've just forgotten how to spell ");
		player->print(cmnd->str[i]);
		player->print("!\n");

		/* But for now, we use the crude method of obtaining the
		   wordlist pathname, locking the file, and removing the
		   word. */
	}

	/*pspell_manager_save_all_word_lists(manager);*/
}

static void do_spelling_check(Player* player,int mode, bstring str) {
	char	*tmp;
	char	*tok;
	char	*word;
	char	*buf = 0;
	int	 wordlen;
	int	 i;

	if(str.c_str() != NULL) {
		if((tmp = strdup(str.c_str())) == NULL)
			return;

		tok = strtok_r(tmp, sp_delimiters, &buf);

		while(tok != NULL) {
			wordlen = strcspn(tok, sp_ignores);
			word = (char *)malloc((wordlen+1) * sizeof(char));

			if(word != NULL) {
				for(i = 0; i <= wordlen; i++)
					word[i] = '\0';
				strncpy(word, tok, wordlen);

				if(pspell_manager_check(manager,word,strlen(word)) == 0) {
					if(mode & SP_MODE_HIGHLIGHT) {
						player->print("Sorry, I don't know how to highlight your spelling errors yet.\n");
					}

					if(mode & SP_MODE_LIST) {
						player->print("\t");
						player->print(word);

						if(mode & SP_MODE_ADVISE) {
							player->print(" -> ");
							print_word_list(player, pspell_manager_suggest(manager, word, strlen(word)));
						}

						player->print("\n");
					}
				}

				free(word);
			}

			tok = strtok_r(NULL,sp_delimiters,&buf);
		}

		free(tmp);
	}
}

/*
static void do_spelling_learn(Player* player,cmd *cmd)
{
}
*/

static void print_word_list(Player* player,const PspellWordList *wl) {
	if(wl != 0) {
		PspellStringEmulation	*emu = pspell_word_list_elements(wl);
		const char		*word;

		while((word = pspell_string_emulation_next(emu)) != 0) {
			player->print((char *) word);
			player->print(" ");
		}
	} else {
		fprintf(stderr,"%s\n",pspell_manager_error_message(manager));
	}
}