Revision 1 (by moose, 2006/03/06 10:00:33) Initial Import
#ifndef __MADCONF_H__
#define __MADCONF_H__

#include <qstring.h>
#include <qcstring.h>
#include "MadSQLite.h"

/*
tables:

Key:
id, pid, typeid, name, dataid

data:
id, data

data possibilities:
id, typeid, data

type ids: val, val list, mult choice|single val, mult choice|mult val
*/

extern const char sql_create_key_table[];
extern const char sql_create_data_table[];
extern const char sql_create_data_opt_table[];


enum {
	MCKT_VALUE = 1,
	MCKT_VALUE_LIST,
	MCKT_MCAV, // mult choice, any value (like for an editable combo box, like a union of a VALUE_LIST and MCMV :))
	MCKT_MCSV, // mult choice, single value
	MCKT_MCMV, // mult choice, mult value
};

class MadConf;

// Got an idea from The_Vulture on #C++@freenode
// methods returning an object byvalue, change to return error, and take object by reference.

class MadConfKeyValue {
	friend class MadConfKey;
		
	public:
		MadConfKeyValue() : conf(0), id(0) { }
		MadConfKeyValue(MadConf *cnf, int i, const char *c) : conf(cnf), id(i), value(c) { }

		int getInt() { return value.toInt(); }
		bool getBool() { return (bool)value.toInt(); }
		const char *getText() { return (const char *)value; }
		double getDouble() { return value.toDouble(); }

		bool set(int);
		bool set(bool);
		bool set(const char *);
		bool set(double);

		void erase();

		operator bool() { return valid(); }
		bool operator!() { return !valid(); }
		bool valid() { return (bool)((conf != 0) ? true : false); }
		
	private:
		MadConf *conf;
		int id;
		QString value;
};

class MadConfKeyOpt {
	friend class MadConfKey;
		
	public:
		MadConfKeyOpt() : conf(0), id(0) { }
		MadConfKeyOpt(MadConf *cnf, int i, const char *c) : conf(cnf), id(i), value(c) { }

		int getInt() { return value.toInt(); }
		bool getBool() { return (bool)value.toInt(); }
		const char *getText() { return (const char *)value; }
		double getDouble() { return value.toDouble(); }

		bool set(int);
		bool set(bool);
		bool set(const char *);
		bool set(double);

		void erase();
		
		operator bool() { return valid(); }
		bool operator!() { return !valid(); }
		bool valid() { return (bool)((conf != 0) ? true : false); }
		
	private:
		MadConf *conf;
		int id;
		QString value;
};

class MadConfKey {
	friend class MadConf;
	
	public:
		MadConfKey() : key(0), id(-1), type(0), conf(0), value_result(0), child_result(0), opt_result(0) { }
		MadConfKey(MadConf *, int, int, const char *);
		~MadConfKey();

		operator bool() { return valid(); }
		bool operator!() { return !valid(); }
		
		MadConfKey(const MadConfKey& ck)
		{
			id   = ck.id;
			key  = ck.key;
			type = ck.type;
			conf = ck.conf;
			
			value_result = child_result = opt_result = 0;
			
			printf("Key copy constructor: %s(%i)\n", (const char *)key, id);
		}
		
		MadConfKey &operator=(const MadConfKey &ck)
		{
			id   = ck.id;
			key  = ck.key;
			type = ck.type;
			conf = ck.conf;
			
			if(value_result)
				delete value_result;
			
			if(child_result)
				delete child_result;
			
			if(opt_result)
				delete opt_result;
			
			
			value_result = child_result = opt_result = 0;
			
			printf("Key copy assign: %s(%i)\n", (const char *)key, id);
			
			return *this;
		}
		
		bool valid() { return (bool)((conf != 0) ? true : false); }

		int getId() { return id; }
		QString name();
		bool setName(const char *);

		int getType() { return type; }
		bool setType(int t);	
		
		int getValueCount() { return ValueCount; }

		// maybe do something funky here with references?
		bool beginValue();
		bool value(MadConfKeyValue &);
		bool step(MadConfKeyValue &);

		bool addValue(MadConfKeyValue &, const char *);

		bool beginOpt();
		bool step(MadConfKeyOpt &);
		bool addOpt(MadConfKeyOpt &, const char *);
		
		// Funky, calling setValue() will invalidate any MadConfKeyValues that are allocated...

		int getChildCount() { return ChildCount; }
		bool child(MadConfKey &, const char *); // obviously messes up the first/next stuff
		bool beginChild();
		bool step(MadConfKey &);

		bool newChild(MadConfKey &, const char *keyname, int type = MCKT_VALUE);

	//	MadConfKey *getParent();

		bool erase();

		inline bool setAutoCommit(bool ac) { AutoCommitSet = true; bool old = AutoCommit; AutoCommit = ac; return old; }
		inline bool isAutoCommitEnabled() { return (AutoCommitSet && AutoCommit) || (!AutoCommitSet && AUTO_COMMIT); }
		static bool AUTO_COMMIT;

		bool isType(int t) { return t == type; }

		void fin() {
			if(value_result)
				delete value_result;
			
			if(child_result)
				delete child_result;
			
			if(opt_result)
				delete opt_result;
			
			value_result = child_result = opt_result = 0;
		}

	private:
		int ChildCount;
		int ValueCount;
		bool AutoCommitSet, AutoCommit;
		QString key;
		int id;
		int type;
		MadConf *conf;
		MadSQLiteResult *value_result, *child_result, *opt_result;

		bool insert_key();
		bool delete_key(int kid);
};

class MadConf {
	friend class MadConfKey;
	friend class MadConfKeyValue;
	friend class MadConfKeyOpt;

	public:
		MadConf(const char *);
		~MadConf();

		bool beginKey();
		bool step(MadConfKey &);

		bool key(MadConfKey &, const char *key);
		bool key(MadConfKey &, int id);
		bool newKey(MadConfKey &, const char *key, int type = MCKT_VALUE);

		MadSQLite *getDB() { return db; }

	private:
		MadSQLite *db;
		MadSQLiteResult *result;

		bool initDB();
};

#if 0

MadConfKey *key = conf->newKey("foo"); // default type is single choice, single value

key->setVaue("foo");

MadConfKey *child = key->addChild("lala", MCKT_MCSV); // Multiple Choice, Single Value
child->addChoice("foo");
child->addChoice("bar");
child->addChoice("baz");
child->addChoice("frob");
child->setValue("foob"); // fails

MadConfKey *child2 = key->addChild("meep", MCKT_MCMV); // Multiple Choice, Multiple Value
child->addChoice("foo");
child->addChoice("bar");
child->addChoice("baz");
child->addChoice("frob");
child->setValue("foo"); // clears all values, and sets this,
child->addValue("bar"); // adds bar, so now child2 == foo, bar

for(val = child->firstValue(); val; val = child->nextValue()) {
	printf("value: %s\n", val->getText());
}

for(ckey = key->fisrtChild(); ckey; ckey = key->nextChild()) {
	printf("child: %s\n", ckey->name());
}

#endif

#endif /* __MADCONF_H__ */