#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <aspell.h>
#include "merc.h"


// You need to compile with the aspell library linking. In your
// make file make sure it has -laspell
//
// Otherwise you get undefined value errors!

AspellConfig *spell_config;

// To make a command to spellcheck a word just use do_spellcheck()
// as your command funciton in interp.c/pp and interp.h


/*  Add the following to string.c or where you contain your string
 *  editing options. The second block is a .h replacement.
    if (!str_cmp(arg1, ".spellcheck")) {
        if (arg2[0])
            do_spellcheck(ch, arg2);
        else
            string_spellcheck(ch, *ch->desc->pString, false);
        return;
    }
    if (!str_cmp (arg1, ".h")) {
        send_to_char ("Sedit help (commands on blank line):   \n\r", ch);
        send_to_char (".r 'old' 'new'   - replace a substring \n\r", ch);
        send_to_char ("                   (requires '', \"\") \n\r", ch);
        send_to_char (".h               - get help (this info)\n\r", ch);
        send_to_char (".s               - show string so far  \n\r", ch);
        send_to_char (".f               - (word wrap) string  \n\r", ch);
        send_to_char (".c               - clear string so far \n\r", ch);
        send_to_char (".ld <num>        - delete line number <num>\n\r", ch);
        send_to_char (".li <num> <str>  - insert <str> at line <num>\n\r", ch);
        send_to_char (".lr <num> <str>  - replace line <num> with <str>\n\r", ch);
        send_to_char (".spellcheck      - spellcheck the string\r\n", ch);
        send_to_char (".spellcheck <w>  - spellcheck a word\r\n", ch);
        send_to_char ("@                - end string          \n\r", ch);
        return;
    }
*/

// We'll set up our aspell checkers. We need to call this function
// once and only once per boot. Add it in boot_db() in most muds.
void init_aspell() {
    //A new configuration class. It's global.
    // I'm quite sure we won't be freeing it.
    spell_config = new_aspell_config();

    // Set up our dictionary settings. English US class dictionary.
    aspell_config_replace(spell_config, "lang", "en_US");
}

// new_checker() creates an spellchecking object with unique settings and
// library. You possibly may want to manage quarks for each user in what ever
// application you use this in. For what I'm using it in we only need one
// generic checker! It's only called once.
AspellSpeller *new_checker() {
    AspellCanHaveError * possible_err = new_aspell_speller(spell_config);
    AspellSpeller * spell_checker = 0;

    if (aspell_error_number(possible_err) != 0)
        logff((char*)aspell_error_message(possible_err));
    else
        spell_checker = to_aspell_speller(possible_err);


    return spell_checker;
}
// This function takes a string and returns an array of strings. Each string is a suggestion.
// The array is null terminated just like a string. max_return is the number of suggestions
// you want to be returned max. You must free each string returned along with the array.

char **spell_check(char *needle, int max_return) {
    int correct;
    static AspellSpeller *spell_checker;
    int count = 0;
    char **strings = (char **) malloc(sizeof(char *) * (max_return+1));


    strings[max_return] = 0;
    strings[0] = 0;

    if (!spell_checker)
        spell_checker = new_checker();

    // negative 1 if it is NULL terminated. Finds if it is true or not.
    correct = aspell_speller_check(spell_checker, needle, -1);

    // If not correct let's build a list of possible words.
    if (!correct) {
        const AspellWordList * suggestions = aspell_speller_suggest(spell_checker, needle, -1);
        AspellStringEnumeration * elements = aspell_word_list_elements(suggestions);
        const char * word;


        while ((word = aspell_string_enumeration_next(elements)) != NULL) {
            // Add an entire word to our list.
            strings[count] = strdup(word);
            ++count;
            if (count >= max_return)
                break;
        }
        strings[count] = 0;
        delete_aspell_string_enumeration(elements);
    }
    return strings;
}

// Checks a string and returns a list of all errors in the entire string.
// Good for descriptions and such.
// string_spellcheck(ch, some_String, false);
void string_spellcheck(CHAR_DATA *ch, char *pString, bool replace) {
    int errors = 0;
    char word[MSL];
    char **words;
    int i;

    while(1) {
       pString = one_word(pString, word);
       if (!word[0])
           break;

       words = spell_check(word, 2);

       if (words[0]) {
           if (errors == 0)
               send_to_char("Wrong words:", ch);
           printf_to_char(ch, " %s", word);
           ++errors;
       }
    }
    if (errors) {
        send_to_char("\r\n", ch);
        printf_to_char(ch, "%d errors found.\r\n", errors);
    }
    else
        send_to_char("All words correct.\r\n", ch);

    for(i = 0;words[i];++i)
        free(words[i]);
    free(words);

}


// Command function to spellcheck a word.
void do_spellcheck(CHAR_DATA *ch, char *argument) {
    char **words;
    char arg1[MSL], arg2[MSL];
    int i;
    argument = one_argument (argument, arg1, false);
    argument = one_argument(argument, arg2);
    if (!arg1[0]) {
        send_to_char("Spellcheck what word?\r\n", ch);
        return;
    }

    if (!strcmp(arg1, "room")) {
        string_spellcheck(ch, ch->in_room->description, false);
        return;
    }
    if (arg2[0] && is_number(arg2))
        words = spell_check(arg1, atoi(arg2));
    else
        words = spell_check(arg1, 3);

    if (!words[0]) {
        send_to_char("That's the right spelling.\r\n", ch);
        return;
    }

    send_to_char("That's not a word.  Do you mean one of these?\r\n", ch);
    for(i = 0;words[i];++i) {
        printf_to_char(ch, "%s\n\r", words[i]);
        free(words[i]);
    }
    free(words);
}

// Epp. Forgot to include this at first. It's like one_arg() but finds words based on being
// in a sentence format. Good for parsing each word in a sentence...like in a spellchecker.
char *one_word (char *argument, char *arg_first) {

    while (isspace (*argument) || *argument == '.' || *argument == ',' || *argument == '!'
           || *argument == '\n' || *argument == '\r')
        argument++;

    while (*argument != '\0') {
        if(isspace(*argument)|| *argument == '.' || *argument == ','
                || *argument == '!' || *argument == '\n' || *argument == '\r')
            break;

        *arg_first = *argument;

        arg_first++;
        argument++;
    }

    *arg_first = '\0';

    while (isspace (*argument) || *argument == '.' || *argument == ','
            || *argument == '!' || *argument == '\n' || *argument == '\r')
        argument++;

    return argument;
}