/****************************************************************************/
/*                                                                          */
/*                      Chaine de CAO & VLSI   Alliance                     */
/*                                                                          */
/*    Produit : Icon util library                                           */
/*    Fichier : Icon_util.c                                                 */
/*                                                                          */
/*    (c) copyright 1991 Laboratoire MASI equipe CAO & VLSI                 */
/*    Tous droits reserves                                                  */
/*    Support : e-mail cao-vlsi@masi.ibp.fr                                 */
/*                                                                          */
/*    Auteur(s) : Vincent POUILLEY                      le : 09/08/1993     */
/*                                                                          */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*    Modifie par :                                     le : ../../....     */
/*                                                                          */
/*    $Id: Icon_util.c,v 2.1.1.1 1993/09/23 16:04:30 sax Exp sax $              */
/*                                                                          */
/****************************************************************************/

#define _ICON_UTIL_C_

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include "IconConst.h"
#include MUT_H
#include ICN_H
#include IAC_H
#include ICU_H
#include "ConvMacro.h"

#ident "@(#)Icon util library v2.00 06/08/93 by Vincent POUILLEY"


#ifdef __STDC__
IconGate_list * loadicon(char * name)
#else
IconGate_list * loadicon(name)
char * name;
#endif
{
#ifdef __STDC__
	extern IconGate_list * loadicnicon(char * name);
	extern IconGate_list * loadaiicon(char * name);
#else
	extern IconGate_list * loadicnicon();
	extern IconGate_list * loadaiicon();
#endif

	
	if (ICON_IN[0] == 0)
	{
		char * str;
		
		str = getenv("ICON_IN");
		if (str != NULL)
		{
			if (!strcmp(str, "icn"))
				strcpy(ICON_IN, "icn");
			else
				if (!strcmp(str, "ai"))
					strcpy(ICON_IN, "ai");
				else
				{
					(void)fprintf(stderr, "*** Icon Error *** loadicon impossible : Icon input format '%s' not supported\n", str);
					return NULL;
				}
		}
		else
			strcpy(ICON_IN, "icn");
	}

	if (!strcmp(ICON_IN, "icn"))
		return loadicnicon(name);
	else
		if (!strcmp(ICON_IN, "ai"))
			return loadaiicon(name);
		else
		{
			(void)fprintf(stderr, "*** Icon Error *** loadicon impossible : ICON_IN : '%s' unknown format\n", ICON_IN);
			return NULL;
		}
} /* loadicon */

#ifdef __STDC__
int saveicon(IconGate_list * icon_gate)
#else
int saveicon(icon_gate)
IconGate_list * icon_gate;
#endif
{
#ifdef __STDC__
	extern int saveicnicon(IconGate_list * icon_gate);
	extern int saveaiicon(IconGate_list * icon_gate);
#else
	extern int saveicnicon();
	extern int saveaiicon();
#endif

	if (ICON_OUT[0] == 0)
	{
		char * str;
		
		str = getenv("ICON_OUT");
		if (str != NULL)
		{
			if (!strcmp(str, "icn"))
				strcpy(ICON_OUT, "icn");
			else
				if (!strcmp(str, "ai"))
					strcpy(ICON_OUT, "ai");
				else
				{
					(void)fprintf(stderr, "*** Icon Error *** saveicon impossible : Icon output format '%s' not supported\n", str);
					return -1;
				}
		}
		else
			strcpy(ICON_OUT, "icn");
	}


	if (!strcmp(ICON_OUT, "icn"))
		return saveicnicon(icon_gate);
	else
		if (!strcmp(ICON_OUT, "ai"))
			return saveaiicon(icon_gate);
		else
		{
			(void)fprintf(stderr, "*** Icon Error *** saveicon impossible : ICON_OUT : '%s' unknown format\n", ICON_OUT);
			return -1;
		}
} /* saveicon */

#ifdef __STDC__
void update_icon (IconGate_list * icon_gate)
#else
void update_icon (icon_gate)
IconGate_list * icon_gate;
#endif
{
	int dl, du, dd, dr;
	IconLine_list *line;
	IconShape_list *shape;
	IconComp_list *comp;
	IconCircle_list *circle;
	IconArc_list *arc;
	IconCon_list *con;
	
	/* calcul the min and the max coordinates */
	dl = dr = ICONGATE_X_MODELNAME(icon_gate);
	du = dd = ICONGATE_Y_MODELNAME(icon_gate);
	dl = min (ICONGATE_X_INSNAME(icon_gate), dl);
	dr = max (ICONGATE_X_INSNAME(icon_gate), dr);
	du = min (ICONGATE_Y_INSNAME(icon_gate), du);
	dd = max (ICONGATE_Y_INSNAME(icon_gate), dd);
	dl = min (ICONGATE_X_LABEL(icon_gate), dl);
	dr = max (ICONGATE_X_LABEL(icon_gate), dr);
	du = min (ICONGATE_Y_LABEL(icon_gate), du);
	dd = max (ICONGATE_Y_LABEL(icon_gate), dd);
	for (line = ICONGATE_LINES(icon_gate); line; line = ICONLINE_NEXT(line))
	{
		dl = min (ICONLINE_X0(line), dl);
		dr = max (ICONLINE_X0(line), dr);
		du = min (ICONLINE_Y0(line), du);
		dd = max (ICONLINE_Y0(line), dd);
		dl = min (ICONLINE_X1(line), dl);
		dr = max (ICONLINE_X1(line), dr);
		du = min (ICONLINE_Y1(line), du);
		dd = max (ICONLINE_Y1(line), dd);
	}
	for (shape = ICONGATE_SHAPES(icon_gate); shape; shape = ICONSHAPE_NEXT(shape))
		for (comp = ICONSHAPE_FIRSTCOMP(shape); comp; comp = ICONSHAPE_NEXTCOMP(comp))
		{
			dl = min (ICONSHAPE_X_COMP(comp), dl);
			dr = max (ICONSHAPE_X_COMP(comp), dr);
			du = min (ICONSHAPE_Y_COMP(comp), du);
			dd = max (ICONSHAPE_Y_COMP(comp), dd);
		}
	for (circle = ICONGATE_CIRCLES(icon_gate); circle; circle = ICONCIRCLE_NEXT(circle))
	{
		dl = min (ICONCIRCLE_X0(circle), dl);
		dr = max (ICONCIRCLE_X0(circle), dr);
		du = min (ICONCIRCLE_Y0(circle), du);
		dd = max (ICONCIRCLE_Y0(circle), dd);
		dl = min (ICONCIRCLE_X1(circle), dl);
		dr = max (ICONCIRCLE_X1(circle), dr);
		du = min (ICONCIRCLE_Y1(circle), du);
		dd = max (ICONCIRCLE_Y1(circle), dd);
	}
	for (arc = ICONGATE_ARCS(icon_gate); arc; arc = ICONARC_NEXT(arc))
	{
		dl = min (ICONARC_X0(arc), dl);
		dr = max (ICONARC_X0(arc), dr);
		du = min (ICONARC_Y0(arc), du);
		dd = max (ICONARC_Y0(arc), dd);
		dl = min (ICONARC_X1(arc), dl);
		dr = max (ICONARC_X1(arc), dr);
		du = min (ICONARC_Y1(arc), du);
		dd = max (ICONARC_Y1(arc), dd);
	}
	for (con = ICONGATE_CONNECTORS(icon_gate); con; con = ICONCON_NEXT(con))
	{
		dl = min (ICONCON_X(con), dl);
		dr = max (ICONCON_X(con), dr);
		du = min (ICONCON_Y(con), du);
		dd = max (ICONCON_Y(con), dd);
		dl = min (ICONCON_X_NAME(con), dl);
		dr = max (ICONCON_X_NAME(con), dr);
		du = min (ICONCON_Y_NAME(con), du);
		dd = max (ICONCON_Y_NAME(con), dd);
	}
	
	/* recenter icon to have the up left corner of the bounding box in 0,0 */
/* 	if ((dl != 0) || (du != 0)) */
/* 	{ */
/* 		ICONGATE_X_MODELNAME(icon_gate) -= dl; */
/* 		ICONGATE_Y_MODELNAME(icon_gate) -= du; */
/* 		ICONGATE_X_INSNAME(icon_gate) -= dl; */
/* 		ICONGATE_Y_INSNAME(icon_gate) -= du; */
/* 		ICONGATE_X_LABEL(icon_gate) -= dl; */
/* 		ICONGATE_Y_LABEL(icon_gate) -= du; */
/* 		for (line = ICONGATE_LINES(icon_gate); line; line = ICONLINE_NEXT(line)) */
/* 		{ */
/* 			ICONLINE_X0(line) -= dl; */
/* 			ICONLINE_Y0(line) -= du; */
/* 			ICONLINE_X1(line) -= dl; */
/* 			ICONLINE_Y1(line) -= du; */
/* 		} */
/* 		for (shape = ICONGATE_SHAPES(icon_gate); shape; shape = ICONSHAPE_NEXT(shape)) */
/* 			for (comp = ICONSHAPE_FIRSTCOMP(shape); comp; comp = ICONSHAPE_NEXTCOMP(comp)) */
/* 			{ */
/* 				ICONSHAPE_X_COMP(comp) -= dl; */
/* 				ICONSHAPE_Y_COMP(comp) -= du; */
/* 			} */
/* 		for (circle = ICONGATE_CIRCLES(icon_gate); circle; circle = ICONCIRCLE_NEXT(circle)) */
/* 		{ */
/* 			ICONCIRCLE_X0(circle) -= dl; */
/* 			ICONCIRCLE_Y0(circle) -= du; */
/* 		} */
/* 		for (arc = ICONGATE_ARCS(icon_gate); arc; arc = ICONARC_NEXT(arc)) */
/* 		{ */
/* 			ICONARC_X0(arc) -= dl; */
/* 			ICONARC_Y0(arc) -= du; */
/* 		} */
/* 		for (con = ICONGATE_CONNECTORS(icon_gate); con; con = ICONCON_NEXT(con)) */
/* 		{ */
/* 			ICONCON_X(con) -= dl; */
/* 			ICONCON_Y(con) -= du; */
/* 			ICONCON_X_NAME(con) -= dl; */
/* 			ICONCON_Y_NAME(con) -= du; */
/* 		} */
/* 	} */
	
	/* restore x, y, width and height */
	ICONGATE_X(icon_gate) = dl;
	ICONGATE_Y(icon_gate) = du;
	ICONGATE_WIDTH(icon_gate) = dr - dl + SCALE_X;
	ICONGATE_HEIGHT(icon_gate) = dd - du + SCALE_X;
} /* update_icon */

#ifdef __STDC__
void rescale_icon (IconGate_list * icon_gate, int con_ecart, int min_width, int min_height)
#else
void rescale_icon (icon_gate, con_ecart, min_width, min_height)
IconGate_list * icon_gate;
int con_ecart;
int min_width;
int min_height;
#endif
{
	int dmin;
	int dl, du, dd, dr, tmp; /* distance left, distance up, distance down, distance right */
	double scale;
	
	/* calcul the min distance between two connectors */
	{
		IconCon_list		*con, *con2;
		
		du = dd = ICONGATE_WIDTH (icon_gate);
		dl = dr = ICONGATE_HEIGHT (icon_gate);
		
		for (con = ICONGATE_CONNECTORS (icon_gate); con; con = ICONCON_NEXT (con))
		{
			switch (ICONCON_SIDE (con))
			{
				case SAX_WEST :
					for (con2 = ICONCON_NEXT (con); con2; con2 = ICONCON_NEXT (con2))
					{
						if (ICONCON_SIDE (con2) == SAX_WEST)
						{
							tmp = (ICONCON_Y (con) < ICONCON_Y (con2)) ?
								ICONCON_Y (con2) - ICONCON_Y (con) :
								ICONCON_Y (con) - ICONCON_Y (con2);
						
							dl = min (dl, tmp);
						}
					}
					break;
				case SAX_EAST :
					for (con2 = ICONCON_NEXT (con); con2; con2 = ICONCON_NEXT (con2))
					{
						if (ICONCON_SIDE (con2) == SAX_EAST)
						{
							tmp = (ICONCON_Y (con) < ICONCON_Y (con2)) ?
								ICONCON_Y (con2) - ICONCON_Y (con) :
								ICONCON_Y (con) - ICONCON_Y (con2);
						
							dr = min (dr, tmp);
						}
					}
					break;
				case SAX_NORTH :
					for (con2 = ICONCON_NEXT (con); con2; con2 = ICONCON_NEXT (con2))
					{
						if (ICONCON_SIDE (con2) == SAX_NORTH)
						{
							tmp = (ICONCON_X (con) < ICONCON_X (con2)) ?
								ICONCON_X (con2) - ICONCON_X (con) :
								ICONCON_X (con) - ICONCON_X (con2);
						
							du = min (du, tmp);
						}
					}
					break;
				case SAX_SOUTH :
					for (con2 = ICONCON_NEXT (con); con2; con2 = ICONCON_NEXT (con2))
					{
						if (ICONCON_SIDE (con2) == SAX_SOUTH)
						{
							tmp = (ICONCON_X (con) < ICONCON_X (con2)) ?
								ICONCON_X (con2) - ICONCON_X (con) :
								ICONCON_X (con) - ICONCON_X (con2);
						
							dd = min (dd, tmp);
						}
					}
					break;
			}
		}
	}
	du = min (du, dd);
	dl = min (dl, dr);
	dmin = min (du, dl);

	/* calcul scale */
	scale = (double)((double)con_ecart / (double)dmin);

	/* See if icon is too small */
	du = min_width - SCALE_TO_INT(scale, ICONGATE_WIDTH (icon_gate));
	dl = min_height - SCALE_TO_INT(scale, ICONGATE_HEIGHT (icon_gate));

	if ((du > 0) || (dl > 0))
	{
		if (du > dl)
			scale = (double)((double)min_width / (double)(ICONGATE_WIDTH (icon_gate)));
		else
			scale = (double)((double)min_height / (double)(ICONGATE_HEIGHT (icon_gate)));
	}

	ICONGATE_SCALE(icon_gate) = scale;
	
	/* if scale = 1, do nothing */
	if (scale == 1.)
		return;
		
	/* Rescale gate coordinates */
	ICONGATE_X_MODELNAME (icon_gate) = SCALE_TO_INT(scale, ICONGATE_X_MODELNAME (icon_gate));
	ICONGATE_Y_MODELNAME (icon_gate) = SCALE_TO_INT(scale, ICONGATE_Y_MODELNAME (icon_gate));

	ICONGATE_X_INSNAME (icon_gate) = SCALE_TO_INT(scale, ICONGATE_X_INSNAME (icon_gate));
	ICONGATE_Y_INSNAME (icon_gate) = SCALE_TO_INT(scale, ICONGATE_Y_INSNAME (icon_gate));

	ICONGATE_X_LABEL (icon_gate) = SCALE_TO_INT(scale, ICONGATE_X_LABEL (icon_gate));
	ICONGATE_Y_LABEL (icon_gate) = SCALE_TO_INT(scale, ICONGATE_Y_LABEL (icon_gate));

	ICONGATE_X (icon_gate) = SCALE_TO_INT(scale, ICONGATE_X (icon_gate));
	ICONGATE_Y (icon_gate) = SCALE_TO_INT(scale, ICONGATE_Y (icon_gate));
	ICONGATE_WIDTH (icon_gate) = SCALE_TO_INT(scale, ICONGATE_WIDTH (icon_gate));
	ICONGATE_HEIGHT (icon_gate) = SCALE_TO_INT(scale, ICONGATE_HEIGHT (icon_gate));

	/* Rescale Lines coordinates */
	{
		IconLine_list*	line;
		
		for (line = ICONGATE_LINES (icon_gate); line; line = ICONLINE_NEXT (line))
		{
			ICONLINE_X0 (line) = SCALE_TO_INT(scale, ICONLINE_X0 (line));
			ICONLINE_Y0 (line) = SCALE_TO_INT(scale, ICONLINE_Y0 (line));
			ICONLINE_X1 (line) = SCALE_TO_INT(scale, ICONLINE_X1 (line));
			ICONLINE_Y1 (line) = SCALE_TO_INT(scale, ICONLINE_Y1 (line));
		}
	}

	/* Rescale Shapes coordinates */
	{
		IconShape_list*	shape;
		IconComp_list*	comp;
		
		for (shape = ICONGATE_SHAPES (icon_gate); shape; shape = ICONSHAPE_NEXT (shape))
		{
			for (comp = ICONSHAPE_FIRSTCOMP (shape); comp; comp = ICONSHAPE_NEXTCOMP (comp))
			{
				ICONSHAPE_X_COMP (comp) = SCALE_TO_INT(scale, ICONSHAPE_X_COMP (comp));
				ICONSHAPE_Y_COMP (comp) = SCALE_TO_INT(scale, ICONSHAPE_Y_COMP (comp));
			}
		}
	}
		
	/* Rescale Circles coordinates */
	{
		IconCircle_list*	circle;
		
		for (circle = ICONGATE_CIRCLES (icon_gate); circle; circle = ICONCIRCLE_NEXT (circle))
		{
			ICONCIRCLE_X0 (circle) = SCALE_TO_INT(scale, ICONCIRCLE_X0 (circle));
			ICONCIRCLE_Y0 (circle) = SCALE_TO_INT(scale, ICONCIRCLE_Y0 (circle));
			ICONCIRCLE_WIDTH (circle) = SCALE_TO_INT(scale, ICONCIRCLE_WIDTH (circle));
			ICONCIRCLE_HEIGHT (circle) = SCALE_TO_INT(scale, ICONCIRCLE_HEIGHT (circle));
		}
	}
	
	/* Rescale Arcs coordinates */
	{
		IconArc_list*	arc;
		
		/* WARNING : scale of 1000 for X0 and Y0 */
		for (arc = ICONGATE_ARCS (icon_gate); arc; arc = ICONARC_NEXT (arc))
		{
			ICONARC_X0 (arc) = SCALE_TO_INT(scale, ICONARC_X0 (arc));
			ICONARC_Y0 (arc) = SCALE_TO_INT(scale, ICONARC_Y0 (arc));
			ICONARC_WIDTH (arc) = SCALE_TO_INT(scale, ICONARC_WIDTH (arc));
			ICONARC_HEIGHT (arc) = SCALE_TO_INT(scale, ICONARC_HEIGHT (arc));
		}
	}
	
	/* Rescale connectors coordinates */
	{
		IconCon_list*	con;
		
		for (con = ICONGATE_CONNECTORS (icon_gate); con; con = ICONCON_NEXT (con))
		{
			ICONCON_X (con) = SCALE_TO_INT(scale, ICONCON_X (con));
			ICONCON_Y (con) = SCALE_TO_INT(scale, ICONCON_Y (con));
			ICONCON_X_NAME (con) = SCALE_TO_INT(scale, ICONCON_X_NAME (con));
			ICONCON_Y_NAME (con) = SCALE_TO_INT(scale, ICONCON_Y_NAME (con));
		}
	}
} /* rescale_icon */

#ifdef __STDC__
int restoredirvbe_icon(IconGate_list * icon_gate)
#else
int restoredirvbe_icon(icon_gate)
IconGate_list * icon_gate;
#endif
{
	FILE *f = NULL;
	char line[BUFSIZ];
	int p, q, r, from, to, inc, nbcon;
	int run = 0; /* shall we interpret what we read? */
	char string[128], hook[128];
	IconCon_list * fc, *fct;
	char dir;
	
	if (!icon_gate)
	{
		fprintf(stderr, "*** Icon Error *** restoredirvbe_icon : Invalid Icon\n");
		return PROBLEM;
	}
	if ((f = mbkfopen(ICONGATE_MODELNAME (icon_gate), "vbe", "r")) == NULL)
		if ((f = mbkfopen(ICONGATE_MODELNAME (icon_gate), "vst", "r")) == NULL)
			return -2;
	nbcon = 0;
	while (1)
	{
		if (fgets(line, BUFSIZ, f) == NULL)
			break;
		for (p = 0; p < BUFSIZ && line[p] && line[p] != '\n'; p++)
			if (isupper(line[p]))
				line[p] = tolower(line[p]);
		p = 0;
		while (isspace(line[p]))
			p++;
		switch (line[p])
		{
			case 'e': /* either entity or end for us */
				if (!strncmp("entity", &line[p], 6)) /* we shall treat now */
					run = 1;
				if (!strncmp("end", &line[p], 3)) /* we shall exit gracefully */
				{
					fclose(f);
					for (p = 0, fct = ICONGATE_CONNECTORS (icon_gate); fct; fct = fct->NEXT)
						p++;
					if (p != nbcon)
					{
						fprintf(stderr, "*** Icon Error *** restoredirvbe_icon : figure %s have more connectors than vbe\n", ICONGATE_MODELNAME (icon_gate));
						return PROBLEM;
					}
					return OK;
				}
				continue; /* next line guys */
			case 'p': /* port or nothing! */
				if (!run)
					continue;
				if (!strncmp("port", &line[p], 4))
				{
					p += 4;
					while (isspace(line[p]))
					{
						if (line[p] == '\n')
						{
							fgets(line, BUFSIZ, f);
							p = 0;
						}
						else
							p++;
					}
					if (line[p] != '(')
					{
						fprintf(stderr, "*** Icon Error *** restoredirvbe_icon : cannot read port well!\n");
						fclose(f);
						return PROBLEM;
					}
					
					while (1)
					{
						fgets(line, BUFSIZ, f);
						for (p = 0; p < BUFSIZ || line[p]; p++)
							if (isupper(line[p]))
								line[p] = tolower(line[p]);
						p = 0;
						while (isspace(line[p]))
							p++;
						if (line[p] == ')')
							break;
						q = p;
						while (!isspace(line[p]) && line[p] != ':')
							p++;
						strncpy(hook, &line[q], p - q);
						hook[p - q] = '\0';
						
						if (isvdd (hook) || isvss (hook))
							continue;
						
						while (isspace(line[p]) || line[p] == ':')
							p++;
						q = p;
						while (!isspace(line[p]))
							p++;
						strncpy(string, &line[q], p - q);
						string[p - q] = '\0';
						while (isspace(line[p]))
							p++;
						if (line[p] == 'b' || line[p] == 'r') /* finished, dir ok */
						{
							if (!strcmp("in", string))
								dir = IN;
							else
								if (!strcmp("out", string))
									dir = OUT;
								else
									dir = UNKNOWN;
						}
						else
						{
							if (!strcmp("inout", string))
								dir = TRANSCV;
							else
								if (!strcmp("out", string))
									dir = TRISTATE;
								else
									dir = UNKNOWN;
						}
						while (line[p] != '(' && line[p] != '\0')
							p++;
						if (line[p] == '\0')
						{
							fc = geticoncon(icon_gate, hook);
							ICONCON_DIRECTION (fc) = dir;
							nbcon++;
						}
						else
						{ /* bit vector indeed */
							p++; /* skip ( */
							from = atoi(&line[p]);
							while (isdigit(line[p]))
								p++;
							while (isspace(line[p]))
								p++;
							if (line[p] == 'd')
								inc = -1;
							else
								if (line[p] == 't')
									inc = 1;
								else
								{
									fprintf(stderr, "*** Icon Error *** restoredirvbe_icon : bit_vect neither to nor downto\n");
									fclose(f);
									return PROBLEM;
								}
							while (!isspace(line[p]))
								p++;
							to = atoi(&line[p]);
							
							for (r = from; r <= to; r += inc)
							{
								sprintf(string, "%s %d", hook, r);
								fc = geticoncon(icon_gate, string);
								ICONCON_DIRECTION (fc) = dir;
								nbcon++;
							}
						}
						continue;
					}
				}
				continue;
			default :
				continue;
		}
	}
	fclose(f);
	for (p = 0, fct = ICONGATE_CONNECTORS (icon_gate); fct; fct = fct->NEXT)
		p++;
	if (p != nbcon)
	{
		fprintf(stderr, "*** Icon Error *** restoredirvbe_icon : figure %s have more connectors than vbe\n", ICONGATE_MODELNAME (icon_gate));
		return PROBLEM;
	}
	return OK;
} /* restoredirvbe_icon */
