#include "dat.h"

Logbuf confbuf;

Req *cusewait;		/* requests waiting for confirmation */
Req **cuselast = &cusewait;

void
confirmread(Req *r)
{
	logbufread(&confbuf, r);
}

void
confirmflush(Req *r)
{
	Req **l;

	for(l=&cusewait; *l; l=&(*l)->aux){
		if(*l == r){
			*l = r->aux;
			if(r->aux == nil)
				cuselast = l;
			closereq(r);
			break;
		}
	}
	logbufflush(&confbuf, r);
}

static int
hastag(Fsstate *fss, int tag, int *tagoff)
{
	int i;

	for(i=0; i<fss->nconf; i++)
		if(fss->conf[i].tag == tag){
			*tagoff = i;
			return 1;
		}
	return 0;
}

int
confirmwrite(char *s)
{
	char *t, *ans;
	int allow, tagoff;
	ulong tag;
	Attr *a;
	Fsstate *fss;
	Req *r, **l;

	a = parseattr(s);
	if(a == nil){
		werrstr("empty write");
		return -1;
	}
	if((t = strfindattr(a, "tag")) == nil){
		werrstr("no tag");
		return -1;
	}
	tag = strtoul(t, 0, 0);
	if((ans = strfindattr(a, "answer")) == nil){
		werrstr("no answer");
		return -1;
	}
	if(strcmp(ans, "yes") == 0)
		allow = 1;
	else if(strcmp(ans, "no") == 0)
		allow = 0;
	else{
		werrstr("bad answer");
		return -1;
	}
	r = nil;
	tagoff = -1;
	for(l=&cusewait; *l; l=&(*l)->aux){
		r = *l;
		if(hastag(r->fid->aux, tag, &tagoff)){
			*l = r->aux;
			if(r->aux == nil)
				cuselast = l;
			break;
		}
	}
	if(r == nil || tagoff == -1){
		werrstr("tag not found");
		return -1;
	}
	fss = r->fid->aux;
	fss->conf[tagoff].canuse = allow;
	rpcread(r);
	return 0;
}

void
confirmqueue(Req *r, Fsstate *fss)
{
	int i, n;
	char msg[1024];

	if(*confirminuse == 0){
		respond(r, "confirm is closed");
		return;
	}

	n = 0;
	for(i=0; i<fss->nconf; i++)
		if(fss->conf[i].canuse == -1){
			n++;
			snprint(msg, sizeof msg, "confirm tag=%lud %A", fss->conf[i].tag, fss->conf[i].key->attr);
			logbufappend(&confbuf, msg);
		}
	if(n == 0){
		respond(r, "no confirmations to wait for (bug)");
		return;
	}
	*cuselast = r;
	r->aux = nil;
	cuselast = &r->aux;
}

/* Yes, I am unhappy that the code below is a copy of the code above. */

Logbuf needkeybuf;
Req *needwait;		/* requests that need keys */
Req **needlast = &needwait;

void
needkeyread(Req *r)
{
	logbufread(&needkeybuf, r);
}

void
needkeyflush(Req *r)
{
	Req **l;

	for(l=&needwait; *l; l=&(*l)->aux){
		if(*l == r){
			*l = r->aux;
			if(r->aux == nil)
				needlast = l;
			closereq(r);
			break;
		}
	}
	logbufflush(&needkeybuf, r);
}

int
needkeywrite(char *s)
{
	char *t;
	ulong tag;
	Attr *a;
	Req *r, **l;

	a = parseattr(s);
	if(a == nil){
		werrstr("empty write");
		return -1;
	}
	if((t = strfindattr(a, "tag")) == nil){
		werrstr("no tag");
		return -1;
	}
	tag = strtoul(t, 0, 0);
	r = nil;
	for(l=&needwait; *l; l=&(*l)->aux){
		r = *l;
		if(r->tag == tag){
			*l = r->aux;
			if(r->aux == nil)
				needlast = l;
			break;
		}
	}
	if(r == nil){
		werrstr("tag not found");
		return -1;
	}
	rpcread(r);
	return 0;
}

int
needkeyqueue(Req *r, Fsstate *fss)
{
	char msg[1024];

	if(*needkeyinuse == 0)
		return -1;

	snprint(msg, sizeof msg, "needkey tag=%lud %s", r->tag, fss->keyinfo);
	logbufappend(&needkeybuf, msg);
	*needlast = r;
	r->aux = nil;
	needlast = &r->aux;
	return 0;
}

