#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include "config.h"
#include "alloc.h"

#define PREFIX			"batch"
#define BATCHSIZE		49152
#define BATCHNAMELEN	128

#define SYSNAMESIZ		12
#define NAMESIZ			32

batchit(struct _parms *p, char *fname, char *pfx);

extern char *optarg;
char *progname;
struct _parms {
	long bsize, nque;
	char *prgb, *prgc, *prgx;
} defparms, sysparms;

void usage(int ier, char *fmt, ...)
{
	if (fmt && *fmt) {
		va_list args;

		va_start(args, fmt);
		vprintf(fmt, args);
		va_end(args);
	}
	printf("Usage:  %s [-S system] [-s size] [-p prefix] -f batch\n", progname);
	exit( ier );
	/* NOTREACHED */
}

void saveparms(struct _parms *p, long sz, long nq, char *pb, char *pc, char *px)
{
	p->bsize = sz;
	p->nque  = nq;
	p->prgb  = strsave(pb);
	p->prgc  = strsave(pc);
	p->prgx  = strsave(px);
}

struct _parms *readparms(char *sys)
{
	FILE *bp;
	char buff[BUFSIZ];
	char name[SYSNAMESIZ], prgb[NAMESIZ], prgc[NAMESIZ], prgx[NAMESIZ];
	long bsize, nque;

	if (bp = fopen(ctlfile("batch/batchparms"), "r")) {
		while (fgets(buff, sizeof(buff), bp)) {
			if (*buff == '#' || *buff == '\n')
				continue;
			if (sscanf(buff, "%s %ld %ld %s %s %s",
				name, &bsize, &nque, prgb, prgc, prgx) != 6)
					printf("Invalid line in batchparms ignored\n");
			if (bsize <= 0 || nque < 0)
				continue;
			if (!strcmp("default", name))
				saveparms(&defparms, bsize, nque, prgb, prgc, prgx);
			else if (!strcmp(sys, name)) {
				saveparms(&sysparms, bsize, nque, prgb, prgc, prgx);
				break;
			}
		}
		fclose(bp);
	}
	return( sysparms.bsize ? &sysparms : defparms.bsize ? &defparms : 0 );
}

main(int argc, char **argv)
{
	char *prefix = PREFIX, *system = NULL, *file = NULL;
	struct _parms *parms;
	size_t batchsize = 0;
	int ch;

	if ((progname=strrchr(*argv, ':')) || (progname=strrchr(*argv, '/')))
		progname++;
	else
		progname = *argv;

	while ((ch = getopt(argc, argv, "S:f:p:s:")) != EOF)
		switch (ch) {
		case 'S' :		/* System name being batched */
			if (system)
				usage(10, "system name specified twice\n");
			system = optarg;
			break;
		case 'f' :		/* File containing the batch list */
			if (file)
				usage(10, "batch file specified twice\n");
			file = optarg;
			break;
		case 'p' :		/* Prefix for output batches */
			if (prefix)
				usage(10, "prefix specified twice\n");
			if (strlen(optarg) > BATCHNAMELEN-4)
				usage(10, "Prefix too long; max %d\n", BATCHNAMELEN-4);
			else
				prefix = optarg;
			break;
		case 's' :		/* Size constraint of batches */
			if (batchsize > 0)
				usage(10, "batchsize specified twice\n");
			ch = atoi(optarg);
			if (ch < 10240)
				usage(10, "Invalid batch size %d; min 10K\n", ch);
			else
				batchsize = ch;
			break;
		default :
			usage(10, NULL);
		}
	if (parms = readparms(system))
		exit( 10 );
	if (batchsize > 0)
		parms->bsize = batchsize;
	if (!batchit(parms, file, prefix))
		usage(10, "system %s: can't batch from %s!\n", system, file);
	return( 0 );
}

batchit(register struct _parms *p, char *fname, char *pfx)
{
	static char buf[32 * BUFSIZ];			/* 32K buffer */

	char name[BATCHNAMELEN];
	char batchname[BATCHNAMELEN];
	int fdb = 0, batchcount = 0;
	int current;
	FILE *fpr;

	register int art;
	register size_t len;
	register size_t ttlsofar = 0;

	if (fpr = fopen(fname, "r")) {
		while (fscanf(fpr, "%s %ld\n", name, &current) == 2) {
			if (current+ttlsofar > p->bsize || (!ttlsofar && current > p->bsize)) {
				if (fdb)
					close(fdb);
				ttlsofar = 0;
				fdb = 0;
			}
			if (!fdb) {
				sprintf(batchname, "%s_%04d", pfx, ++batchcount);
				fdb = open(batchname, O_WRONLY | O_CREAT | O_TRUNC);
				if (fdb == -1) {
					perror(batchname);
					exit( 10 );
				}
			}
			if ((art = open(artfile(name), O_RDONLY)) != -1) {
				sprintf(buf, "#! rnews %ld\n", current);
				ttlsofar += write(fdb, buf, strlen(buf));
				while ((len = read(art, buf, sizeof(buf))) > 0)
					if (write(fdb, buf, len) != len) {
						perror(batchname);
						exit( 10 );
					}
				close(art);
				ttlsofar += current;
			} else
				perror(artfile(name));
		}
		fclose(fpr);
	} else
		perror(fname);
	return( 0 );
}
