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

#include "whack.h"

int debug;
int mainstacksize = 256*1024;

static void	ventiserver(char *vaddr);

void
threadmain(int argc, char *argv[])
{
	char *config, *haddr, *vaddr;
	u32int mem, icmem, bcmem, minbcmem;

	vaddr = "tcp!*!venti";
	haddr = nil;
	config = nil;
	mem = 0xffffffffUL;
	icmem = 0;
	bcmem = 0;
	ARGBEGIN{
	case 'a':
		vaddr = ARGF();
		if(vaddr == nil)
			goto usage;
		break;
	case 'B':
		bcmem = unittoull(ARGF());
		break;
	case 'c':
		config = ARGF();
		if(config == nil)
			goto usage;
		break;
	case 'C':
		mem = unittoull(ARGF());
		break;
	case 'd':
		debug = 1;
		break;
	case 'h':
		haddr = ARGF();
		if(haddr == nil)
			goto usage;
		break;
	case 'I':
		icmem = unittoull(ARGF());
		break;
	case 'w':
		queuewrites = 1;
		break;
	default:
		goto usage;
	}ARGEND

print("whack %d\n", sizeof(Whack));

	if(argc){
  usage:
		fprint(2, "usage: venti [-dw] [-a ventiaddress] [-h httpaddress] [-c config] [-C cachesize] [-I icachesize] [-B blockcachesize]\n");
		threadexitsall("usage");
	}

	fmtinstall('V', vtscorefmt);
	fmtinstall('H', encodefmt);
	fmtinstall('F', vtfcallfmt);

	if(config == nil)
		config = "venti.conf";


	if(initarenasum() < 0)
		fprint(2, "warning: can't initialize arena summing process: %r");

	if(initventi(config) < 0)
		sysfatal("can't init server: %r");

	if(mem == 0xffffffffUL)
		mem = 1 * 1024 * 1024;
	fprint(2, "initialize %d bytes of lump cache for %d lumps\n",
		mem, mem / (8 * 1024));
	initlumpcache(mem, mem / (8 * 1024));

	icmem = u64log2(icmem / (sizeof(IEntry)+sizeof(IEntry*)) / ICacheDepth);
	if(icmem < 4)
		icmem = 4;
	fprint(2, "initialize %d bytes of index cache for %d index entries\n",
		(sizeof(IEntry)+sizeof(IEntry*)) * (1 << icmem) * ICacheDepth,
		(1 << icmem) * ICacheDepth);
	initicache(icmem, ICacheDepth);

	/*
	 * need a block for every arena and every process
	 */
	minbcmem = maxblocksize * 
		(mainindex->narenas + mainindex->nsects*4 + 16);
	if(bcmem < minbcmem)
		bcmem = minbcmem;

	fprint(2, "initialize %d bytes of disk block cache\n", bcmem);
	initdcache(bcmem);

	fprint(2, "sync arenas and index...\n");
	if(syncindex(mainindex, 1) < 0)
		sysfatal("can't sync server: %r");

	if(queuewrites){
		fprint(2, "initialize write queue...\n");
		if(initlumpqueues(mainindex->nsects) < 0){
			fprint(2, "can't initialize lump queues,"
				" disabling write queueing: %r");
			queuewrites = 0;
		}
	}

	if(haddr){
		fprint(2, "starting http server at %s\n", haddr);
		if(httpdinit(haddr) < 0)
			fprint(2, "warning: can't start http server: %r");
	}

	ventiserver(vaddr);
	threadexitsall(0);
}

static void
vtrerror(VtReq *r, char *error)
{
	r->rx.type = VtRerror;
	r->rx.error = estrdup(error);
}

static void
ventiserver(char *addr)
{
	Packet *p;
	VtReq *r;
	VtSrv *s;
	char err[ERRMAX];

	s = vtlisten(addr);
	if(s == nil)
		sysfatal("can't announce %s: %r", addr);

	while((r = vtgetreq(s)) != nil){
		r->rx.type = r->tx.type+1;
	//	print("req (arenas[0]=%p sects[0]=%p) %F\n",
	//		mainindex->arenas[0], mainindex->sects[0], &r->tx);
		switch(r->tx.type){
		default:
			vtrerror(r, "unknown request");
			break;
		case VtTread:
			if((r->rx.data = readlump(r->tx.score, r->tx.dtype, r->tx.count)) == nil){
				rerrstr(err, sizeof err);
				vtrerror(r, err);
			}
			break;
		case VtTwrite:
			p = r->tx.data;
			r->tx.data = nil;
			if(writelump(p, r->rx.score, r->tx.dtype, 0) < 0){
				rerrstr(err, sizeof err);
				vtrerror(r, err);
			}
			break;
		case VtTsync:
			flushqueue();
			flushdcache();
			break;
		}
		vtrespond(r);
	}
}