/*
    cfgfile.cc - hierarchical config file handling
    Copyright (C) 2003  Matthew Mueller <donut AT dakotacom.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "cfgfile.h"
#include "status.h"

void CfgSection::load(c_file *f, int &level) {
	char *v,*buf;
	int slen;
	while ((slen=f->bgets())>0){
		buf=f->rbufp();
		if (slen<1)
			continue;
		buf+=strspn(buf," \t");
		if (!*buf)
			continue;
		if (*buf=='}') {
			//			printf("end section\n");
			level--;
			break;
		}
		if (*buf=='{')
		{
			level++;
			CfgSection *s=new CfgSection(name(),buf+1,f,level);
			CfgSection_map::iterator si;
			if ((si=sections.find(s->key))!=sections.end()) {
				delete si->second;
				si->second=s;
				PERROR("%s: duplicate section", s->name().c_str());
				set_user_error_status();
			}
			else
				sections.insert(CfgSection_map::value_type(s->key,s));
			//			printf("new section: %s\n",buf+r+1);
		}
		else if (*buf=='#')
			;//ignore
		else if (buf[0]=='/' && buf[1]=='/')
			;//ignore
		else if((v=strchr(buf,'='))) {
			*v=0;
			v++;
			CfgItem *i=new CfgItem(name(),buf,v);
			CfgItem_map::iterator ii;
			if ((ii=items.find(i->key))!=items.end()) {
				delete ii->second;
				ii->second=i;
				PERROR("%s: duplicate item", i->name().c_str());
				set_user_error_status();
			}
			else
				items.insert(CfgItem_map::value_type(i->key,i));
			//				printf("new item: %s=%s\n",n,v);
		}
		else {
			PERROR("%s: invalid line '%s'",f->name(),buf);
			set_user_error_status();
		}
	}
}
CfgSection::CfgSection(const string &filename) : CfgBase(filename,"") {
	c_file_fd f(filename.c_str(),O_RDONLY);
	f.initrbuf();
	int level=0;
	load(&f, level);
	if (level!=0) {
		PERROR("%s: unbalanced {}'s: level=%+i", filename.c_str(), level);
		set_user_error_status();
	}
	f.close();
	used=true;
}
CfgSection::~CfgSection() {
	for (CfgItem_map::iterator i = items.begin(); i != items.end(); ++i)
		delete (*i).second;
	for (CfgSection_map::iterator s = sections.begin(); s != sections.end(); ++s)
		delete (*s).second;
}

int CfgSection::check_unused(void) const {
	int count=0;
	for (CfgItem_map::const_iterator i = items.begin(); i != items.end(); ++i)
		if (!i->second->isused()) {
			count++;
			PERROR("%s: unused item (possible typo)", i->second->name().c_str());
			set_user_error_status();
		}
	for (CfgSection_map::const_iterator s = sections.begin(); s != sections.end(); ++s){
		if (s->second->isused()) {
			count+=s->second->check_unused();
		}
		else {
			count++;
			PERROR("%s: unused section (possible typo)", s->second->name().c_str());
			set_user_error_status();
		}
	}
	return count;
}

const CfgItem *CfgSection::getitem(const char *name) const {
	used=true;
	CfgItem_map::const_iterator i=items.find(name);
	return (i!=items.end()) ? (*i).second : NULL;
}
const CfgSection *CfgSection::getsection(const char *name) const {
	used=true;
	CfgSection_map::const_iterator i=sections.find(name);
	return (i!=sections.end()) ? (*i).second : NULL;
}

