/*
 * KA: the definition for a single configuration variable in a
 * Karray.
 *
 * Copyright (c) 1996 David L Parsons
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by David L Parsons (orc@pell.chi.il.us).  My name may not be used
 * to endorse or promote products derived from this software without
 * specific prior written permission.  THIS SOFTWARE IS PROVIDED
 * ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * functions provided:
 *
 *	KA(char*)		initialize, assigning value.
 *	KA()			initialize, no value.
 *	KA(int)			initialize, make invalid.
 *	~KA()			goodbye, cruel world.
 *	-- NO COPY CONSTRUCTOR --
 *	changed()		has this KA been modified?
 *	drop(int)		drop element
 *	operator [](int)	get array index 
 *	(char*)			the value of this KA
 *	operator =(char*)	assign a value to this KA
 *	operator =(KA&)		copy the value of another KA to this one
 *	operator +=(char*)	append to this KA's value
 *	operator +=(KA*)	append another KA to this KA's value
 *
 *	print(FILE*)		print a dump of the KA to a FILE*
 *
 *	True()			is this ON/TRUE/YES/1 ?
 *	False()			is this OFF/NO/FALSE/0 ?
 */
#ifndef _KA_D
#define _KA_D

extern "C" {
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
}
#include <string.h>

class KA {
private:
    char **_value;
    int   _nrvalue;
    int   _valid;
    int   _different;

    inline void _flush()	{   int x;
				    for (x=0; x<_nrvalue; x++)
					free(_value[x]);
				    _nrvalue = 0;
				}
    void _add(char *rhs)	{
				    if (!(valid() && rhs))
					return;

				    int i = locate(rhs);

				    if (i >= 0)
					return;
				    _value = (char**)realloc(_value,
						    (1+_nrvalue)*sizeof(char*));
				    _value[_nrvalue] = strdup(rhs);
				    _nrvalue++;
				    _different = 1;
				}
    inline void _init()		{
				    if ((_value = (char**)malloc(1)) != 0)
					_value[0] = 0;
				    _nrvalue = _different = 0;
				    _valid = 1;
				}

public:
    inline KA(char *value)	{ _init(); if (value) _add(value); }
    inline KA()			{ _init(); }
    inline KA(int ick)		{ _init(); _valid = 0; ick = !ick; }
    inline ~KA()		{ _flush(); free(_value); }
    char *operator [](int index) { return _value[index]; }
    inline int locate(char *rhs) {
				    int i;
				    for (i=0; i<_nrvalue; i++)
					if (strcasecmp(rhs, _value[i]) == 0)
					    return i;
				    return EOF;
				}
    inline int has(char *rhs)	{ return locate(rhs) != EOF; }
    inline unsigned int count()	{ return _nrvalue; }
    inline int changed()	{ return _different; }
    inline int changed(int val) { return _different = val; }
    inline int valid()		{ return _valid; }

    /* STRING ASSIGNMENT */
    KA& operator =(char *rhs) {
			    if (valid()) {
				_flush();
				_add(rhs);
			    }
			    return *this;
			}
    KA& operator +=(char *rhs) {
			    _add(rhs);
			    return *this;
			}

    inline void drop(char *k)	{ drop(locate(k)); }
    void drop(unsigned int k)	{
			    if (valid() && k < count()) {
				free(_value[k]);
				if (k < count()) {
				    while (k < count()-1) {
					_value[k] = _value[1+k];
					++k;
				    }
				    _nrvalue--;
				}
				_different = 1;
			    }
			}
    /* COPY OPERATORS */
    inline KA& operator =(KA &rhs) {
			    if (valid()) {
				_flush();
				while (count() < rhs.count())
				    _add(rhs[count()]);
			    }
			    _different = 0;
			    return *this;
			}
    inline KA& operator +=(KA &rhs) {
			    if (valid()) {
				unsigned int x;
				for (x=0; x<rhs.count(); x++)
				    _add(rhs[x]);
				_different = 1;
			    }
			    return *this;
			}
    inline KA& Zero()	{
			    _flush();
			    return *this;
			}
    inline KA& operator =(int rhs) {
			    assert(rhs == 0);
			    return Zero();
			}

    inline int print(FILE *out = stdout) {
			    if (valid()) {
				if (count() > 0) {
				    unsigned int x;

				    for (x=0; x<count(); x++)
					fprintf(out, "%c\"%s\"",
						x ? ',' : '(', _value[x]);
				    fputc(')', out);
				    fputc(' ', out);
				}
				fprintf(out, "changed is %d\n", changed());
				return count();
			    }
			    fprintf(out, "invalid\n");
			    return 0;
			}

};

#endif/*_KA_D*/
