#import "FooSpellCheck.h"

@implementation FooSpellCheckClass

- (id <NSSpellServerDelegate>)init
{
	NSLog(@"Init called.\n");
	self = [super init];
    
	NSLog(@"Trying to load dictionary.\n");
	if ((spell_fsm = fsm_read_binary_file("/Library/Services/EuSpell.service/Contents/MacOS/euspell.foma")) != NULL) {
		NSLog(@"Loaded foma binary euspell.foma.\n");		
		if ((spell_apply_handle = apply_init(spell_fsm)) != NULL) {
			NSLog(@"Initalized fsm.\n");
		}
		if ((spell_apply_med_handle = apply_med_init(spell_fsm)) != NULL) {
			NSLog(@"Initalized fsm MED.\n");
            apply_med_set_med_cutoff(spell_apply_med_handle, 3);
            apply_med_set_med_limit(spell_apply_med_handle,100);
		}
	}
    NSLog(@"Trying to load grammar.\n");
	if ((grammar_fsm = fsm_read_binary_file("/Library/Services/EuSpell.service/Contents/MacOS/euspell-grammar.foma")) != NULL) {
		NSLog(@"Loaded foma binary euspell-grammar.foma.\n");		
		if ((grammar_apply_handle = apply_init(grammar_fsm)) != NULL) {
			NSLog(@"Initalized fsm.\n");
		}
	}
    return self;
}

- (void) dealloc
{
	NSLog(@"Deallocing.\n");
	fsm_destroy(spell_fsm);
	spell_fsm = NULL;
    [super dealloc];
}

// New method: Search for a misspelled word in a given string
- (NSArray *)spellServer:(NSSpellServer *)sender
			 checkString:(NSString *)stringToCheck
				  offset:(NSUInteger)offset
				   types:(NSTextCheckingTypes)checkingTypes
				 options:(NSDictionary *)options
			 orthography:(NSOrthography *)orthography
			   wordCount:(NSInteger *)wordCount
{
    // TODO: check the flags of checkingTypes (seems to be uint_64)
    // see NSTextCheckingResult.h for types
    // Currently, we check both grammar and spelling regardless of the flags
    // set by the caller.
    
    int i, startrange, endrange, utfpos, utfoffset;
    char *markedinstring;

	NSLog(@"FooSpellCheck. Unite (10.6. method) called. String to check: %@\n",stringToCheck);
    
	NSScanner *stringToCheckScanner = [NSScanner scannerWithString:stringToCheck]; // create NSScanner object to scan stringToCheck
	NSCharacterSet *wordCharSet = [NSCharacterSet alphanumericCharacterSet]; // set allowed charsets for words - letters and numbers 
	*wordCount = [[stringToCheck componentsSeparatedByString:@" "] count]; // get number of words in stringToCheck
	NSMutableArray *returnArray = [NSMutableArray array]; // create return array
    while (![stringToCheckScanner isAtEnd]) // while scanner is not at end
	{
		
		[stringToCheckScanner scanUpToCharactersFromSet:wordCharSet intoString:nil]; // scans the string until a character from wordCharSet character set is encountered, send accumulating characters into nil 
		if (![stringToCheckScanner isAtEnd]) { // if scanner at this point is not at end (or characters from the set to be skipped remaining != TRUE), we have found a word
			
			NSString *wordToCheck; //create string object for word
			
			[stringToCheckScanner scanCharactersFromSet:wordCharSet intoString:&wordToCheck]; // scan the stringToCheck as long as characters from wordCharSet are encountered
			
			// and accumulate characters into wordToCheck
			
			// if word is in dictionary (wordsArray) or or word is in user dictionary 
			if ([self isWordCorrect:wordToCheck] || ([sender isWordInUserDictionaries:wordToCheck caseSensitive:YES])) {
				continue;
			} else {
				[returnArray addObject:[NSTextCheckingResult spellCheckingResultWithRange: NSMakeRange(offset + [stringToCheckScanner scanLocation] - [wordToCheck length], [wordToCheck length])]];
			}
		}
	}
    NSDictionary *dummyArr = [NSDictionary dictionaryWithObjectsAndKeys: @"a", @"dummy", nil];
    // Check grammar
    NSLog(@"Checking grammar for: %@\n",stringToCheck);
    markedinstring = apply_down(grammar_apply_handle, [stringToCheck UTF8String]);
    NSLog(@"Grammar transducer return string: %s\n", markedinstring);
    for (i = 0, utfpos = 0, utfoffset = 0; markedinstring[i] != '\0'; utfpos++, i += utf8skip((markedinstring+i))) {
        if (strncmp((markedinstring+i), "<ERR", 4) == 0) {
            startrange = utfpos - utfoffset;
            utfoffset = utfoffset + 6;
        }
        if (strncmp((markedinstring+i), "</ERR", 5) == 0) {
            endrange = utfpos - utfoffset;
            [returnArray addObject:[NSTextCheckingResult grammarCheckingResultWithRange: NSMakeRange(offset+startrange,(endrange-startrange)) details:[NSArray arrayWithObjects:dummyArr,nil]]];
            utfoffset = utfoffset + 7;
        }
    }
	return returnArray;
}


// Possible word completions, based on a partially completed string

- (NSArray *)spellServer:(NSSpellServer *)sender
suggestCompletionsForPartialWordRange:(NSRange)range
				inString: (NSString *)string
				language:(NSString *)language

{
	
	NSLog(@"FooSpellCheck. Word completions asked for: %@\n",[string substringWithRange:range]);
	// Return a simple array
	
	return [NSArray arrayWithObjects:@"completion1", @"completion2", @"completion3", @"completion3", nil];
	
}

// Suggest guesses for the correct spelling of the given misspelled word

- (NSArray *)spellServer:(NSSpellServer *)sender
   suggestGuessesForWord: (NSString *)word
			  inLanguage:(NSString *)language

{
	NSMutableArray *array = [NSMutableArray array];
	NSLog(@"FooSpellCheck. Word suggestions asked for: %@\n",word);
	
	
	char *p, *string;
    p = [word UTF8String];

    int seen, i;
    for (seen = 0, i = 0; (string = apply_med(spell_apply_med_handle, p)) != NULL && (i < 4); ) {
		NSString *potentialword = [NSString stringWithUTF8String: string];
        // Avoid duplicated
        for(NSString * myStr in array) {
            if ([myStr isEqualToString:potentialword]) {
                seen = 1;
            }
        }
        if (seen == 0) {
            [array addObject: potentialword];
            i++;
        }
		p = NULL; // iterate
	}
	return array;	
}



// User has added the specified word to the user’s list of acceptable words in the specified language. 
- (void)spellServer:(NSSpellServer *)sender didLearnWord:(NSString *) word
		 inLanguage:(NSString *)language

{
	// do nothing
}


// User has removed the specified word from the user’s list of acceptable words in the specified language 
- (void)spellServer:(NSSpellServer *)sender
	  didForgetWord:(NSString *) word
		 inLanguage:(NSString *)language

{
	// do nothing
}

// Search for a grammar in a given string

- (NSRange)spellServer:(NSSpellServer *)sender
  checkGrammarInString: (NSString *)string
			  language:(NSString *)language
			   details:(NSArray **) outDetails

{
    NSMutableArray *returnArray = [NSMutableArray array]; // The array to return 
    NSLog(@"FooSpellCheck. Grammar check asked for: %@\n",string);  
	// no grammatical issues found
	NSArray* myGrammaticalIssues = [NSArray array];
	*outDetails = myGrammaticalIssues;
	return NSMakeRange (0, 3);
}

- (BOOL)isWordCorrect:(NSString *)word {
	if (apply_down(spell_apply_handle, [word UTF8String]) == NULL) {
		return FALSE;
	} else {
		return TRUE;
	}

}

/*
int utf8skip(char *str) {
    unsigned char s;
    
    s = (unsigned char)(unsigned int) (*str);
    if (s < 0x80)
        return 1;
    if ((s & 0xe0) == 0xc0) {
        return 2;
    }
    if ((s & 0xf0) == 0xe0) {
        return 3;
    }
    if ((s & 0xf8) == 0xf0) {
        return 4;
    }
    return -1;
}
*/
@end
