#include <u.h>
#include <libc.h>
#include <thread.h>
#include "audio.h"
#undef pipe

static int
readline(int fd, char *buf, int nbuf)
{
	int i, x;
	
	for(i=0; i<nbuf; i++){
		if((x = read(fd, buf+i, 1)) != 1 || buf[i]=='\n'){
			if(x < 0)
				return -1;
			buf[i] = 0;
			return i;
		}
	}
	buf[nbuf-1] = 0;
	return i;
}

static int
xpopen(char *cmd, int *ret)
{
	int fd[3];
	int p1[2], p2[2], pid;
	
	if(pipe(p1) < 0)
		return -1;
	if(pipe(p2) < 0){
		close(p1[0]);
		close(p1[1]);
		return -1;
	}
	fd[0] = p1[0];
	fd[1] = p2[1];
	fd[2] = p2[1];
	if((pid = threadspawnl(fd, "rc", "rc", "-c", cmd, nil)) < 0){
		close(p1[0]);
		close(p1[1]);
		close(p2[0]);
		close(p2[1]);
		return -1;
	}
	ret[0] = p2[0];
	ret[1] = p1[1];
	return pid;
}

static int
getvolume(Audio *a, char *name, int *l, int *r)
{
	char buf[100], *p;
	
	if(fprint(a->cfd[1], "%q\n", name) < 0)
		return -1;
	if(readline(a->cfd[0], buf, sizeof buf) < 0)
		return -1;
	if(buf[0] == 'E'){
		werrstr("%s", buf+1);
		return -1;
	}
	*l = strtol(buf, &p, 0);
	if(p == buf || *p == 0){
		fprint(2, "bad response: %s\n", buf);
		*l = *r = 0;
		return -1;
	}
	*r = strtol(p, 0, 0);
	return 0;
}

static int
setvolume(Audio *a, char *name, int l, int r)
{
	char buf[100];
	if(fprint(a->cfd[1], "%q %d %d\n", name, l, r) < 0)
		return -1;
	if(readline(a->cfd[0], buf, sizeof buf) < 0)
		return -1;
	if(buf[0] == 'E'){
		werrstr("%s", buf+1);
		return -1;
	}
	if(strcmp(buf, "ok") != 0){
		fprint(2, "bad response: %s\n", buf);
		return -1;
	}
	return 0;
}

static void
audioclose(Audio *a)
{
	char buf[1024];
	close(a->fd[1]);
	while(read(a->fd[0], buf, sizeof buf) > 0)
		;
	close(a->fd[0]);
	close(a->cfd[0]);
	close(a->cfd[1]);
	if(a->apid > 0)
		postnote(PNPROC, a->apid, "kill");
	if(a->vpid > 0)
		postnote(PNPROC, a->vpid, "kill");
	free(a);
}

Audio*
openaudiossh(char *sys, int flag)
{
	char buf[100];
	int n;
	char *cmd;
	Audio *a;
	
	a = mallocz(sizeof *a, 1);
	a->fd[0] = -1;
	a->fd[1] = -1;
	a->cfd[0] = -1;
	a->cfd[1] = -1;

	if(flag&AUDIO){
		cmd = smprint("exec ssh -2q %q /usr/local/plan9/bin/aplay -i", sys);
		if((a->apid = xpopen(cmd, a->fd)) < 0){
			free(a);
			return nil;
		}
		buf[0] = 0;
		if((n = readline(a->fd[0], buf, sizeof buf)) != 2 || strcmp(buf, "ok") != 0){
			if(n > 0){
				buf[n] = 0;
				werrstr("%s", buf);
			}
			close(a->fd[0]);
			close(a->fd[1]);
			free(a);
			return nil;
		}
	}
	
	if(flag&VOLUME){
		cmd = smprint("exec ssh -2q %q /usr/local/plan9/bin/volume -i", sys);
		if((a->vpid = xpopen(cmd, a->cfd)) < 0){
			close(a->fd[0]);
			close(a->fd[1]);
			free(a);
			return nil;
		}
		if((n = readline(a->cfd[0], buf, sizeof buf)) != 2 || strcmp(buf, "ok") != 0){
			if(n > 0){
				buf[n] = 0;
				werrstr("%s", buf);
			}
			close(a->fd[0]);
			close(a->fd[1]);
			close(a->cfd[0]);
			close(a->cfd[1]);
			free(a);
			return nil;
		}
	}
	
	a->getvolume = getvolume;
	a->setvolume = setvolume;
	a->close = audioclose;
	a->blksz = 1400;	/* one ethernet packet */
	return a;
}

Audio*
openaudio(char *name, int flag)
{
	if(name == nil || strcmp(name, "local") == 0 || strncmp(name, "/dev/", 5) == 0)
		return openaudiodev(name, flag);
	return openaudiossh(name, flag);
}


