/* MBK : Management functions of the visualisation database
 			Version : 1.0
 			Date		: 11/06/90 */

#include <stdio.h>
#include MUT_H
#include MPH_H
#include "mbk_extern.h"
#include "g_visu.h"
#include "g_extern.c"
#include "v_view.h"
#include "v_extern.h"

LAMBDA xab2fig, yab2fig;

/* insert_visu : adds a descriptor in the database */
void insert_visu (ptdesc, typedesc)
X_RECT *ptdesc;
unsigned char typedesc;
{
X_RECT *pt;

#ifdef TRACE
	fprintf(stderr, "insert_visu : ptdesc= %#x typedesc= %#x\n",
					 ptdesc, typedesc);
#endif

	pt = visu_db[typedesc];
	visu_db[typedesc] = ptdesc;
	ptdesc->NEXT = pt;

	if (run_mode != RUN)
		V_drawBox(ptdesc, (int)typedesc);
}

/* del_cache : frees space allocated for the database */
void del_cache ()
{
X_RECT *pt, *aux;
register int i;

	for (i = 0; i <= DEFAULT_LAYER; i++){
			pt = visu_db[i];
			while (pt) {
					aux = pt->NEXT;
					mbkfree((char *)pt);
					pt = aux;
			}
			visu_db[i] = NULL;
	}
	ptinsref = NULL;
	xabfig = yabfig = xab2fig = yab2fig = 0;
}

/* fill_trans : adds a transistor into the database as two segments */
X_RECT *fill_trans (ptseg, indicepoly, indicedif)
phseg_list *ptseg;
unsigned char indicepoly, indicedif;
{
LAMBDA x, y, dx, dy, x1, y1, dx1, dy1;
X_RECT *ptdesc, *ptdescpoly;

	trans_coord(ptseg, xvisufig, &x, &y, &dx, &dy, &x1, &y1, &dx1, &dy1,
					 tablayer[indicepoly].EXT, tablayer[indicedif].EXT);

   /* subminimal transistor size imply this check for proper display */
	if (dx1 != 0 && dy1 != 0) {
		ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
		ptdesc->X = x1;
		ptdesc->Y = y1 + dy1;
		ptdesc->DX = dx1;
		ptdesc->DY = dy1;
		ptdesc->TYPE = SEG;
		ptdesc->PTMBK = (char *)ptseg;
		ptdesc->USER = NULL;
		update_BB(ptdesc); /* Uptdates bounding-box coordinates */
		insert_visu (ptdesc, indicedif);
	}

	ptdescpoly = (X_RECT *)mbkalloc(sizeof(X_RECT));
	ptdescpoly->X = x;
	ptdescpoly->Y = y + dy;
	ptdescpoly->DX = dx;
	ptdescpoly->DY = dy;
	ptdescpoly->TYPE = SEG;
	ptdescpoly->PTMBK = (char *)ptseg;
	ptdescpoly->USER = (char *)ptdesc; /* link dif. descr. to poly descr. */
	update_BB(ptdesc); /* Uptdates bounding-box coordinates */
	insert_visu(ptdescpoly, indicepoly);

	nbseg += 2;
	nbtrans++;
	return ptdescpoly;
}

/* fill_seg : adds a segment into the database */
X_RECT *fill_seg (ptseg)
phseg_list *ptseg;
{
LAMBDA x, y, dx, dy;
X_RECT *ptdesc;
unsigned char indice;

	/* If the seg. is a transistor, it must be considered as two segments */
	if (ptseg->LAYER == PTRANS)
		ptdesc = fill_trans (ptseg, get_layert (G_GATE), get_layert (PDIF));
	else if (ptseg->LAYER == NTRANS)
		ptdesc = fill_trans (ptseg, get_layert (G_GATE), get_layert (NDIF));
	else {
		indice = get_layert (ptseg->LAYER);
		seg_coord (ptseg, xvisufig, &x, &y, &dx, &dy, tablayer[indice].EXT);

		ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
		ptdesc->X = x;
		ptdesc->Y = y + dy;
		ptdesc->DX = dx;
		ptdesc->DY = dy;
		ptdesc->TYPE = SEG;
		ptdesc->PTMBK = (char *)ptseg;
		ptdesc->USER = NULL;
		/* Uptdates bounding-box coordinates */
		update_BB (ptdesc);
		insert_visu (ptdesc, indice);
		nbseg++;
	}
	return ptdesc;
}
/*	fill_via : adds a via into the database */
X_RECT *fill_via (ptvia)
phvia_list *ptvia;
{
LAMBDA x, y, dx, dy;
X_RECT *ptdesc;
char type;

#ifdef TRACE
	fprintf (stderr, "fill_via : ptvia= %#x\n", ptvia);
#endif

	via_coord (ptvia, xvisufig, &x, &y, &dx, &dy);

	if (ptvia->TYPE < C_X_N){
		ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
		ptdesc->X = x;
		ptdesc->Y = y + dy;
		ptdesc->DX = dx;
		ptdesc->DY = dy;
		ptdesc->TYPE = VIA; /* | (ptvia->TYPE << 4)*/
		ptdesc->PTMBK = (char *)ptvia;
		ptdesc->USER = NULL;
		/* Uptdates bounding-box coordinates */
		update_BB (ptdesc);
		switch (ptvia->TYPE){
			case CONT_POLY :
				type = G_CONT_POLY; 
				break;
			case CONT_DIF_N : 
				type = G_CONT_DIFN; 
				break;
			case CONT_DIF_P : 
				type = G_CONT_DIFP; 
				break;
			case CONT_BODY_N : 
				type = G_CONT_BODY_N; 
				break;
			case CONT_BODY_P : 
				type = G_CONT_BODY_P; 
				break;
			case CONT_VIA : 
				type = G_CONT_VIA; 
				break;
			case CONT_VIA2 : 
				type = G_CONT_VIA2; 
				break;
		}
		insert_visu (ptdesc, get_layert(type));
		nbvia++;
	} else {
		/* gate part of macro */
		ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
		ptdesc->X = x + 1;
		ptdesc->Y = y + dy - 1;
		ptdesc->DX = dx - 2;
		ptdesc->DY = dy - 2;
		ptdesc->TYPE = VIA; /* | (ptvia->TYPE << 4)*/
		ptdesc->PTMBK = (char *)ptvia;
		ptdesc->USER = NULL;
		/* Uptdates bounding-box coordinates */
		update_BB (ptdesc);
		insert_visu (ptdesc, get_layert (G_GATE));
		/* dif part of macro */
		ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
		ptdesc->X = x - 3;
		ptdesc->Y = y + dy + 3;
		ptdesc->DX = dx + 6;
		ptdesc->DY = dy + 6;
		ptdesc->TYPE = 0xFF; /* VIA | (ptvia->TYPE << 4);*/
		ptdesc->PTMBK = (char *)ptvia;
		ptdesc->USER = NULL;
		/* Uptdates bounding-box coordinates */
		update_BB(ptdesc);
		insert_visu(ptdesc, get_layert(ptvia->TYPE == C_X_N ? NDIF : PDIF));
		nbseg+=2;
	}
	return ptdesc;
}

/***************************************************************************
*				fill_inscon : adds an instance connector into the database						 *
***************************************************************************/
X_RECT *fill_inscon (ptcon, ptfig, ptins, sym)
phcon_list *ptcon;
phfig_list *ptfig;
X_RECT *ptins;
int sym;
{
LAMBDA x, y, dx, dy, xins, yins;
X_RECT *ptdesc;

#ifdef TRACE
	fprintf (stderr, "fill_inscon : ptcon= %#x ptfig= %#x ptins= %#x sym= %d\n",
			ptcon, ptfig, ptins, sym);
#endif

	xins = ptins->X;
	yins = ptins->Y - ptins->DY;

	ins_con_coord (ptcon, ptfig, &x, &y, &dx, &dy);
	/* connector must be symetrised */
	if (sym != NOSYM)
		make_sym (&x, &y, dx, dy, ptins->DX, ptins->DY, sym);

	/* updates coordinates with his instance */
	x += xins;
	y += yins;

	ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
	ptdesc->X = x;
	ptdesc->Y = y + dy;
	ptdesc->DX = dx;
	ptdesc->DY = dy;
	/* sym used for string drawing */
	ptdesc->TYPE = INSCON | ((unsigned char)sym << 3);
	ptdesc->PTMBK = (char *)ptcon;
	/* * A connector must keep a link with his instance for inspect function */
	ptdesc->USER = (char *)ptins;
	/* Uptdates bounding-box coordinates */
	update_BB (ptdesc);

	insert_visu (ptdesc, get_layert (ptcon->LAYER));
	nbinscon++;

	return ptdesc;
}
/*fill_insseg : adds an instance segment to the database : feed thru needs it*/
X_RECT *fill_insseg (ptseg, ptfig, ptins, sym)
phseg_list *ptseg;
phfig_list *ptfig;
X_RECT *ptins;
int sym;
{
LAMBDA x, y, dx, dy, xins, yins;
X_RECT *ptdesc;

#ifdef TRACE
	fprintf (stderr, "fill_insseg : ptseg= %#x ptfig= %#x ptins= %#x sym= %d\n",
			ptseg, ptfig, ptins, sym);
#endif

	xins = ptins->X;
	yins = ptins->Y - ptins->DY;

	ins_seg_coord(ptseg, ptfig, &x, &y, &dx, &dy,
						tablayer[get_layert(ptseg->LAYER)].EXT);
	/* connector must be symetrised */
	if (sym != NOSYM)
		make_sym (&x, &y, dx, dy, ptins->DX, ptins->DY, sym);

	/* updates coordinates with its instance */
	x += xins;
	y += yins;

	ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
	ptdesc->X = x;
	ptdesc->Y = y + dy;
	ptdesc->DX = dx;
	ptdesc->DY = dy;
	/* sym used for string drawing */
	ptdesc->TYPE = SEG;
	ptdesc->PTMBK = (char *)ptseg;
	/* * A connector must keep a link with his instance for inspect function */
	ptdesc->USER = (char *)ptins;
	/* Uptdates bounding-box coordinates */
	update_BB (ptdesc);

	insert_visu (ptdesc, get_layert (ptseg->LAYER));
	nbinscon++;

	return ptdesc;
}

/* fill_ins : adds an instance descriptor into the database */
X_RECT *fill_ins (ptins)
phins_list *ptins;
{
LAMBDA x, y, dx, dy;
phfig_list *ptfig;
X_RECT *ptdesc;
phcon_list *ptcon;
phseg_list *ptseg;

#ifdef TRACE
	fprintf (stderr, "fill_ins : ptins= %#x\n", ptins);
#endif

	/* The instance model is seeked into MBK database to get his connectors */
	ptfig = getphfig (ptins->FIGNAME, 'P');

	x = 2 * ptins->XINS / SCALE_X;
	y = 2 * ptins->YINS / SCALE_X;
	/* the AB coordinates stand for the instance, not for the cell, it
		should be substracted */
	dx = 2 * (ptfig->XAB2 - ptfig->XAB1)/ SCALE_X;
	dy = 2 * (ptfig->YAB2 - ptfig->YAB1)/ SCALE_X;

	ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
	ptdesc->X = x;
	ptdesc->Y = y + dy;
	ptdesc->DX = dx;
	ptdesc->DY = dy;
	ptdesc->TYPE = INS | ((unsigned char)ptins->TRANSF << 3);
	ptdesc->PTMBK = (char *)ptins;
	/* Uptdates bounding-box coordinates */
	update_BB (ptdesc);
	insert_visu (ptdesc, get_layert (G_INS));
	nbins++;
	/* Instance connectors are added to the database */
	ptcon = ptfig->PHCON;
	while (ptcon){
		fill_inscon (ptcon, ptfig, ptdesc, ptins->TRANSF);
		ptcon = ptcon->NEXT;
	}
	/* Instance allow segs are added to the database */
	ptseg = ptfig->PHSEG;
	while (ptseg){
		if (ptseg->LAYER == TALU2 || ptseg->LAYER == TALU1)
			fill_insseg (ptseg, ptfig, ptdesc, ptins->TRANSF);
		ptseg = ptseg->NEXT;
	}
	return ptdesc;
}

/* fill_figcon : adds a figure connector into the database */
X_RECT *fill_figcon (ptcon)
phcon_list *ptcon;
{
LAMBDA x, y, dx, dy;
X_RECT *ptdesc;

#ifdef TRACE
	fprintf (stderr, "fill_figcon : ptcon= %#x\n", ptcon);
#endif

	con_coord (ptcon, xvisufig, &x, &y, &dx, &dy);

	ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
	ptdesc->X = x;
	ptdesc->Y = y + dy;
	ptdesc->DX = dx;
	ptdesc->DY = dy;
	ptdesc->TYPE = FIGCON;
	ptdesc->PTMBK = (char *)ptcon;
	/* Uptdates bounding-box coordinates */
	update_BB (ptdesc);
	insert_visu (ptdesc, get_layert (ptcon->LAYER));
	nbfigcon++;
	return ptdesc;
}
/* fill_ref : adds a reference name into the string database */
X_RECT *fill_ref (ptref)
phref_list *ptref;
{
LAMBDA x, y, dx, dy;
X_RECT *ptdesc;

#ifdef TRACE
	fprintf (stderr, "fill_ref : ptref= %#x\n", ptref);
#endif
/* let's say the computation is equivalent */
	ref_coord (ptref, xvisufig, &x, &y, &dx, &dy);

	ptdesc = (X_RECT *)mbkalloc(sizeof(X_RECT));
	ptdesc->X = x;
	ptdesc->Y = y + dy;
	ptdesc->DX = dx;
	ptdesc->DY = dy;
	ptdesc->TYPE = REF;
	ptdesc->PTMBK = (char *)ptref;
	ptdesc->USER = NULL;
	insert_visu (ptdesc, get_layert(G_REF));
	return ptdesc;
}

/* fill_descr : adds a single descriptor into the database */
void fill_descr (ptdesc, type)
char *ptdesc;
unsigned char type;
{
#ifdef TRACE
	fprintf (stderr, "fill_descr : ptdesc= %#x type= %#x\n", ptdesc, type);
#endif
	/* In case of generation of a descriptor in MBK */
	switch (type){
		case SEG:
			fill_seg ((phseg_list *)ptdesc);
			break;
		case VIA:
			fill_via ((phvia_list *)ptdesc);
			break;
		case INS:
			ptinsref = fill_ins ((phins_list *)ptdesc);
			if (run_mode != RUN)
				V_drawInsRef();
			break;
		case REF:
			fill_ref ((phref_list *)ptdesc);
			break;
		case FIGCON:
			fill_figcon ((phcon_list *)ptdesc);
			break;
#ifdef DEBUG
		default:
			g_error ("fill_descr : unknown descriptor code", 1);
#endif
	}
}
/* fill_cache : adds all figure descriptors into the database */
void fill_cache ()
{
phseg_list *ptseg;
phvia_list *ptvia;
phins_list *ptins;
phcon_list *ptcon;
phref_list *ptref;
char old_run_mode = run_mode;

	run_mode = RUN;
	ptseg = xvisufig->PHSEG;
	while (ptseg){
		fill_seg (ptseg);
		ptseg = ptseg->NEXT;
	}

	ptvia = xvisufig->PHVIA;
	while (ptvia){
		fill_via (ptvia);
		ptvia = ptvia->NEXT;
	}

	ptins = xvisufig->PHINS;
	while (ptins){
		ptinsref = fill_ins (ptins);
		ptins = ptins->NEXT;
	}

	ptcon = xvisufig->PHCON;
	while (ptcon){
		fill_figcon (ptcon);
		ptcon = ptcon->NEXT;
	}

	ptref = xvisufig->PHREF;
	while (ptref){
		fill_ref (ptref);
		ptref = ptref->NEXT;
	}
	run_mode = old_run_mode;
}

/* update_AB : changes the mother cell abutment box coordinates */
void update_AB ()
{
void V_drawAB();

#ifdef TRACE
	fprintf (stderr, "update_AB\n");
#endif

/* In case of DEF_AB */
	xabfig = 2 * xvisufig->XAB1 / SCALE_X;
	yabfig = 2 * xvisufig->YAB1 / SCALE_X;
	xab2fig = 2 * xvisufig->XAB2 / SCALE_X;
	yab2fig = 2 * xvisufig->YAB2 / SCALE_X;

	if (run_mode != RUN)				
		V_drawAB ();				
}

/* init_fig : changes the mother cell */
void init_fig ()
{
void V_clear ();
int i;
int oldmode;

#ifdef TRACE
	fprintf (stderr, "init_fig\n");
#endif

	/* In case of DEF_PHFIG */
	ptinsref = NULL;

	if ((xvisufig = WORK_PHFIG) == NULL)
		return;
	oldmode	= run_mode;
	run_mode = RUN;
	update_AB();
	run_mode = oldmode;

	xvisu = yvisu = 0;
	dxvisu = dyvisu = 500;

	/* random initialisation because don't know bounding box */
	scale = 1;
	xscreen = yscreen = 0;
	dxscreen = dxWin;
	dyscreen = dyWin;

	/* Erase old database */
	del_cache ();
	for (i = 0; i <= DEFAULT_LAYER; i++)
		peek_db[i] = NULL;

	/* Screen must be cleared because WORK_PHFIG has changed */
	V_clear ();
	V_changeName(xvisufig->NAME);

	zoomTrack.x = xscreen;
	zoomTrack.y = yscreen;
	zoomTrack.dx = dxscreen;
	zoomTrack.dy = dyscreen;
	zoomTrack.scale = scale;
}

/* load_fig : loads the mother cell from disk */
void load_fig(name)
char *name;
{
int i;
char buffer[BUFSIZ];
phfig_list *pfig;
char mode = run_mode;

	/* avoid a ab box burst before the display of the drawing */
	run_mode = RUN;
	ptinsref = NULL;
	sprintf(buffer, "Loading '%s', please wait\n",name);
	T_print(buffer);
	XFlush(display);
	for (pfig = HEAD_PHFIG; pfig; pfig = pfig->NEXT){
/*
		if (pfig->NAME == NULL || pfig->NAME[0] == '\0')
			continue;
*/
		delphfig(pfig->NAME); /* erase all cells in memory */
	}
	xvisu = yvisu = LONG_MAX;
	dxvisu = dyvisu = 0;
	del_cache(); /* Erase old databases */
	for (i = 0; i <= DEFAULT_LAYER; i++)
		peek_db[i] = NULL;
	xvisufig = NULL; /* if getlofig terminates, xvisufig is ok */ 

	xvisufig = getphfig(name, 'A');
	update_AB();
	fill_cache(); /* database loading, and then plotting */
	sprintf(buffer, 
"Bounding box : x:%g y:%g dx:%g dy:%g\nAbutment box : x:%g y:%g dx:%g dy:%g\n",
				(float)xvisu / 2, (float)yvisu / 2, 
				(float)dxvisu / 2, (float)dyvisu / 2,
				(float)(xvisufig->XAB1 / 10), (float)(xvisufig->YAB1 / 10),
				(float)((xvisufig->XAB2 - xvisufig->XAB1)/ 10), 
				(float)((xvisufig->YAB2 - xvisufig->YAB1)/ 10));
	T_print(buffer);
	zoomTrack.x = xscreen;
	zoomTrack.y = yscreen;
	zoomTrack.dx = dxscreen;
	zoomTrack.dy = dyscreen;
	zoomTrack.scale = scale;
	run_mode = mode;
}

/* ram_load : loads the mother cell from disk */
void ram_load()
{
int i;
phfig_list *pfig;
char old_mode;

	ptinsref = NULL;
	XFlush (display);
	xvisufig = getphfig (WORK_PHFIG->NAME, 'A');
	/* avoid a ab box burst before the display of the drawing */
	old_mode = run_mode;
	run_mode = RUN;
	update_AB ();

	xvisu = yvisu = LONG_MAX;
	dxvisu = dyvisu = 0;
	del_cache (); /* Erase old databases */
	for (i = 0; i <= DEFAULT_LAYER; i++)
		peek_db[i] = NULL;
	fill_cache (); /* database loading, and then plotting */
	zoomTrack.x = xscreen;
	zoomTrack.y = yscreen;
	zoomTrack.dx = dxscreen;
	zoomTrack.dy = dyscreen;
	zoomTrack.scale = scale;
	update_AB ();
	run_mode = old_mode;
	if (run_mode != RUN)
		V_refresh();
}
