/*
 * thing: a base class that holds small associative arrays.
 * litem: a list object with trivial printing ability.
 */
#include "thing.H"


/*
 * comparison function for qsort'ing things
 */
static int
compare(const void *left, const void *right)
{
    return strcasecmp(((litem*)left)->name, ((litem*)right)->name);
} /* thing::compare */


/*
 * create a thing, trivially.
 */
thing::thing()
{
    list = (litem*)malloc(1);
    count = 0;
} /* thing::thing */


/*
 * delete a thing, trivially
 */
thing::~thing()
{
    int x;

    for (x=0; x<count; x++) {
	free(list[x].name);
	if (list[x].value)
	    free(list[x].value);
    }
    free(list);
    count = 0;
} /* thing::~thing */


/*
 * add a new item to the list
 */
int
thing::assoc(char *name)
{
    if (find(name).valid)
	return count;
    litem *tmp = (litem*)realloc(list, (1+count) * sizeof list[0]);
    char *lname = strdup(name);

    if (tmp == (litem*)0 || lname == (char*)0) {
	if (lname) free(lname);
	return EOF;
    }
    list = tmp;
    list[count].name = lname;
    list[count].value = (void*)0;
    list[count].valid = 1;
    ++count;
    ::qsort(list, count, sizeof(litem), compare);

    return count;
} /* thing::assoc */


/*
 * This is C++, so we'll cheerfully abuse the language.
 */
litem &
thing::operator [] (char *key)
{
    return find(key);
} /* thing::operator [] */


/*
 * and here it is again, in a functional form for those heretics who
 * have not embraced the One True Way of spaghet^Wobject oriented
 * code (tm)
 */
litem &
thing::find(char *key)
{
    static litem null = { 0, 0, 0 };
    null.name = key;
    litem *p = (litem*)::bsearch(&null, list, count, sizeof(litem), compare);

    return p ? *p :  null;
} /* thing::find */


/*
 * print hte name of a litem
 */
int 
litem::print(FILE *output)
{
    if (null()) {
	return fputs("{null}", output) ? EOF : 1;
    }
    else if (value) {
	return fprintf(output, "%s = %s", name, (char*)value);
    }
    else
	return fputs(name, output) ? EOF : 1;
} /* litem::print */


/*
 * assign something to an litem
 */
void*
litem::operator=(void*rval)
{
    value = rval;
    return rval;
} /* litem::operator= */


#ifdef TESTING
main()
{
    thing list;
    list.assoc("FIRST");
    list.assoc("SECOND");

    list["first"] = "Xyzzy";
    list["second"] = "Plugh";

    printf("list[\"first\"] is "); list["first"].print(); putchar('\n');
    printf("list[\"second\"] is "); list["second"].print(); putchar('\n');
    printf("list[\"third\"] is "); list["third"].print(); putchar('\n');
}
#endif
