#ifndef _NTPM_CONFIG_H
#define _NTPM_CONFIG_H

#include <map>
#include <vector>
#include <list>
#include <string>
#include <stdexcept>

namespace NTPM {

class Configurator
{
public:
    Configurator() { root_class.name = ":";    }
    Configurator(const string &_cfgfname) {
	root_class.name = ":";
	open(_cfgfname);
    }
    void open(const string &_cfgfname);


    const string &GetFilename() const { return cfgfname; }

    void print() { root_class.print(); }

    template <class T>
    T lookup(const string &classname, const string &key) const {
	const Class *cls =
	    const_cast<Configurator&>(*this).find_class(classname);
	return lookup<T>(cls, key);
    }
    string lookup(const string &classname, const string &key) const;


    template <class T>
    vector<T> list_lookup(const string &classpath) const;

    template <class T>
    T lookup(const string &classpath) const {
	string key;
	Class *cls;
	const_cast<Configurator&>(*this).find_class_and_key(classpath,
							     &cls, &key);
	if(!cls)
	    throw runtime_error(string("Class of '") + classpath
				+ "' does not exist.");
	return lookup<T>(cls,key);
    }
    string lookup(const string &classpath) const;


    void CallSubroutine(const string &subroutine);

public:
    class Class;
    struct Subroutine {
	Subroutine(Configurator *_owner=NULL, Class *_parent=NULL) :
	    owner(_owner), parent(_parent), name("?") {}
	void Execute() const;
	map<string,string> bindings;
	Configurator *owner;
  	Class *parent;
	string name;
    };

    struct Class {
	Class(Configurator *_owner=NULL, Class *_parent=NULL) :
	    owner(_owner), parent(_parent), name("?") {}
	void print();
	const Class *GetChild(const string &childname) const;
	Class *GetChild(const string &childname);
	void CallSubroutine(const string &subname);
	string Lookup(const string &key) const;

	list<Class> children;
	list<Subroutine> subroutines;
	map<string,string> bindings;
	list<string> parents;
	Configurator *owner;
  	Class *parent;
	string name;
    };


    Class root_class;


    friend class Class;
    friend class Subroutine;
private:
    Class *find_class(const string &classname, Class *starting_from=NULL);
    void find_class_and_key(const string &classpath,
			    Class **cls, string *key,
			    Class *starting_from=NULL);
    template <class T>
    T lookup(const Class *cls, const string &key) const;


    string cfgfname;
};

}


#include "config.tcc"

#endif // _NTPM_CONFIG_H
