#include "splib.h"
#include <string.h>

/* Use system getopt.  Is there a header file for this? */
extern int      getopt(int argc, char **argv, char *opstring);
extern char    *optarg;
extern int      optind, opterr;

/* All our consts, types, and globals are in this header file */
#include "wordcheck.h"

    NODE           *dawg;

/*
 * -d dict and -s stoplist params come through here.  The dictionaries are
 * loaded and noted in an array, which is used in 'check_file'
 */
void
add_dict(int enabling, char *dictname, int (*check) (NODE * dawg, char *word),
         NODE * dawg, INDEX edges) {
    dict[max_dict].dict = dawg;
    dict[max_dict].edges = edges;
    dict[max_dict].dict_name = dictname;
    dict[max_dict].full_name = dictname;        /* For now - should expand
                                                 * dawg_init args */
    dict[max_dict].check = check;
    if (enabling) {
        dict[max_dict].enabling = TRUE;
        if (wordcheck_verbose)
            fprintf(stderr,
                    "%s: accepting words from dict %s\n",
                    progname, dictname);
    } else {
        dict[max_dict].enabling = FALSE;
        if (wordcheck_verbose)
            fprintf(stderr,
                    "%s: suppressing words from dict %s\n",
                    progname, dictname);
    }
    max_dict += 1;
    if (max_dict == MAX_USER_DICTS) {
        fprintf(stderr,
                "%s: can\'t cope with more than %d user dictionaries\n",
                progname, MAX_USER_DICTS);
        exit(EXIT_FAILURE);
    }
}

/*
 * Main body of spelling checker.  Takes a list of words, one per line, and
 * checks in dict.  This approach allows other (user-supplied) utilities to
 * define what exactly constitutes a word.  Outputs any rejected words to
 * stdout on a line on their own.
 */
int
check_word(char *line)
{
    int             ok;
    int             i;

    if (max_dict == 0) {
        fprintf(stderr, "%s: no dictionaries given!\n", progname);
        exit(EXIT_FAILURE);
    }
        if ((i = strlen(line)) <= 1)
            return(TRUE);           /* Allow blank lines */
        ok = FALSE;
        for (i = 0; i < max_dict; i++) {
            /*
             * rather neat code for minimum checking against multiple dicts
             * and stop lists
             */
            if (!ok && dict[i].enabling) {
                if (dict[i].check(dict[i].dict, line)) {
                    ok = TRUE;
                }
            } else if (ok && !dict[i].enabling) {
                if (dict[i].check(dict[i].dict, line)) {
                    ok = FALSE;
                }
            }                   /* Otherwise skip to the next dict that
                                 * matters */
        }
        return(ok);
}

void
usage(void)
{
    /*
     * If a usage error is given, we want the user to know which program
     * really gave the error -- ie 'wordcheck' rather than spell.  This is
     * because it is almost certainly a mistake on the part of the shell
     * script writer, not the user.
     */
    fprintf(stderr,
            "usage: %s -w progname -v -x -d dict -D transdict -s stoplist -S transstop\n",
            trueprogname);
}

/*
 * wordcheck: takes a file of lines.  Each line is assumed to be a single
 * word, which is checked against the dictionaries.  Words which fail the
 * check are printed to stdout.  This supports multiple dictionaries and stop
 * lists.
 */
int
spell_main(int argc, char **argv)
{
    INDEX           edges;
    int             c;

    trueprogname = progname = argv[0];
    exact_case = FALSE;

    while ((c = getopt(argc, argv, "D:d:S:s:vw:xyh?")) != -1) {
        switch (c) {
        case 'D':
            if (!dawg_init(optarg, &dawg, &edges)) {
                fprintf(stderr,
                        "%s: cannot load translation list \"%s\"\n",
                        progname, optarg);
                exit(EXIT_FAILURE);
            }
            /*
             * The "left=right" style of dictionary requires a slightly
             * different checking procedure.
             */
            add_dict(ENABLING, optarg, dawg_checkeq, dawg, edges);
            if (!exact_case)
                add_dict(ENABLING, optarg, dawg_casecheckeq, dawg, edges);
            break;
        case 'd':
            if (!dawg_init(optarg, &dawg, &edges)) {
                fprintf(stderr,
                        "%s: cannot load dictionary \"%s\"\n",
                        progname, optarg);
                exit(EXIT_FAILURE);
            }
            add_dict(ENABLING, optarg, dawg_check, dawg, edges);
            /*
             * If we're not worried about exact case matching, we can add
             * another procedure to check the word less strictly.  Note that
             * the second procedure will only be called if the first returns
             * false.
             */
            if (!exact_case)
                add_dict(ENABLING, optarg, dawg_casecheck, dawg, edges);
            break;
        case 'S':
            if (!dawg_init(optarg, &dawg, &edges)) {
                fprintf(stderr,
                        "%s: cannot load translation stop list \"%s\"\n",
                        progname, optarg);
                exit(EXIT_FAILURE);
            }
            /*
             * The "left=right" style of dictionary requires a slightly
             * different checking procedure.
             */
            add_dict(DISABLING, optarg, dawg_checkeq, dawg, edges);
            if (!exact_case)
                add_dict(DISABLING, optarg, dawg_casecheckeq, dawg, edges);
            break;
        case 's':
            if (!dawg_init(optarg, &dawg, &edges)) {
                fprintf(stderr,
                        "%s: cannot load stop list \"%s\"\n",
                        progname, optarg);
                exit(EXIT_FAILURE);
            }
            add_dict(DISABLING, optarg, dawg_check, dawg, edges);
            if (!exact_case)
                add_dict(DISABLING, optarg, dawg_casecheck, dawg, edges);
            break;
        case 'v':
            /* LOUD, AREN'T YOU? */
            wordcheck_verbose = TRUE;
            break;
        case 'w':
            /* Inherit our callers program name, for better diagnostics */
            progname = optarg;
            break;
        case 'x':
            /* Words must match those in dicts following this flag exactly. */
            exact_case = TRUE;
            break;
        case 'y':
            /*
             * Normal service has been resumed.  This is only likely to be
             * needed if you've built a dawg from AN ALL UPPERCASE WORD LIST
             * :-(
             */
            exact_case = TRUE;
            break;
        case 'h':
        case '?':
            usage();
            exit(EXIT_SUCCESS);
            break;
        default:
            fprintf(stderr,
                    "syntax: %s -w progname -v -x -d dict -s stoplist -t translate\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    return (0);
}
