#include "tdef.h"
#include "fns.h"
#include "ext.h"

/*
 * troff10.c
 * 
 * typesetter interface
 */

int	vpos	 = 0;	/* absolute vertical position on page */
int	hpos	 = 0;	/* ditto horizontal */

extern Font fonts[MAXFONTS+1];

int	Inch;
int	Hor;
int	Vert;
int	Unitwidth;
int	nfonts;



void t_ptinit(void)
{
	int i;
	char buf[100], *p;

	hmot = t_hmot;
	makem = t_makem;
	setabs = t_setabs;
	setch = t_setch;
	sethl = t_sethl;
	setht = t_setht;
	setslant = t_setslant;
	vmot = t_vmot;
	xlss = t_xlss;
	findft = t_findft;
	width = t_width;
	mchbits = t_mchbits;
	ptlead = t_ptlead;
	ptout = t_ptout;
	ptpause = t_ptpause;
	setfont = t_setfont;
	setps = t_setps;
	setwd = t_setwd;

	/* open table for device, */
	/* read in resolution, size info, font info, etc., set params */
	if ((p = getenv("TYPESETTER")) != 0)
		strcpy(devname, p);
	if (termtab[0] == 0)
		strcpy(termtab, DWBfontdir);
	if (fontdir[0] == 0)
		strcpy(fontdir, DWBfontdir);
	if (devname[0] == 0)
		strcpy(devname, TDEVNAME);
	hyf = 1;
	lg = 1;

	sprintf(buf, "/dev%s/DESC", devname);
	strcat(termtab, buf);
	if (getdesc(termtab) < 0) {
		ERROR "can't open DESC file %s", termtab WARN;
		done3(1);
	}
	if (!ascii) {
		OUT "x T %s\n", devname PUT;
		OUT "x res %d %d %d\n", Inch, Hor, Vert PUT;
		OUT "x init\n" PUT;
	}
	for (i = 1; i <= nfonts; i++)
		setfp(i, fontlab[i], (char *) 0, 0);
	sps = EM/3;	/* space size */
	ics = EM;	/* insertion character space */
	for (i = 0; i < (NTAB - 1) && DTAB * (i + 1) < TABMASK; i++)
		tabtab[i] = DTAB * (i + 1);
	tabtab[NTAB-1] = 0;
	pl = 11 * INCH;			/* paper length */
	po = PO;		/* page offset */
	spacesz = SS;
	lss = lss1 = VS;
	ll = ll1 = lt = lt1 = LL;
	t_specnames();	/* install names like "hyphen", etc. */
}

void t_specnames(void)
{
	int	i;

	for (i = 0; spnames[i].n; i++)
		*spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
}

void t_ptout(Tchar i)
{
	int dv;
	Tchar *k;
	int temp, a, b;
	int diff;

	if (cbits(i) != '\n') {
		if (olinep >= oline + olnsize) {
			diff = olinep - oline;
			olnsize += OLNSIZE;
			if ((oline = (Tchar *)realloc((char *)oline, olnsize * sizeof(Tchar))) != NULL) {
				if (diff && olinep)
					olinep = oline + diff;
			} else {
				ERROR "Output line overflow." WARN;
				done(2);
			}
		}
		*olinep++ = i;
		return;
	}
	if (olinep == oline) {
		lead += lss;
		return;
	}

	hpos = po;	/* ??? */
	esc = 0;	/* ??? */
	ptesc();	/* the problem is to get back to the left end of the line */
	dv = 0;
	for (k = oline; k < olinep; k++) {
		if (ismot(*k) && isvmot(*k)) {
			temp = absmot(*k);
			if (isnmot(*k))
				temp = -temp;
			dv += temp;
		}
	}
	if (dv) {
		vflag++;
		*olinep++ = makem(-dv);
		vflag = 0;
	}

	b = dip->blss + lss;
	lead += dip->blss + lss;
	dip->blss = 0;
	for (k = oline; k < olinep; )
		k += ptout0(k);	/* now passing a pointer! */
	olinep = oline;
	lead += dip->alss;
	a = dip->alss;
	dip->alss = 0;
	/*
	OUT "x xxx end of line: hpos=%d, vpos=%d\n", hpos, vpos PUT;
*/
	OUT "n%d %d\n", b, a PUT;	/* be nice to chuck */
}

int ptout0(Tchar *pi)
{
	int j, k, w;
	int z, dx, dy, dx2, dy2, n;
	Tchar i;
	int outsize;	/* size of object being printed */

	w = 0;
	outsize = 1;	/* default */
	i = *pi;
	k = cbits(i);
	if (ismot(i)) {
		j = absmot(i);
		if (isnmot(i))
			j = -j;
		if (isvmot(i))
			lead += j;
		else 
			esc += j;
		return(outsize);
	}
	if (k == CHARHT) {
		xpts = fbits(i);	/* sneaky, font bits as size bits */
		if (xpts != mpts)
			ptps();
		OUT "x H %ld\n", sbits(i) PUT;
		return(outsize);
	}
	if (k == SLANT) {
		OUT "x S %ld\n", sfbits(i)-180 PUT;
		return(outsize);
	}
	if (k == WORDSP) {
		oput('w');
		return(outsize);
	}
	if (sfbits(i) == oldbits) {
		xfont = pfont;
		xpts = ppts;
	} else 
		xbits(i, 2);
	if (k == XON) {
		extern int xon;
		ptflush();	/* guarantee that everything is out */
		if (esc)
			ptesc();
		if (xfont != mfont)
			ptfont();
		if (xpts != mpts)
			ptps();
		if (lead)
			ptlead();
		OUT "x X " PUT;
		xon++;
		for (j = 1; cbits(pi[j]) != XOFF; j++)
			outascii(pi[j]);
		oput('\n');
		xon--;
		return j+1;
	}
	if (k < 040 && k != DRAWFCN)
		return(outsize);
	j = z = 0;
	if (k != DRAWFCN) {
		if (widcache[k].fontpts == (xfont<<8) + xpts  && !setwdf) {
			w = widcache[k].width;
			bd = 0;
			cs = 0;
		} else
			w = getcw(k);
		if (cs) {
			if (bd)
				w += (bd - 1) * HOR;
			j = (cs - w) / 2;
			w = cs - j;
			if (bd)
				w -= (bd - 1) * HOR;
		}
		if (iszbit(i)) {
			if (cs)
				w = -j; 
			else 
				w = 0;
			z = 1;
		}
	}
	esc += j;
	if (xfont != mfont)
		ptfont();
	if (xpts != mpts)
		ptps();
	if (lead)
		ptlead();
	/* put out the real character here */
	if (k == DRAWFCN) {
		if (esc)
			ptesc();
		w = 0;
		dx = absmot(pi[3]);
		if (isnmot(pi[3]))
			dx = -dx;
		dy = absmot(pi[4]);
		if (isnmot(pi[4]))
			dy = -dy;
		switch (cbits(pi[1])) {
		case DRAWCIRCLE:	/* circle */
			OUT "D%c %d\n", DRAWCIRCLE, dx PUT;	/* dx is diameter */
			hpos += dx;
			break;
		case DRAWELLIPSE:
			OUT "D%c %d %d\n", DRAWELLIPSE, dx, dy PUT;
			hpos += dx;
			break;
		case DRAWBUILD:
			k = cbits(pi[2]);
			OUT "D%c %d ", DRAWBUILD, dx PUT;
			if (k < ALPHABET)
				OUT "%c\n", k PUT;
			else
				ptchname(k);
			hpos += dx;
			break;
		case DRAWLINE:	/* line */
			k = cbits(pi[2]);
			OUT "D%c %d %d ", DRAWLINE, dx, dy PUT;
			if (k < ALPHABET)
				OUT "%c\n", k PUT;
			else
				ptchname(k);
			hpos += dx;
			vpos += dy;
			break;
		case DRAWARC:	/* arc */
			dx2 = absmot(pi[5]);
			if (isnmot(pi[5]))
				dx2 = -dx2;
			dy2 = absmot(pi[6]);
			if (isnmot(pi[6]))
				dy2 = -dy2;
			OUT "D%c %d %d %d %d\n", DRAWARC,
				dx, dy, dx2, dy2 PUT;
			hpos += dx + dx2;
			vpos += dy + dy2;
			break;

		case 's':	/* using 's' internally to avoid .tr ~ */
			pi[1] = '~';
		case DRAWSPLINE:	/* spline */
		default:	/* something else; copy it like spline */
			OUT "D%c %d %d", (char)cbits(pi[1]), dx, dy PUT;
			hpos += dx;
			vpos += dy;
			if (cbits(pi[3]) == DRAWFCN || cbits(pi[4]) == DRAWFCN) {
				/* it was somehow defective */
				OUT "\n" PUT;
				break;
			}
			for (n = 5; cbits(pi[n]) != DRAWFCN; n += 2) {
				dx = absmot(pi[n]);
				if (isnmot(pi[n]))
					dx = -dx;
				dy = absmot(pi[n+1]);
				if (isnmot(pi[n+1]))
					dy = -dy;
				OUT " %d %d", dx, dy PUT;
				hpos += dx;
				vpos += dy;
			}
			OUT "\n" PUT;
			break;
		}
		for (n = 3; cbits(pi[n]) != DRAWFCN; n++)
			;
		outsize = n + 1;
	} else if (k < ALPHABET) {
		/* try to go faster and compress output */
		/* by printing nnc for small positive motion followed by c */
		/* kludgery; have to make sure set all the vars too */
		if (esc > 0 && esc < 100) {
			oput(esc / 10 + '0');
			oput(esc % 10 + '0');
			oput(k);
			hpos += esc;
			esc = 0;
		} else {
			if (esc)
				ptesc();
			oput('c');
			oput(k);
			oput('\n');
		}
	} else {
		if (esc)
			ptesc();
		ptchname(k);
	}
	if (bd) {
		bd -= HOR;
		if (esc += bd)
			ptesc();
		if (k < ALPHABET)
			OUT "c%c\n", k PUT;
		else
			ptchname(k);
		if (z)
			esc -= bd;
	}
	esc += w;
	return(outsize);
}

void ptchname(int k)
{
	char *chn = chname(k);

	switch (chn[0]) {
	case MBchar:
		OUT "c%s\n", chn+1 PUT;	/* \n not needed? */
		break;
	case Number:
		OUT "N%s\n", chn+1 PUT;
		break;
	case Troffchar:
		OUT "C%s\n", chn+1 PUT;
		break;
	default:
		ERROR "illegal char type %s", chn WARN;
		break;
	}
}

void ptflush(void)	/* get us to a clean output state */
{
	if (TROFF) {
		/* ptesc(); but always H, no h */
		hpos += esc;
		OUT "\nH%d\n", hpos PUT;
		esc = 0;
		ptps();
		ptfont();
		ptlead();
	}
}

void ptps(void)
{
	int i, j, k;

	i = xpts;
	for (j = 0; i > (k = pstab[j]); j++)
		if (!k) {
			k = pstab[--j];
			break;
		}
	if (!ascii)
		OUT "s%d\n", k PUT;	/* really should put out string rep of size */
	mpts = i;
}

void ptfont(void)
{
	mfont = xfont;
	if (ascii)
		return;
	if (xfont > nfonts) {
		ptfpcmd(0, fonts[xfont].longname, 0);	/* Put the desired font in the
					 * fontcache of the filter */
		OUT "f0\n" PUT;	/* make sure that it gets noticed */
	} else
		OUT "f%d\n", xfont PUT;
}

void ptfpcmd(int f, char *s, char *longname)
{
	if (f > nfonts)		/* a bit risky? */
		f = 0;
	if (longname) {
		OUT "x font %d %s %s\n", f, s, longname PUT;
	} else {
		OUT "x font %d %s\n", f, s PUT;
	}
/*	OUT "f%d\n", xfont PUT;	/* need this for buggy version of adobe transcript */
				/* which apparently believes that x font means */
				/* to set the font, not just the position. */
}

void t_ptlead(void)
{
	vpos += lead;
	if (!ascii)
		OUT "V%d\n", vpos PUT;
	lead = 0;
}

void ptesc(void)
{
	hpos += esc;
	if (!ascii)
		if (esc > 0) {
			oput('h');
			if (esc>=10 && esc<100) {
				oput(esc/10 + '0');
				oput(esc%10 + '0');
			} else
				OUT "%d", esc PUT;
		} else
			OUT "H%d\n", hpos PUT;
	esc = 0;
}

void ptpage(int n)	/* called at end of each output page, we hope */
{
	int i;

	if (NROFF)
		return;
	ptlead();
	vpos = 0;
	if (ascii)
		return;
	OUT "p%d\n", n PUT;	/* new page */
	for (i = 0; i <= nfonts; i++)
		if (fontlab[i]) {
			if (fonts[i].truename)
				OUT "x font %d %s %s\n", i, fonts[i].longname, fonts[i].truename PUT;
			else
				OUT "x font %d %s\n", i, fonts[i].longname PUT;
		}
	ptps();
	ptfont();
}

void pttrailer(void)
{
	if (TROFF)
		OUT "x trailer\n" PUT;
}

void ptstop(void)
{
	if (TROFF)
		OUT "x stop\n" PUT;
}

void t_ptpause(void)
{
	if (ascii)
		return;
	ptlead();
	vpos = 0;
	pttrailer();
	ptlead();
	OUT "x pause\n" PUT;
	flusho();
	mpts = mfont = 0;
	ptesc();
	esc = po;
	hpos = vpos = 0;	/* probably in wrong place */
}
