/*
 * DATlib   Copyright (c) 1995-1996 Marcus Meissner &
 *          Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *          All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Marcus Meissner
 *    at the Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *
 * 4. The name of the University or the author may not be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE AUTHOR ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR THE AUTHOR BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* $Id: cd2dat.c,v 1.2 1997/08/06 14:54:01 msmeissn Exp $
 *
 * $Log: cd2dat.c,v $
 * Revision 1.2  1997/08/06 14:54:01  msmeissn
 * +usage
 *
 * Revision 1.1  1997/03/16 20:27:25  msmeissn
 * Initial revision
 *
 *
 * cd2dat.c: Write zoocd files to audio-DAT
 */

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/fcntl.h>

#include "dataudiolib.h"

#define MAPLAY "maplay"
#define ZOO "zoo"

void copy2cd(int fd,char *an,char *fn);

struct track {
	char	*an;
	char	*fn;
	char	*workmandb;
	char	*name;
	struct	da_catalognr	cat;
	int	length;
} *tracks=NULL;
int	nroftracks=0;

char*
find_file(char *fn,char **paths) {
	struct	stat	stbuf;
	char	*fullfn,**path;

	path=paths;
	if (-1!=stat(fn,&stbuf))
		return strdup(fn);
	while (*path) {
		fullfn=malloc(strlen(*path)+strlen(fn)+2);
		sprintf(fullfn,"%s/%s",*path,fn);
		if (-1!=stat(fullfn,&stbuf))
			return fullfn;
		path++;
		free(fullfn);
	}
	/* fn mit ".zoo" dahinter? */
	return NULL;
}

void
add_track(char *an,char *fn) {
	int	tnr,i,curtrack;
	char	*xp,*s;
	FILE	*I;
	char	buf[200];
	char	*artist=0,*track=0;

	curtrack=0;
	sscanf(fn,"t%d.mp2",&tnr);
	tracks=(struct track*)realloc(tracks,sizeof(struct track)*(nroftracks+1));
	tracks[nroftracks].an=strdup(an);
	tracks[nroftracks].fn=strdup(fn);
	tracks[nroftracks].length=0;
	memset(tracks[nroftracks].cat.nr,'0',13); /* yes, '0' */
	tracks[nroftracks].cat.nr[13]='\0';
	/* load workmandb from zoo file */
	xp=(char*)malloc(strlen(an)+strlen(ZOO" xpq workmandb  "));
	sprintf(xp,ZOO" xpq %s workmandb",an);
	I=popen(xp,"r");
	while (NULL!=fgets(buf,200,I)) {
		if (buf==strstr(buf,"tracks ")) {
			int	nr,last,cur;
			/* main TOC useable line */
/*#tracks 12 150 6307 27912 44322 54542 71562 87232 100210 109202 131440 163430 187002 3293*/
/* nroftracks on this CD, start1,...,startn, length */
			s=buf+7;
			if (!sscanf(s,"%d",&nr))
				continue;
			if (tnr>nr)
				continue;
			for (i=0;i<tnr-1;i++) {
				s=strchr(s,' ');
				if(s==NULL) break;
				s++;
			}
			if (s==NULL)			continue;
			if (!sscanf(s,"%d",&last))	continue;
			s=strchr(s,' ');
			if(s==NULL)
				continue;
			s++;
			if (!sscanf(s,"%d",&cur))	continue;
			if (cur<last)			continue;
			tracks[nroftracks].length=cur-last;
			continue;
		}
		if (buf==strstr(buf,"ean ")) {
			/* catalog nr */
/*#ean 45-09910-1020-30*/
			struct da_catalognr	cat;
			s=buf+4;i=0;
			while (*s) {
				if (*s>='0' && *s<='9') {
					cat.nr[i++]=*s;
					if (i==13) break;
				}
				s++;
			}
			while (i<13)
				cat.nr[i++]='0';
			cat.nr[13]='\0';
			memcpy(&(tracks[nroftracks].cat),&cat,sizeof(cat));
			continue;
		}
		if (buf==strstr(buf,"artist ")) {
			artist=strdup(strchr(buf,' ')+1);
			*strchr(artist,'\n')=0;
			continue;
		}
		if (buf==strstr(buf,"track ")) {
			curtrack++;
			if (curtrack==tnr) {
				track=strdup(strchr(buf,' ')+1);
				*strchr(track,'\n')=0;
			}
			continue;
		}
	}
	pclose(I);
	free(xp);
	if (!artist) artist=strdup("");
	if (!track) track=strdup("");
	tracks[nroftracks].name=malloc(strlen(artist)+strlen(track)+strlen(" - ")+1);
	sprintf(tracks[nroftracks].name,"%s - %s",artist,track);
	fprintf(stderr,"added %s(%s) length %d EAN=%s, NAME=%s\n",
		fn,an,tracks[nroftracks].length,tracks[nroftracks].cat.nr,
		tracks[nroftracks].name
	);
	nroftracks++;
}

void
generate_cd(int fd) {
	int	i,res,curleft,pnr;
	struct	da_time	datime;
	FILE	*I;
	unsigned char buf[2000];
	char	*xp;
	struct	da_tocentry	toc;

	/* set prerecorded flag , so tracknumbers will be written over
	 * the whole tape
	 */
	/*
	i=1;
	if (-1==da_control(fd,DA_SET_PRERECORDED,(long)&i))
		perror("da_control DA_SET_PROGNR");
	 */
	i=1;
	if (-1==da_control(fd,DA_SET_PROGNR,(long)&i))
		perror("da_control DA_SET_PROGNR");
	toc.value=DA_TOC_ENTRIES;
	toc.prognr=nroftracks; /* +1 ? */
	toc.name=NULL;
	if (-1==da_control(fd,DA_SET_TOCENTRY,(long)&toc))
		perror("da_control TOCENT1");

	toc.prognr=1;
	toc.hour=toc.minute=toc.second=toc.frame=0;
	toc.value=DA_TOC_START;
	toc.name=NULL;
	if (-1==da_control(fd,DA_SET_TOCENTRY,(long)&toc))
		perror("da_control TOCENT2");

	toc.value=1;
	toc.name=tracks[0].name;
	for (i=0;i<nroftracks;i++) {
		if (-1==da_control(fd,DA_SET_TOCENTRY,(long)&toc))
			perror("da_control TOCENT3");
		toc.prognr++;
		toc.frame+=tracks[i].length*32/75;
		toc.name=tracks[i].name;
		toc.second+=toc.frame/32;
		toc.frame=toc.frame%((toc.second&1)+32);
		toc.minute+=toc.second/60;
		toc.second=toc.second%60;
		toc.hour+=toc.minute/60;
		toc.minute=toc.minute/60;
	}
	toc.value=DA_TOC_END;
	toc.name=NULL;
	if (-1==da_control(fd,DA_SET_TOCENTRY,(long)&toc))
		perror("da_control TOCENT4");
	for (i=0;i<nroftracks;i++) {
		struct da_time	xtime;
		if (-1==da_control(fd,DA_SET_CATALOG,(long)&(tracks[i].cat)))
			perror("da_control SET_CATALOG");
		if (-1==da_control(fd,DA_SET_TRACKNAME,(long)tracks[i].name))
			perror("da_control SET_TRACKNAME");
		xtime.frame=tracks[i].length*32/75;
		xtime.second=xtime.frame/32;
		xtime.frame = xtime.frame%((toc.second&1)+32);
		xtime.minute = xtime.second/60;
		xtime.second = xtime.second%60;
		xtime.hour = xtime.minute/60;
		xtime.minute = xtime.minute%60;
		if (-1==da_control(fd,DA_SET_TRACKTIME,(long)&xtime))
			perror("da_control SET_TRACKTIME");
		fprintf(stderr,"copying %s:|%s|\n",tracks[i].an,tracks[i].fn);
		xp=(char*)malloc(strlen(tracks[i].an)+strlen(tracks[i].fn)+5+strlen(ZOO" xpq|"MAPLAY" - -s"));
		sprintf(xp,ZOO" xpq %s %s|"MAPLAY" -s -",tracks[i].an,tracks[i].fn);
		I=popen(xp,"r");
		free(xp);
		while (!feof(I)) {
			curleft=0;
			while (curleft<2000) {
			  res=fread(buf+curleft,1,2000-curleft,I);
			  if (res==-1) {
				  perror("read");
				  break;
			  }
			  if (!res) break;
			  curleft+=res;
			}
			if (res<0) break;
			if (-1==da_write(fd,buf,2000))
				break;
		}
		pclose(I);
		/* advance one song */
		da_control(fd,DA_GET_PROGNR,(long)&pnr);
		pnr++;
		da_control(fd,DA_SET_PROGNR,(long)&pnr);
		da_control(fd,DA_GET_PROGTIME,(long)&datime);
		datime.indexnr	=
		datime.hour	=
		datime.minute	=
		datime.second	=
		datime.frame	= 0;
		da_control(fd,DA_SET_PROGTIME,(long)&datime);
	}
}


void usage() {
	fprintf(stderr,
"Usage: cd2dat [cds]*\n"
"	cd2dat copies CD from the I4CD CD archive to DAT. You can specify\n"
"	multiple CDs on the commandline, format:\n"
"		CDNAME.zoo	 		- record whole CD\n"
"		CDNAME.zoo:<nr>,<nr1>-<nr2>,... - record only selected titles\n"
"						  ranges\n"
"	Tracks will start at 1.\n"
	);
}

int
main(int argc,char **argv) {
	int	from,to,i,j,k,fd;
	char	*tape;
	char	*buf,*s,*cdcacheenv,**cdpaths;
	int	xsamplerate;
	FILE	*I;

	tape=getenv("TAPE");
	if (!tape) tape=DEFAULTAUDIOTAPE;
	if (argc<2) { usage(); exit(0); }
	for (i=1;i<argc;i++) {
		if (	!strcmp(argv[i],"--help") ||
			!strcmp(argv[i],"-h")
		) {
			usage();exit(0);
		}
	}
			
	fd=da_open(tape,O_WRONLY);
	if (fd==-1) {
		fprintf(stderr,"%s:da_open:could not open ",argv[0]);
		perror(tape);
		exit(1);
	}
/*	if (-1==da_control(fd,DA_WRITE_LEADIN,0))
		perror("da_control DA_WRITE_LEADIN");
 */
	xsamplerate=44100;
	if (-1==da_control(fd,DA_SET_SAMPLERATE,(long)&xsamplerate))
		perror("da_control DA_SET_SAMPLERATE");

/* CD MAGIC */
	/* CD_CACHE_PATH=blabla:foofoo*/
	cdcacheenv=getenv("CD_CACHE_PATH");
	if (cdcacheenv==NULL)
		cdcacheenv="/proj/i4cd/cache/:.";
	cdcacheenv=strdup(cdcacheenv);
	s=cdcacheenv;
	for (i=0;(s=strchr(s,':'));s++,i++)
		/*EMPTY*/;
	cdpaths=(char**)malloc((i+2)*sizeof(char*));
	s=cdcacheenv;cdpaths[0]=s;
	for (i=1;(s=strchr(s,':'));s++,i++)
		cdpaths[i]=s;
	cdpaths[i]=NULL;

	for (i=1;i<argc;i++) {
		char	*argx,*b,*f,*c;
		if (NULL==(b=strchr(argv[i],':'))) {
			/* the whole CD */
			f=find_file(argv[i],cdpaths);
			if (f==NULL)
				continue;
			b=(char*)malloc(strlen(f)+2+strlen(ZOO" l "));
			sprintf(b,ZOO" l %s",f);
			I=popen(b,"r");
			free(b);
			buf=(char*)malloc(200);
			while (NULL!=fgets(buf,100,I)) {
				if (NULL!=(b=strstr(buf,".mp2"))) {
					while (*b!=' ') b--;
					b++;
					c=b;
					while (*c!='\n')
						c++;
					*c='\0';
					add_track(f,b);

				}
			}
			free(buf);
			free(f);
			pclose(I);
		} else {
			char	*c,*d,*arg;
			argx=strdup(argv[i]);
			b=strchr(argx,':');
			*b++='\0';
			arg=b;
			f=find_file(argx,cdpaths);
			if (f==NULL) {
				free(argx);
				continue;
			}
			to=0;
			from=10000;
			/* b parsen. hmm */
			/* <nr>[,<nr>]* 
			 * <nr>-
			 * -<nr>
			 * <nr>-<nr>
			 */
			b=(char*)malloc(strlen(f)+2+strlen(ZOO" l "));
			sprintf(b,ZOO" l %s",f);
			I=popen(b,"r");
			free(b);
			buf=(char*)malloc(200);
			while (NULL!=fgets(buf,100,I)) {
				if (NULL!=(b=strstr(buf,".mp2"))) {
					while (*b!=' ') b--;
					b++;
					if (sscanf(b,"t%d.mp2",&j)) {
						if (j<from)	from=j;
						if (j>to)	to=j;
					}
				}
			}
			free(buf);
			pclose(I);
			b=arg;
			while(1) {
				char	*e;
				e=(char*)malloc(10);
				c=strchr(b,',');
				if (c!=NULL) *c++='\0';
				if (NULL==(d=strchr(b,'-'))) {
					sprintf(e,"t%s.mp2",b);
					add_track(f,e);
				} else {
					if (1==sscanf(b,"-%d",&j)) {
						for (k=1;k<j;k++) {
							sprintf(e,"t%d.mp2",k);
							add_track(f,e);
						}
					} else {
						if (2==sscanf(b,"%d-%d",&j,&k)) {
							for (;j<=k;j++) {
								sprintf(e,"t%d.mp2",j);
								add_track(f,e);
							}
						} else {
							if (1==sscanf(b,"%d-",&j)) {
								for (k=j;k<=to;k++) {
									sprintf(e,"t%d.mp2",k);
									add_track(f,e);
								}
							}
						}
					} 
				}
				free(e);
				if (c==NULL) break;
				b=c;
			}
		}
	}
	generate_cd(fd);
	if (-1==da_control(fd,DA_WRITE_LEADOUT,0))
		perror("da_control DA_WRITE_LEADOUT");
	da_close(fd);
	return 0;
}
