
#include <cstdio>
#include <cstring>

#include "llconf.h"
#include "mess.h"

#define BUFSZ 512


llc_list *conf_load(const char *file)
{
	llc_list *list;
	llc_list *listp;
	llc_cat  *cat;
	llc_cat  *confs;
	llc_var  *conf_vars;

	cat = conf_load_file(file);
	if( ! cat ) return NULL;

	list = new llc_list;
	list->cats=cat;
	list->next=NULL;
	conf_find_val(list->name, cat, "general", "name");
	/* Check if there are more configs */
	confs = conf_find_cat(cat,"configs");
	if (confs != NULL){
		listp=list;
		conf_vars = confs->vars;
		while(conf_vars !=NULL){
			cat = conf_load_file(conf_vars->value);
			if (cat != NULL){
				listp->next = new llc_list;
				listp = listp->next;
				listp->cats=cat;
				listp->next = NULL;
				conf_find_val(listp->name, cat, "general", "name");
			}
			conf_vars = conf_vars->next;
		}
	}
	return list;
}

static char *buf_strip(char *buf)
{
	char *start;
	/* Strip off trailing whitespace, returns, etc */
	//mprintf("Doing trailing spaces...\n");
	while ((strlen(buf)>0)&&(buf[strlen(buf)-1]<33)){
		buf[strlen(buf)-1] = '\0';
	}
	//mprintf("Done trailing spaces...\n");
	start = buf;
	/* Strip off leading whitespace, returns, etc */
	while ((*start > 0) && (*start < 33) && (start < (buf+strlen(buf)))){
		*start++='\0';
	}
	//mprintf("Done leading spaces...\n");
	return start;
}

static int conf_get_cat(char *cat, char *buf)
{
	char *pbuf=buf+1;
	char *pcat=cat;
	while((*pbuf != ']')&&(*pbuf != '\0')){
		*pcat=*pbuf;
		pbuf++;
		pcat++;
	}
	*pcat='\0';
	return 0;
}

static int conf_get_tag_value(char *tag, char *value, char *buffer)
{
	int got_tag=0;
	char * buf_p=buffer;
	char * tag_p=tag;
	char * val_p=value;
	char tmp[BUFSZ];
	while(*buf_p != '\0'){
		if (*buf_p == '='){
			got_tag=1;
		}
		else {
			if(!got_tag){
				*tag_p=*buf_p;
				tag_p++;
			}
			else {
				*val_p=*buf_p;
				val_p++;
			}
		}
		buf_p++;
	}
	if(!got_tag){
		*tag='\0';
		*value='\0';
		return -1;
	}
	else {
		*tag_p='\0';
		*val_p='\0';
		strcpy(tmp,buf_strip(tag));
		strcpy(tag,tmp);
		strcpy(tmp,buf_strip(value));
		strcpy(value,tmp);
		return 0;
	}
}

static void proc_line(char *pbuf, llc_cat **conf_root,
		      llc_cat **conf_current, llc_var **last_var)
{
	char *tp;
	char tag[254],value[254],cat[254];
	llc_var *new_var;
	llc_cat *new_cat;
	//mprintf("doing strip...\n");
	pbuf = buf_strip(pbuf);
	if (pbuf[0] == '\n'){
		return;
	}
	else {
		/* Check for comment */
		if ((tp = strchr(pbuf,'#'))){
			return;
		}
		/* Check for Catagory */
		else if ((tp = strchr(pbuf,'['))){
			conf_get_cat(cat,pbuf);
			new_cat = new llc_cat;
			strcpy(new_cat->name,cat);
			new_cat->next = NULL;
			if (*conf_current == NULL){
				if (*conf_root == NULL){
					*conf_root = new_cat;
				}
				else {
					(*conf_root)->next = new_cat;
				}
				*conf_current = new_cat;
			}
			else {
				(*conf_current)->next = new_cat;
				*conf_current = new_cat;
				*last_var = NULL;
			}
		}
		/* Then must be a variable */
		else {
			conf_get_tag_value(tag,value,pbuf);
			if ( *conf_current != NULL){
				new_var = new llc_var;
				new_var->next = NULL;
				strcpy(new_var->name,tag);
				strcpy(new_var->value,value);
				//mprintf("Tag=> %s Val=> %s\n",tag,value);
				if (*last_var == NULL){
					(*conf_current)->vars = new_var;
					*last_var = new_var;
				}
				else {
					(*last_var)->next= new_var;
					*last_var = new_var;
				}
			}
		}
	}
}

llc_cat *conf_load_file(const char *file)
{
	FILE *f;
	char pbuf[BUFSZ];
	llc_cat *conf_root=NULL;
	llc_cat *conf_current=NULL;
	llc_var *last_var=NULL;
	mprintf("Opening [%s]...\n",file);
	if (!(f = fopen(file,"r"))){
		return NULL;
	}
	while(!feof(f)){
		if(fgets(pbuf,BUFSZ,f)){
			//mprintf("proc line...[%s]\n",pbuf);
			proc_line(pbuf,&conf_root,&conf_current,&last_var);
		}
	}
	fclose(f);
	return conf_root;
}

char *conf_find_val(char *value, llc_list *root_list, const char *listname,
		    const char *catname, const char *varname)
{
	llc_list *listp = NULL;
	llc_cat *catp = NULL;
	llc_var *varp = NULL;
	value[0]='\0';
	listp = root_list;
	while (listp != NULL){
		if (strcasecmp(listp->name,listname)==0){
			while (catp != NULL){
				if (strcasecmp(catp->name,catname)==0){
					varp = catp->vars;
					while(varp !=NULL){
						if (strcasecmp(varp->name,varname)==0){
							strcpy(value,varp->value);
							return value;
						}
						varp = varp->next;
					}
				}
				catp = catp->next;
			}
		}
		listp=listp->next;
	}
	return value;
}

char *conf_find_val(char *value, llc_cat *root_cat,
		    const char *catname, const char *varname)
{
	llc_cat *catp = root_cat;
	llc_var *varp;
	value[0]='\0';
	while (catp != NULL){
		if (strcasecmp(catp->name,catname)==0){
			varp = catp->vars;
			while(varp !=NULL){
				if (strcasecmp(varp->name,varname)==0){
					strcpy(value,varp->value);
					return value;
				}
				varp = varp->next;
			}
		}
		catp = catp->next;
	}
	return value;
}

char *conf_find_val(char *value, llc_cat *cat, const char *varname)
{
	llc_var *varp;
	value[0]='\0';
	varp = cat->vars;
	while(varp !=NULL){
		if (strcasecmp(varp->name,varname)==0){
			strcpy(value,varp->value);
			return value;
		}
		varp = varp->next;
	}
	return value;
}

llc_cat *conf_find_cat(llc_cat *root_cat, const char *catname)
{
	llc_cat *catp = root_cat;
	while (catp != NULL){
		if (strcasecmp(catp->name,catname)==0){
			return catp;
		}
		catp = catp->next;
	}
	return NULL;
}

llc_list *conf_find_list(llc_list *root_list, const char *listname)
{
	llc_list *listp = root_list;
	while (listp != NULL){
		if (strcasecmp(listp->name,listname)==0){
			return listp;
		}
		listp = listp->next;
	}
	return NULL;
}

static void conf_release_vars( llc_var *var )
{
	if( var->next ) {
		conf_release_vars( var->next );
		var->next = NULL;
	}
	delete var;
}

static void conf_release_cats( llc_cat *cat )
{
	if( cat->next ) {
		conf_release_cats( cat->next );
		cat->next = NULL;
	}
	conf_release_vars( cat->vars );
	delete cat;
}

void conf_release_list( llc_list *list )
{
	if( ! list ) return;
	if( list->next ) {
		conf_release_list( list->next );
		list->next = NULL;
	}
	conf_release_cats( list->cats );
	delete list;
}

