#include "system.h"
#include <stdio.h>
#include "popt.h"

static int _debug = 0;
static int _verbose = 1;
static const char * dictfn = "/usr/share/dict/words";
static poptBits dictbits = NULL;
static struct {
    unsigned total;
    unsigned hits;
    unsigned misses;
} e;

static int loadDict(const char * fn, poptBits * ap)
{
    char b[BUFSIZ];
    FILE * fp = fopen(fn, "r");
    char * t, *te;
    int nlines = -1;

    if (fp == NULL || ferror(fp)) goto exit;

    nlines = 0;
    while ((t = fgets(b, sizeof(b), fp)) != NULL) {
	while (*t && isspace(*t)) t++;
	if (*t == '#') continue;
	te = t + strlen(t);
	while (te-- > t && isspace(*te)) *te = '\0';
	if (*t == '\0') continue;
	if (ap) {
if (_debug)
fprintf(stderr, "==> poptSaveBits(%p, \"%s\")\n", *ap, t);
	    (void) poptSaveBits(ap, 0, t);
	}
	nlines++;
    }
exit:
    if (fp) (void) fclose(fp);
    return nlines;
}

static struct poptOption options[] = {
  { "debug", 'd', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE, &_debug, 1,
        "Set debugging.", NULL },
  { "verbose", 'v', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE, &_verbose, 1,
        "Set verbosity.", NULL },

  POPT_AUTOALIAS
  POPT_AUTOHELP
  POPT_TABLEEND
};

int main(int argc, const char ** argv)
{
    poptContext optCon = NULL;
    const char ** av = NULL;
    poptBits avbits = NULL;
    int ec = 2;		/* assume failure */
    int rc;

#if defined(HAVE_MCHECK_H) && defined(HAVE_MTRACE)
    mtrace();   /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
#endif

    /* XXX Scale the Bloom filters in popt. */
    if ((rc = loadDict(dictfn, NULL)) <= 0)
	goto exit;
    _poptBitsK = 2;
    _poptBitsM = 0;
    _poptBitsN = _poptBitsK * (unsigned)rc;

    optCon = poptGetContext("tdict", argc, argv, options, 0);

    /* Read all the options (if any). */
    while ((rc = poptGetNextOpt(optCon)) > 0) {
        char * optArg = poptGetOptArg(optCon);
	if (optArg) free(optArg);
        switch (rc) {
        default:	goto exit;
        }
    }
    if (rc < -1) {
        fprintf(stderr, "tdict: %s: %s\n",
                poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
                poptStrerror(rc));
	goto exit;
    }

    if ((rc = loadDict(dictfn, &dictbits)) <= 0)
	goto exit;

    av = poptGetArgs(optCon);
    if ((rc = poptBitsArgs(optCon, &avbits)) != 0)
	goto exit;
    if (avbits) {
	poptBits Ibits = NULL;
	(void) poptBitsUnion(&Ibits, dictbits);
	rc = poptBitsIntersect(&Ibits, avbits);
	fprintf(stdout, "===== %s words are in %s\n", (rc ? "Some" : "No"), dictfn);
	if (Ibits) free(Ibits);
    }
    if (av && avbits)
    while (*av) {
	rc = poptBitsChk(dictbits, *av);
	if (rc < 0) goto exit;
	e.total++;
	if (rc > 0) {
	    if (_verbose)
		fprintf(stdout, "%s:\tYES\n", *av);
	    e.hits++;
	} else {
	    if (_verbose)
		fprintf(stdout, "%s:\tNO\n", *av);
	    e.misses++;
	}
	av++;
    }

    ec = 0;

exit:
    fprintf(stdout, "===== poptBits N:%u M:%u K:%u (%uKb) total(%u) = hits(%u) + misses(%u)\n",
	_poptBitsN, _poptBitsM, _poptBitsK, (((_poptBitsM/8)+1)+1023)/1024, e.total, e.hits, e.misses);
    if (avbits) free(avbits);
    optCon = poptFreeContext(optCon);
#if defined(HAVE_MCHECK_H) && defined(HAVE_MTRACE)
    muntrace();   /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
#endif
    return ec;
}
