#include "stdinc.h"
#include "dat.h"
#include "fns.h"

Index			*mainindex;
int			paranoid = 1;		/* should verify hashes on disk read */

static ArenaPart	*configarenas(char *file);
static ISect		*configisect(char *file);
static Bloom		*configbloom(char *file);

int
initventi(char *file, Config *conf)
{
	statsinit();

	if(file == nil){
		seterr(EOk, "no configuration file");
		return -1;
	}
	if(runconfig(file, conf) < 0){
		seterr(EOk, "can't initialize venti: %r");
		return -1;
	}
	mainindex = initindex(conf->index, conf->sects, conf->nsects);
	if(mainindex == nil)
		return -1;
	mainindex->bloom = conf->bloom;
	return 0;
}

static int
numok(char *s)
{
	char *p;

	strtoull(s, &p, 0);
	if(p == s)
		return -1;
	if(*p == 0)
		return 0;
	if(p[1] == 0 && strchr("MmGgKk", *p))
		return 0;
	return 0;
}

/*
 * configs	:
 *		| configs config
 * config	: "isect" filename
 *		| "arenas" filename
 *		| "index" name
 *		| "bcmem" num
 *		| "mem" num
 *		| "icmem" num
 *		| "queuewrites"
 *		| "httpaddr" address
 *		| "addr" address
 *
 * '#' and \n delimit comments
 */
enum
{
	MaxArgs	= 2
};
int
runconfig(char *file, Config *config)
{
	ArenaPart **av;
	ISect **sv;
	IFile f;
	char *s, *line, *flds[MaxArgs + 1];
	int i, ok;

	if(readifile(&f, file) < 0)
		return -1;
	memset(config, 0, sizeof *config);
	config->mem = Unspecified;
	ok = -1;
	line = nil;
	for(;;){
		s = ifileline(&f);
		if(s == nil){
			ok = 0;
			break;
		}
		line = estrdup(s);
		i = getfields(s, flds, MaxArgs + 1, 1, " \t\r");
		if(i == 2 && strcmp(flds[0], "isect") == 0){
			sv = MKN(ISect*, config->nsects + 1);
			for(i = 0; i < config->nsects; i++)
				sv[i] = config->sects[i];
			free(config->sects);
			config->sects = sv;
			config->sects[config->nsects] = configisect(flds[1]);
			if(config->sects[config->nsects] == nil)
				break;
			config->nsects++;
		}else if(i == 2 && strcmp(flds[0], "arenas") == 0){
			av = MKN(ArenaPart*, config->naparts + 1);
			for(i = 0; i < config->naparts; i++)
				av[i] = config->aparts[i];
			free(config->aparts);
			config->aparts = av;
			config->aparts[config->naparts] = configarenas(flds[1]);
			if(config->aparts[config->naparts] == nil)
				break;
			config->naparts++;
		}else if(i == 2 && strcmp(flds[0], "bloom") == 0){
			if(config->bloom){
				seterr(EAdmin, "duplicate bloom lines in configuration file %s", file);
				break;
			}
			if((config->bloom = configbloom(flds[1])) == nil)
				break;
		}else if(i == 2 && strcmp(flds[0], "index") == 0){
			if(nameok(flds[1]) < 0){
				seterr(EAdmin, "illegal index name %s in config file %s", flds[1], file);
				break;
			}
			if(config->index != nil){
				seterr(EAdmin, "duplicate indices in config file %s", file);
				break;
			}
			config->index = estrdup(flds[1]);
		}else if(i == 2 && strcmp(flds[0], "bcmem") == 0){
			if(numok(flds[1]) < 0){
				seterr(EAdmin, "illegal size %s in config file %s",
					flds[1], file);
				break;
			}
			if(config->bcmem != 0){
				seterr(EAdmin, "duplicate bcmem lines in config file %s", file);
				break;
			}
			config->bcmem = unittoull(flds[1]);
		}else if(i == 2 && strcmp(flds[0], "mem") == 0){
			if(numok(flds[1]) < 0){
				seterr(EAdmin, "illegal size %s in config file %s",
					flds[1], file);
				break;
			}
			if(config->mem != Unspecified){
				seterr(EAdmin, "duplicate mem lines in config file %s", file);
				break;
			}
			config->mem = unittoull(flds[1]);
		}else if(i == 2 && strcmp(flds[0], "icmem") == 0){
			if(numok(flds[1]) < 0){
				seterr(EAdmin, "illegal size %s in config file %s",
					flds[1], file);
				break;
			}
			if(config->icmem != 0){
				seterr(EAdmin, "duplicate icmem lines in config file %s", file);
				break;
			}
			config->icmem = unittoull(flds[1]);
		}else if(i == 1 && strcmp(flds[0], "queuewrites") == 0){
			config->queuewrites = 1;
		}else if(i == 2 && strcmp(flds[0], "httpaddr") == 0){
			if(config->haddr){
				seterr(EAdmin, "duplicate httpaddr lines in configuration file %s", file);
				break;
			}
			config->haddr = estrdup(flds[1]);
		}else if(i == 2 && strcmp(flds[0], "webroot") == 0){
			if(config->webroot){
				seterr(EAdmin, "duplicate webroot lines in configuration file %s", file);
				break;
			}
			config->webroot = estrdup(flds[1]);
		}else if(i == 2 && strcmp(flds[0], "addr") == 0){
			if(config->vaddr){
				seterr(EAdmin, "duplicate addr lines in configuration file %s", file);
				break;
			}
			config->vaddr = estrdup(flds[1]);
		}else{
			/*
			 * this is insanely paranoid.  a single typo should not
			 * prevent venti from starting.
			 */
			seterr(EAdmin, "illegal line '%s' in configuration file %s", line, file);
			break;
		}
		free(line);
		line = nil;
	}
	free(line);
	freeifile(&f);
	if(ok < 0){
		free(config->sects);
		config->sects = nil;
		free(config->aparts);
		config->aparts = nil;
	}
	return ok;
}

static ISect*
configisect(char *file)
{
	Part *part;
	ISect *is;
	
	if(0) fprint(2, "configure index section in %s\n", file);

	part = initpart(file, ORDWR|ODIRECT);
	if(part == nil)
		return nil;
	is = initisect(part);
	if(is == nil)
		werrstr("%s: %r", file);
	return is;
}

static ArenaPart*
configarenas(char *file)
{
	ArenaPart *ap;
	Part *part;

	if(0) fprint(2, "configure arenas in %s\n", file);
	part = initpart(file, ORDWR|ODIRECT);
	if(part == nil)
		return nil;
	ap = initarenapart(part);
	if(ap == nil)
		werrstr("%s: %r", file);
	return ap;
}

static Bloom*
configbloom(char *file)
{
	Bloom *b;
	Part *part;

	if(0) fprint(2, "configure bloom in %s\n", file);
	part = initpart(file, ORDWR|ODIRECT);
	if(part == nil)
		return nil;
	b = readbloom(part);
	if(b == nil){
		werrstr("%s: %r", file);
		freepart(part);
	}
	return b;
}

/* for OS X linker, which only resolves functions, not data */
void
needmainindex(void)
{
}

