// CUserDict.cp
// CUserDict.h
// ----------------------------------------------------------------------------------
// The user dictionary class.
//
// This dictionary is a dictionary that is created by users.
//
// Note: This file is proprietary and confidential to Art Pollard
//	and Lextek Internation.  
// Copyright 1994 Art Pollard / LexTek International
//
//
// ----------------------------------------------------------------------------------
// History:
// 		Art Pollard			June 94
//			Original
//		Clark Goble			08/13/94
//			Checked it over and made a few modifications as part of the
//			C++ conversion.
//		Clark Goble			01/29/95
//			Fixed usability check that was causing some problems
// ----------------------------------------------------------------------------------

#include "CUsrDct.h"
#include "Tspell.h"
#include "string.h"
#include "UError.h"

// ----------------------------------------------------------------------------------
//	CUserDict		- Dictionary constructor
// ----------------------------------------------------------------------------------
// The destructor frees the memory

CUserDict::CUserDict(long NumBuffers, FioParam * theFile )
	: CDict( NumBuffers, theFile)
{	// NumBuffers is the number of words

	char 	*Word;
	Word = NULL;
	Usable = TRUE;

	// copy the file data so we don't need to do housekeeping
	// Mac dependent at moment!

	#ifdef _MACINTOSH_
//	UserDict = (FioParam *) ::malloc(sizeof(FioParam));
//	memcpy((void *) UserDict, (void *)theFile, sizeof(FioParam));
	// AP 6/27/1995
	UserDict = theFile;
	#else
	if(theFile == NULL)
		theFile = "UserDict.Lex";
	UserDict = (char *) ::malloc(strlen(theFile)+1);
	strcpy(UserDict,theFile);
	#endif

	NumWords = 0;
	WordList = new UBloom( NumBuffers, 23, By_Key );
	if ( WordList == NULL )	{
		Usable = FALSE;
		return;
		// error checking in UBloom
	}

	// Load in the wordlist
	Uio	*theDict;

//	theDict = new Uio(UserDict); // AP 6/24/95
	theDict = new Uio(theFile); // new AP 6/24/95
	theDict->Open();

	if ( ErrorFunc(0, GET) < eNo_Err )
	{	// try to create it
		ErrorFunc(0, SET);
		if(! theDict->Exist()){
			//theDict->Close();
			theDict->Create(); // If it does not exist, create it

			if ( ErrorFunc(0, GET) < eNo_Err ){
				Usable = FALSE;
				return;		// hopeless
			}

			theDict->SetPos(0, SEEK_SET);
			// Put our magic word
			theDict->PutWord(USERMAGIC);
			theDict->Close();
		}

		// Open it for regular reading/writing
		theDict->Open();
		theDict->SetPos(0, SEEK_SET);

		Word = theDict->GetWord();
		if ( ErrorFunc(0, GET) < eNo_Err )	{
			Usable = FALSE;
			return;
		}
		if (strcmp(USERMAGIC,Word)){
			Usable = FALSE;
			// error
			ErrorFunc(eNot_Dictionary, SET);
			return;
		}
	}

	long Length = theDict->GetLength();

	if (Length == 0)	{
		// new dictionary
		theDict->PutWord(USERMAGIC);
	}

	theDict->SetPos(0, SEEK_SET);

	// check for magic number
	Word = theDict->GetWord();

	if (strcmp(Word,USERMAGIC))
	{
		free(Word);
		// try to create it
		ErrorFunc(0, SET);
		theDict->Close();
		theDict->Create();

		if ( ErrorFunc(0, GET) < eNo_Err )	{
			Usable = FALSE;
			return;		// hopeless
		}

		theDict->SetPos(0, SEEK_SET);
		// Put our magic word
		theDict->PutWord(USERMAGIC);

		theDict->Close();

		// Open it for regular reading/writing
		theDict->Open();
		theDict->SetPos(0, SEEK_SET);

		Word = theDict->GetWord();
		if ( ErrorFunc(0, GET) < eNo_Err )
		{	Usable = FALSE;
			return;
		}

		if (strcmp(Word, USERMAGIC))
		{	// error
			Usable = FALSE;
			ErrorFunc(eNot_Dictionary, SET);
			free(Word);
			return;
		}
	}

	free(Word);

	while ( !theDict->eof() && ( ErrorFunc(0, GET) >= eNo_Err ) )
	{	Word = theDict->GetWord();
		if(Word != NULL) {
			WordList->Insert( Word, strlen(Word) );
			free(Word);
		}
	}

	theDict->Close();
	delete theDict;

} // CUserDict

// ----------------------------------------------------------------------------------
//	CUserDict		- Dictionary destructor
// ----------------------------------------------------------------------------------
// The destructor frees the memory

CUserDict::~CUserDict()
{
	// AP 6/29/95
	//if(UserDict != NULL) free (UserDict);

	if ( WordList != NULL )
		delete WordList;
	#ifndef _MACINTOSH_
	if(UserDict != NULL) free(UserDict);
	#endif

} // ~CUserDict


// ----------------------------------------------------------------------------------
//	LoadUserDictionary		- Reads in the dictionary
// ----------------------------------------------------------------------------------
// Reads in the specified dictionary from disk.  

short
CUserDict::LoadUserDictionary(FioParam *UserDictionary)
{
	Uio	*theDict;

	if ( Usable == FALSE )
	{	ErrorFunc(eNo_Mem, SET);
		return ( eNo_Mem );
	}
	
	theDict = new Uio(UserDictionary);
	theDict->Open();
	
	if ( ErrorFunc(0, GET) < eNo_Err )
		return ( ErrorFunc(0, GET) );
	
	
	if (theDict->GetLength() == 0)
	{	ErrorFunc(eNot_Dictionary, SET);
		return( eNot_Dictionary );
	}
	
	theDict->SetPos(0, SEEK_SET );
	
	char *word;

	while ( !theDict->eof() && ( ErrorFunc(0, GET) >= eNo_Err ) )
	{	word = theDict->GetWord();
		WordList->Insert( word, strlen(word) );
		free(word);
	}

	theDict->Close();
	delete theDict;
	return OK;
} // LoadUserDictionary

// ----------------------------------------------------------------------------------
//	CountUserWords		- Counts the words in the dictionary
// ----------------------------------------------------------------------------------
// This is basically the same as LoadUserDictionary, except that it counts words
// without loading them into memory.

long
CUserDict::CountWords(FioParam *UserDictionary)
{
	unsigned short	theNumWords = 0;
	Uio		*theDict;

	#ifdef _MACINTOSH_
	FioParam 	*TempDict;
	#else
	FioParam 	*TempDict;
	TempDict = "UserDict.Lex";
	#endif

	// If nothing passed use the default
	if ( UserDictionary == NULL )
		TempDict = UserDict;
	else
		TempDict = UserDictionary;

	theDict = new Uio(TempDict);
	theDict->Open();
	if ( ErrorFunc(0, GET) < eNo_Err )
		return ( ErrorFunc(0, GET) );



	if (theDict->GetLength() == 0 )
	{	ErrorFunc(eNot_Dictionary, SET);
		return eNot_Dictionary;
	}

	theDict->SetPos( 0, SEEK_SET);

	char *word;

	while (!theDict->eof() && ( ErrorFunc(0, GET) >= eNo_Err ) )
	{	word = theDict->GetWord();
		NumWords++;
		free(word);
	}

	theDict->Close();
	delete theDict;

	return (NumWords);
} // CountUserWords


// ----------------------------------------------------------------------------------
//	AddWord		- Add a word to the dictionary
// ----------------------------------------------------------------------------------
// This adds a word to the dictionary in two places.  It is first put in the bloom
// filter for the dictionary and at the end of the file that makes up the word
// list.

short
CUserDict::Add(char *Word)
{
	if (!Usable )
	{	ErrorFunc(eUnusableDict, SET);
		return eUnusableDict;
	}
	
	WordList->Insert(Word, strlen(Word));
	NumWords++;
	
	Uio	*DictFile = new Uio(UserDict);
	DictFile->Open();
	
	if ( ErrorFunc(0, GET) < eNo_Err )
		return ( ErrorFunc(0, GET) );

	// add word to end of file
	DictFile->SetPos(0, SEEK_END );
	DictFile->putstring(Word);
	DictFile->putstring("\n");
	DictFile->Close();
	
	return OK;
	
} // AddWord

// ----------------------------------------------------------------------------------
//	Check		- checks for a word
// ----------------------------------------------------------------------------------
// This checks for a word within the dictionary.

short
CUserDict::Check(char *Word)
{
	if ( Usable ){
		if ( WordList->Test(Word, strlen(Word) ) )
			return FOUND;
		return NOTFOUND;
	}
	ErrorFunc(eUnusableDict, SET);
	return eUnusableDict;
} // Check

		
// ----------------------------------------------------------------------------------
//	SetUserDictionaryName		- Sets the name of the dictionary
// ----------------------------------------------------------------------------------
// This sets up the name of the dictionary.

/*
void
CUserDict::SetName(FioParam *UserDictionary)
{
	if (UserDict == NULL)
		UserDict = (FioParam *) ::malloc(sizeof(FioParam));
	memcpy(UserDict, UserDictionary, sizeof(FioParam));

} */ // SetDictionaryName

// ----------------------------------------------------------------------------------
//	ReturnDictName		- Gets the name of the dictionary
// ----------------------------------------------------------------------------------
// This gets up the name of the dictionary.

/*
void
CUserDict::GetName(FioParam *UserDictionary)
{
	UserDictionary = UserDict;
} */ // GetDictionaryName

// ----------------------------------------------------------------------------------
//	ReAllocate		- Tries to load the dictionary again
// ----------------------------------------------------------------------------------
// This loads the dictionary again.  It is used to try to load it again if the
// there was no memory and some new memory was recently freed.

short
CUserDict::ReAllocate(long NumWords)
{
	WordList = new UBloom( NumWords, 20, By_Key);
	if ( WordList == NULL )
	{	Usable = FALSE;
		ErrorFunc(eNo_Mem, SET);
		return eNo_Mem;
	} 
	
	Usable = TRUE;
	return OK;
} // ReAllocate



