#ifndef lint
static char *sccsid = "@(#)paren.c	1.8 (UKC) 20/12/85";
#endif  lint
# include "e.h"
# include "paren.h"

/*
 *	Tops and bottoms of the various sorts of brackets
 *	B_INTEGRAL is for the Sanders
 *	J_* versions are for the HP Laserjet's Maths fontpack which has
 *	spindly square brackets.
 *	Don't worry about all the identical strings - xstr will sort them out.
 */
static char *B_top[] = {
	"\\(lt",	/* 0	B_LCURLY */
	"\\(rt",	/* 1	B_RCURLY */
	"\\(bv",	/* 2	B_LFLOOR */
	"\\(bv",	/* 3	B_RFLOOR */
	"\\(lc",	/* 4	B_LCEILING */
	"\\(rc",	/* 5	B_RCEILING */
	"\\(lc",	/* 6	B_LSQUARE */
	"\\(rc",	/* 7	B_RSQUARE */
	"\\(lt",	/* 8	B_LROUND */
	"\\(rt",	/* 9	B_RROUND */
	"\\(bv",	/* 10	B_BAR */
	"\\(ti",	/* 11	B_INTEGRAL */
};
static char *J_top[] = {
	"\\(lt",	/* 0	B_LCURLY */
	"\\(rt",	/* 1	B_RCURLY */
	"\\(tv",	/* 2	B_LFLOOR */
	"\\(tv",	/* 3	B_RFLOOR */
	"\\(lc",	/* 4	B_LCEILING */
	"\\(rc",	/* 5	B_RCEILING */
	"\\(lc",	/* 6	B_LSQUARE */
	"\\(rc",	/* 7	B_RSQUARE */
	"\\(lt",	/* 8	B_LROUND */
	"\\(rt",	/* 9	B_RROUND */
	"\\(bv",	/* 10	B_BAR */
	"\\(ti",	/* 11	B_INTEGRAL */
};
static char **b_top = B_top;

/* does this sort of bracket have a non-\(bv centre? */
#define hascentre(type)	((type)<2)

/* Centre only applies to B_LCURLY and B_RCURLY */
static char *b_centre[] = {
	"\\(lk",	/* 0	B_LCURLY */
	"\\(rk",	/* 1	B_RCURLY */
};

/*
 *	Table of characters to use for the long vertical bits.
 *	Necessitated by the Laserjet's varying needs.
 */
static char *B_riser[] = {
	"\\(bv",	/* 0	B_LCURLY */
	"\\(bv",	/* 1	B_RCURLY */
	"\\(bv",	/* 2	B_LFLOOR */
	"\\(bv",	/* 3	B_RFLOOR */
	"\\(bv",	/* 4	B_LCEILING */
	"\\(bv",	/* 5	B_RCEILING */
	"\\(bv",	/* 6	B_LSQUARE */
	"\\(bv",	/* 7	B_RSQUARE */
	"\\(bv",	/* 8	B_LROUND */
	"\\(bv",	/* 9	B_RROUND */
	"\\(bv",	/* 10	B_BAR */
	"\\(bv",	/* 11	B_INTEGRAL */
};
static char *J_riser[] = {
	"\\(bv",	/* 0	B_LCURLY */
	"\\(bv",	/* 1	B_RCURLY */
	"\\(tv",	/* 2	B_LFLOOR */
	"\\(tv",	/* 3	B_RFLOOR */
	"\\(tv",	/* 4	B_LCEILING */
	"\\(tv",	/* 5	B_RCEILING */
	"\\(tv",	/* 6	B_LSQUARE */
	"\\(tv",	/* 7	B_RSQUARE */
	"\\(bv",	/* 8	B_LROUND */
	"\\(bv",	/* 9	B_RROUND */
	"\\(bv",	/* 10	B_BAR */
	"\\(bv",	/* 11	B_INTEGRAL */
};
static char **b_riser = B_riser;

static char *B_bottom[] = {
	"\\(lb",	/* 0	B_LCURLY */
	"\\(rb",	/* 1	B_RCURLY */
	"\\(lf",	/* 2	B_LFLOOR */
	"\\(rf",	/* 3	B_RFLOOR */
	"\\(bv",	/* 4	B_LCEILING */
	"\\(bv",	/* 5	B_RCEILING */
	"\\(lf",	/* 6	B_LSQUARE */
	"\\(rf",	/* 7	B_RSQUARE */
	"\\(lb",	/* 8	B_LROUND */
	"\\(rb",	/* 9	B_RROUND */
	"\\(bv",	/* 10	B_BAR */
	"\\(bi",	/* 11	B_INTEGRAL */
};
static char *J_bottom[] = {
	"\\(lb",	/* 0	B_LCURLY */
	"\\(rb",	/* 1	B_RCURLY */
	"\\(lf",	/* 2	B_LFLOOR */
	"\\(rf",	/* 3	B_RFLOOR */
	"\\(tv",	/* 4	B_LCEILING */
	"\\(tv",	/* 5	B_RCEILING */
	"\\(lf",	/* 6	B_LSQUARE */
	"\\(rf",	/* 7	B_RSQUARE */
	"\\(lb",	/* 8	B_LROUND */
	"\\(rb",	/* 9	B_RROUND */
	"\\(bv",	/* 10	B_BAR */
	"\\(bi",	/* 11	B_INTEGRAL */
};
static char **b_bottom = B_bottom;

paren(leftc, p1, rightc) int p1, leftc, rightc; {
	int n, m, h1, b1, v;
	h1 = eht[p1]; b1 = ebase[p1];
	yyval = p1;
	lfont[yyval] = rfont[yyval] = 0;
	n = (h1 + EM(1.0, EFFPS(ps)) - 1) / EM(1.0, EFFPS(ps));
	if( n<2 ) n = 1;
	m = n-2;
	switch (ttype) {
	case DEVSAN:
		break;
	default:
		if (leftc=='{' || rightc == '}') {
			n = n%2 ? n : ++n;
			if( n<3 ) n=3;
			m = n-3;
		}
	}
	eht[yyval] = VERT( EM(n, ps) );
	ebase[yyval] = b1 + (eht[yyval]-h1)/2;
	v = b1 - h1/2 + VERT( EM(0.4, ps) );
	v = 0;	/* BUG??? */
	printf(".ds %d \\|\\v'%du'", yyval, v);
	switch( leftc ) {
		case 'n':	/* nothing */
		case '\0':
			break;
		case 'f':	/* floor */
			brack2(B_LFLOOR, n); break;
		case 'c':	/* ceiling */
			brack2(B_LCEILING, n); break;
		case '{':
			brack2(B_LCURLY, n); break;
		case '[':
			brack2(B_LSQUARE, n); break;
		case '(':
			brack2(B_LROUND, n); break;
		case '|':
			brack2(B_BAR, n); break;
		default:
			brack(m, (char *) &leftc, (char *) &leftc, (char *) &leftc);
			break;
		}
	printf("\\v'%du'\\*(%d", -v, p1);
	if( rightc ) {
		if (ttype == DEV202)
			printf("\\v'%du'", v);
		else
			printf("\\|\\v'%du'", v);
		switch( rightc ) {
			case 'f':	/* floor */
				brack2(B_RFLOOR, n); break;
			case 'c':	/* ceiling */
				brack2(B_RCEILING, n); break;
			case '}':
				brack2(B_RCURLY, n); break;
			case ']':
				brack2(B_RSQUARE, n); break;
			case ')':
				brack2(B_RROUND, n); break;
			case '|':
				brack2(B_BAR, n); break;
			default:
				brack(m, (char *) &rightc, (char *) &rightc, (char *) &rightc);
				break;
		}
		printf("\\v'%du'", -v);
	}
	putchar('\n');
	if(dbg)printf(".\tcurly: h=%d b=%d n=%d v=%d l=%c, r=%c\n", 
		eht[yyval], ebase[yyval], n, v, leftc, rightc);
}

brack(m, t, c, b) int m; char *t, *c, *b; {
	int j;
	printf("\\b'%s", t);
	for( j=0; j<m; j++)
		printf("%s", c);
	printf("%s'", b);
}

/*
 *	brack2: better bracket building function, implemented for the
 *	benefit of the sanders whose bracket parts are only 0.7 ems high.
 *	type	one of the B_* defines
 *	height	of the bracket in ems
 *	If type is B_LCURLY or B_RCURLY, height must be an odd number.
 */

brack2(type, height)
int type, height;
{
	switch (ttype) {
	case DEVSAN: {
		/* The height of the Sanders' bracketty bits is 0.7 ems,
		 * ie. from the baseline to the top of capital letters */

		int nsegments;	/* number of bits required (may overlap) */
		int step;	/* distance between centres of adjacent bits in units. Should be <= 0.7 em */
		double dheight;	/* double copy of height; maybe arg should be double anyway */
		char tmp[32];	/* for sprintfing into */
		int disp = 0;	/* how far we have moved from the baseline */
		register int i;

		dheight = (double) height;
		nsegments = (int) ( dheight / 0.7 + 0.999 );
		/* Curly brackets must have an odd number of parts. */
		if (hascentre(type) && (nsegments&1)==0) ++nsegments;
		step = EM(dheight/nsegments, ps);
		if (dbg) printf(".\tsanders construct: height = %d ems, nsegments = %d, step = %d units", height, nsegments, step);

		/* Move to top of bracket and put out top part */
		disp = EM( -(dheight-1) / 2, ps);
		printf("\\v'%du'\\z%s", disp, b_top[type]);

		/* Construct the vertical motion string. Note trailing \z */
		(void) sprintf(tmp, "\\v'%du'\\z", step);

		if (hascentre(type)) {
			/* Deal with 3-part brackets */
			for (i=(nsegments-3)/2; i>0; i--) {
				fputs(tmp, stdout);
				disp += step;
				fputs(b_riser[type], stdout);
			}
			fputs(tmp, stdout);
			disp += step;
			fputs(b_centre[type], stdout);
			for (i=(nsegments-3)/2; i>0; i--) {
				fputs(tmp, stdout);
				disp += step;
				fputs(b_riser[type], stdout);
			}
		} else {
			/* Put out appropriate number of vertical bars */
			for (i=nsegments-2; i>0; i--) {
				fputs(tmp, stdout);
				disp += step;
				fputs(b_riser[type], stdout);
			}
		}
		/* Put out bottom and move back to original height */
		printf("\\v'%du'%s\\v'%du'", step, b_bottom[type], -(disp + step) );
		break;
	}
	case DEVJETJ:
		b_top = J_top;
		b_riser = J_riser;
		b_bottom = J_bottom;
		/* otherwise as normal... */
	default:
		/* All other typesetters */
		if (height <= 1) {
			switch (type) {
			case B_LCEILING:
			case B_RCEILING:
				fputs(b_top[type], stdout);
				return;

			case B_LFLOOR:
			case B_RFLOOR:
				fputs(b_bottom[type], stdout);
				return;
			}
		}
		printf("\\b'%s",b_top[type]);
		if (hascentre(type)) {
			register int i;

			for (i=(height-3)/2; i>0; i--)
				fputs(b_riser[type], stdout);
			fputs(b_centre[type], stdout);
			for (i=(height-3)/2; i>0; i--)
				fputs(b_riser[type], stdout);
		} else {
			register int i;

			for (i=height-2; i>0; i--) fputs(b_riser[type], stdout);
		}
		printf("%s'", b_bottom[type]);
	}
}
