/*	Copyright (c) 1988 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*	@(#)picasso:blockgen.c	1.0	*/
#include	"picasso.h"
#include	"y.tab.h"

#define	NBRACK	20	/* depth of [...] */
#define	NBRACE	20	/* depth of {...} */

struct	pushstack stack[NBRACK];
int	nstack	= 0;
struct	pushstack bracestack[NBRACE];
int	nbstack	= 0;
obj	*cur_block = (obj *)0;

obj *leftthing(c)	/* called for {... or [... */
			/* really ought to be separate functions */
	int c;
{
	obj *p;

	if (c == '[') {
		if (nstack >= NBRACK)
			fatal("[...] nested too deep");
		stack[nstack].p_x = curx;
		stack[nstack].p_y = cury;
		stack[nstack].p_hvmode = hvmode;
		stack[nstack].p_redo = redo_gbox;
		stack[nstack].p_xmin = Gbox[0];
		stack[nstack].p_ymin = Gbox[1];
		stack[nstack].p_xmax = Gbox[2];
		stack[nstack].p_ymax = Gbox[3];
		nstack++;
		Gbox[0] = Gbox[1] = 32767;
		Gbox[2] = Gbox[3] = -32767;
		p = makenode(BLOCK, N_VAL+2, (int)getfval("curlayer"));
		curx = cury = 0;
		cur_block = p;
	} else {
		if (nbstack >= NBRACK)
			fatal("{...} nested too deep");
		bracestack[nbstack].p_x = curx;
		bracestack[nbstack].p_y = cury;
		bracestack[nbstack].p_hvmode = hvmode;
		nbstack++;
		p = NULL;
	}
	return(p);
}

obj *rightthing(p, c)	/* called for ... ] or ... } */
	obj *p;
{
	obj *q;

	if (c == '}') {
		nbstack--;
		curx = bracestack[nbstack].p_x;
		cury = bracestack[nbstack].p_y;
		hvmode = bracestack[nbstack].p_hvmode;
		q = makenode(MOVE, 0, 0);
	} else {
		nstack--;
		hvmode = stack[nstack].p_hvmode;
		q = makenode(BLOCKEND, 0, p->o_layer);
		cur_block = p->o_parent;
		curx = stack[nstack].p_x;
		cury = stack[nstack].p_y;
		p->o_val[N_VAL+0].o = q;
		p->o_val[N_VAL+1].s = stack[nstack+1].p_symtab;
	/*  If redo_gbox is set we need to recalculate the bounding box
	 *  for this block.
	 */
		if (redo_gbox) {
		    obj	    *o;
		    float   bnd[4];

		    Gbox[0] = Gbox[1] = - (Gbox[2] = Gbox[3] = -32767);
		    for (o = q->o_prev; o != p; o = o->o_prev) {
			if (o->o_type == BLOCKEND)
			    o = o->o_parent;
			if (o->o_type > TEXT)	/* a MOVE could have text? */
			    continue;
			get_bounds(o, bnd, 0);
			track_bounds(bnd[0], bnd[1], bnd[2], bnd[3]);
		    }
		}
		redo_gbox = stack[nstack].p_redo;
		p->o_x   = (Gbox[2]+Gbox[0])/2;
		p->o_wid = (Gbox[2]-Gbox[0]);
		if (p->o_wid < 0)		p->o_wid = 0;
		p->o_y   = (Gbox[3]+Gbox[1])/2;
		p->o_ht  = (Gbox[3]-Gbox[1]);
		if (p->o_ht < 0)		p->o_ht = 0;
		Gbox[0] = stack[nstack].p_xmin;
		Gbox[1] = stack[nstack].p_ymin;
		Gbox[2] = stack[nstack].p_xmax;
		Gbox[3] = stack[nstack].p_ymax;
	}
	return(q);
}

obj *blockgen(p)	/* handles [...] */
	obj *p;
{
	float	h, w, xwith, ywith;
	float	ctrx, ctry, x0, y0, x1, y1;
	int	i, at, with;
	obj	*ppos;
	Attr	*ap;

	at = with = xwith = ywith = 0;
	if (ntext > ntext1)
		set_text();
	ctrx = curx + p->o_x;
	ctry = cury + p->o_y;
	w  = p->o_wid;
	h  = p->o_ht;
	for (i = 0; i < nattr; i++) {
		ap = &attr[i];
		switch (ap->a_type) {
		case HEIGHT:
			h = ap->a_val.f;
			break;
		case WIDTH:
			w = ap->a_val.f;
			break;
		case WITH:
			with = ap->a_val.i;	/* corner */
			break;
		case PLACE:	/* actually with position ... */
			ppos = ap->a_val.o;
			xwith = p->o_x - Xformx(ppos, 1, ppos->o_x, ppos->o_y);
			ywith = p->o_y - Xformy(ppos, 0, ppos->o_x, ppos->o_y);
			with = PLACE;
			break;
		case AT:
		case FROM:
			ppos = ap->a_val.o;
			ctrx = Xformx(ppos, 1, ppos->o_x, ppos->o_y);
			ctry = Xformy(ppos, 0, ppos->o_x, ppos->o_y);
			at++;
			break;
		case LAYER:
			if ((p->o_layer = (int)ap->a_val.f) > top_layer)
				top_layer = p->o_layer;
			break;
		case FONT:
			reset_font((double)ap->a_val.f);
			break;
		case SIZE:
			reset_size(ap->a_sub, (double)ap->a_val.f);
			break;
		case SPACE:
			reset_space(ap->a_sub, (double)ap->a_val.f);
			break;
		case TEXTATTR:
			savetext(ap->a_sub, ap->a_val.p);
			break;
		case TCOLOR:
			p->o_text = checkcolor((double)ap->a_val.f);
			break;
		}
	}
#if 0
/*	This appears to be unnecessary (and even undesireable!) */
	if (!at && !with)
		with = isright(hvmode) ? WEST : isleft(hvmode) ? EAST :
				isup(hvmode) ? SOUTH : NORTH;
#endif
	if (with) {
		switch (with) {
		case NORTH:	ywith = -h/2;			break;
		case SOUTH:	ywith =  h/2;			break;
		case EAST:	xwith = -w/2;			break;
		case WEST:	xwith =  w/2;			break;
		case NE:	xwith = -w/2;	ywith = -h/2;	break;
		case SE:	xwith = -w/2;	ywith =  h/2;	break;
		case NW:	xwith =  w/2;	ywith = -h/2;	break;
		case SW:	xwith =  w/2;	ywith =  h/2;	break;
		}
		ctrx += xwith;
		ctry += ywith;
	}
	x0 = ctrx - w / 2;
	x1 = ctrx + w / 2;
	y0 = ctry - h / 2;
	y1 = ctry + h / 2;
	p->o_nt1 = ntext1;
	p->o_nt2 = ntext;
	if (ntext > ntext1) {
		ntext1 = ntext;
		checktextcolor(p);
	}
	translate(p, ctrx - p->o_x, ctry - p->o_y);
	text_bounds(p);
	if (isright(hvmode))
		curx = x1;
	else if (isleft(hvmode))
		curx = x0;
	else if (isup(hvmode))
		cury = y1;
	else
		cury = y0;
	stack[nstack+1].p_symtab = NULL;	/* so won't be found again */
	return(p);
}
