#ifndef lint
static char *SccsId = "@(#)plot_eps.c 4.2 (TU-Delft) 11/24/92";
#endif
#include <stdio.h>
#include <errno.h>
#include "dmincl.h"
#include "config.h"
#include "plot.h"
#include "aux/aux.h"

# define StartPolygon(x,y) fprintf (fpPlot, "%d %d P\n", x, y)
# define LineTo(x,y)       fprintf (fpPlot, "%d %d T\n", x, y)
# define LastPoint(x,y)    fprintf (fpPlot, "%d %d L\n", x, y)
# define PlotRect(xl, yb, dx, dy)   fprintf (fpPlot, "%d %d %d %d B\n", xl, yb, dx, dy)

# define BeginRect(x0, y0, dx, dy)  fprintf (fpPlot, "%d %d %d %d R\n", x0, y0, dx, dy)
# define ContRect(dx, dy)  fprintf (fpPlot, "%d %d X\n", dx, dy)
# define EndRect(dx, dy)   fprintf (fpPlot, "%d %d C\n", dx, dy)

#define Scale(x) (scale * (x))
static int scale = 1;
static int bxl, bxr, byb, byt;

static int busy_layer = 0;

/* local operations */
private FILE * openTechFile ();
private void techFileInclude ();

static FILE * fpPlot;
static FILE * fpTech;

/* A4 dimensions, in points (= 1/72 inch) */
static double BbLeft   = 28,
              BbBot    = 28,
              BbRight  = 566,
              BbTop    = 807;

static bool_t doRotate = FALSE;

plotSetRotation ()
{
    doRotate = TRUE;
}

static double lambdaScale = 0.0;

/* explicitely set scaling, in lambda/cm */
plotSetLambda (s)
char * s;
{
    extern double atof ();
    lambdaScale = 2.54 * 72.0 / atof (s);
}

/* set width of drawing region, in cm */
plotSetDrawWidth (s)
char * s;
{
    extern double atof ();
    double w = atof (s) / 2.54 * 72.0;
    double v = BbRight - BbLeft;
    BbRight -= (v - w)/2;
    BbLeft  += (v - w)/2;
}

/* set heigth of drawing region, in cm */
plotSetDrawHeight (s)
char * s;
{
    extern double atof ();
    double h = atof (s) / 2.54 * 72.0;
    double v = BbTop - BbBot;
    BbTop -= (v - h)/2;
    BbBot += (v - h)/2;
}

plotInit (key)
DM_CELL * key;
{
    DM_STREAM * info;
    extern double ceil ();

    double PicHeight, PicWidth;
    double BbWidth, BbHeight;
    double ScaleFactor;

    fpPlot = cfopen (mprintf ("%s.eps", key -> cell), "w");

    info = dmOpenStream (key, "info3", "r");
    dmGetDesignData (info, GEO_INFO3);
    dmCloseStream (info, COMPLETE);

    if (ginfo3.nr_samples != 0)
	scale = ginfo3.nr_samples;
    else
	scale = SCALE;

    PicHeight = Scale (ginfo3.byt) - Scale (ginfo3.byb);
    PicWidth  = Scale (ginfo3.bxr) - Scale (ginfo3.bxl);

    if (doRotate) {
	double t = PicHeight; PicHeight = PicWidth; PicWidth = t;
    }

    BbLeft   = ceil (BbLeft + 0.5);
    BbBot    = ceil (BbBot + 0.5);
    BbRight  = ceil (BbRight + 0.5);
    BbTop    = ceil (BbTop + 0.5);
    BbWidth  = BbRight - BbLeft;
    BbHeight = BbTop - BbBot;

    if (lambdaScale == 0) {
	double WidthScale, HeightScale;
	WidthScale  = BbWidth  / PicWidth;
	HeightScale = BbHeight / PicHeight;
	ScaleFactor = WidthScale < HeightScale ? WidthScale : HeightScale;
    }
    else {
	ScaleFactor = lambdaScale / scale;
    }

    /* now move to center of paper */
    BbLeft  += (BbWidth  - PicWidth * ScaleFactor) / 2.0;
    BbWidth  = PicWidth * ScaleFactor;
    BbRight  = BbLeft + BbWidth;
    BbBot   += (BbHeight - PicHeight * ScaleFactor) / 2.0;
    BbHeight = PicHeight * ScaleFactor;
    BbTop    = BbBot + BbHeight;

    /* make prolog */

    doEpsProlog ((long) BbLeft, (long) BbBot,
	(long) (BbRight), (long) (BbTop));

    if (doRotate) {
	fprintf (fpPlot, "/Rotate true def\n");
    }

    fprintf (fpPlot, "[%ld %ld %ld %ld %ld %ld %ld %ld %ld] BeginLayout\n",
	    (long) BbLeft, (long) BbBot,
	    (long) (BbRight), (long) (BbTop),
	    Scale (ginfo3.bxl), Scale (ginfo3.byb),
	    Scale (ginfo3.bxr), Scale (ginfo3.byt),
	    Scale (1) /* Resolution */
	);

    bxl = Scale (ginfo3.bxl);
    bxr = Scale (ginfo3.bxr);
    byb = Scale (ginfo3.byb);
    byt = Scale (ginfo3.byt);
}

plotEnd ()
{
    endLayer ();
    fprintf (fpPlot, "EndLayout\n");

    doEpsEpilog ();

    fclose (fpPlot), fpPlot = NULL;
}

plotBbox ()
{
    fprintf (fpPlot, "PlotBBox\n");
}

plotPass (pass)
int pass;
{
    endLayer ();
    fprintf (fpPlot, "%d plotPass\n", pass);
}

endLayer ()
{
    if (busy_layer)  fprintf (fpPlot, "EndLayer\n");
    busy_layer = 0;
}

setLayer (layer)
char * layer;
{
    fprintf (fpPlot, "(%s) SetLayer\n", layer);
    busy_layer = 1;
}


plotMask (name, color)
char * name;
int color;
{
    endLayer ();
    setLayer (name);
}

/* Postscript: xl xr yb yt dx dy termname plotTerminal */

plotTerminal (xl, xr, yb, yt, name)
long xl, xr, yb, yt;
char * name;
{
    xl = Scale (xl);
    xr = Scale (xr);
    yb = Scale (yb);
    yt = Scale (yt);

    fprintf (fpPlot, "%d %d %d %d %d %d (%s) plotTerminal\n",
       xl, xr, yb, yt, 0, 0, name);
}

plotContour (edge)
edge_t * edge;
{
    edge_t * e;

    for (e = edge; e != NULL; e = e -> link) {
	if (e -> yl != e -> yr) {
	    plotPolygon (edge);
	    return;
	}
    }
    plotRect (edge);
}

plotLine (x1, y1, x2, y2, mode)
long int x1, y1, x2, y2;
int mode;
{
    fprintf (fpPlot, "%ld %ld %ld %ld %d DrawArrow\n",
	    Scale (x1), Scale (y1), Scale (x2), Scale (y2), mode);
}

plotText (x, y, orient, text)
long int x, y;
int orient;
char * text;
{
    fprintf (fpPlot, "%ld %ld %d (%s) Text\n",
	    Scale (x), Scale (y), orient, text);
}

    

static plotRect (edge)
edge_t *edge;
{
    edge_t * e;
    int x0 = edge -> xr, y0 = edge -> yr;
    int x = edge -> xl, y = edge -> link -> yl;

    if (edge -> link -> link == NULL) { /* a rectangle */
	PlotRect (x, y, x0-x, y0-y);
	return;
    }

    BeginRect (x0, y0, x - x0, y - y0);

    e = edge -> link, DISPOSE (edge), edge = e;
    while (e = edge -> link) {
	int ox = x, oy = y;
	x = (edge -> xl == x) ? edge -> xr : edge -> xl;
	y = e -> yl;
	if (edge -> link -> link)
	    ContRect (x - ox, y - oy);
	else
	    EndRect (x - ox, y - oy);
	DISPOSE (edge), edge = e;
    }

    DISPOSE (edge);
}

static plotPolygon (edge)
edge_t * edge;
{
    edge_t * e;
    int x0 = edge -> xr, y0 = edge -> yr;
    int x  = edge -> xl, y  = edge -> yl;

    StartPolygon (x0, y0);
    LineTo (x, y);

    e = edge -> link, DISPOSE (edge), edge = e;
    while (edge) {
        if (edge -> xl == x) {
	    if (edge -> yl != y) {	/* vert */
		x = edge -> xl, y = edge -> yl;
		LineTo (x, y);
	    }
	    x = edge -> xr, y = edge -> yr;
	    if (edge -> link)	/* do not close contour */
		LineTo (x, y);
	    else
		LastPoint (x, y);
	}
	else {
	    ASSERT (edge -> xr == x);
	    if (edge -> yr != y) {	/* vert */
		x = edge -> xr, y = edge -> yr;
		LineTo (x, y);
	    }
	    x = edge -> xl, y = edge -> yl;
	    if (edge -> link)	/* do not close contour */
		LineTo (x, y);
	    else
		LastPoint (x, y);
	}
	e = edge -> link, DISPOSE (edge), edge = e;
    }
}

printLinks (edge)	/* print contour (use when in debugger) */
edge_t * edge;
{
    while (edge) {
        printf ("%d %d %d %d\n",
	    edge -> xl, edge -> xr, edge -> yl, edge -> yr);
	edge = edge -> link;
    }
}


doEpsProlog (l, b, r, t)
long l, b, r, t;
{
    char buf[200];

    fputs ("%!PS-Adobe-1.0\n", fpPlot);
    fprintf (fpPlot, "%%%%BoundingBox: %ld %ld %ld %ld\n", l, b, r, t);
    fputs ("%%Pages: 1\n", fpPlot);
    fputs ("%%EndComments\n", fpPlot);

    rewind (fpTech);

    while (fgets (buf, sizeof (buf), fpTech) == buf) {

	if (strncmp (buf, "%%Include", 9) == 0) {
	    techFileInclude (buf, fpPlot);
	}
	else {
	    fputs (buf, fpPlot);
	}

    }
}

/*
 * Handle file inclusion directive
 * syntax: %%Include <filename>
 *     or: %%Include "filename"
 * First form only seeks in icdpath/lib, second first locally.
 * Analogous to cpp convention.
 */
private void techFileInclude (buf, fp)
char * buf;
FILE * fp;
{
    char includename [1024];
    char filename [1024];
    FILE * fpInclude;
    int c;

    extern int errno;
    extern char * sys_errlist [];

    if (sscanf (buf, "%*s \"%[^\"]\"", filename) == 1) {
	if ((fpInclude = fopen (filename, "r")) == NULL) {
	    if (errno == ENOENT && filename [0] != '/') {
		strcpy (includename, filename);
		goto LibInclude;
	    }
	    else {
		say ("inclusion of eps prolog file \"%s\" failed (%s)",
		    filename, sys_errlist[errno]);
		return;
	    }
	}
    }

    else if (sscanf (buf, "%*s <%[^>]>", includename) == 1) {
LibInclude:
	sprintf (filename, "%s/lib/%s", icdpath, includename);
	if ((fpInclude = fopen (filename, "r")) == NULL) {
	    say ("inclusion of eps prolog file \"%s\" failed (%s)",
		filename, sys_errlist[errno]);
	    return;
	}
    }

    else {
	/* chop terminating \n, if present */
	if (buf [strlen (buf) - 1] == '\n')
	    buf [strlen (buf) - 1] =  '\0';

	say ("Syntax error in eps prolog include directive: '%s'", buf);
	return;
    }

    ASSERT (fpInclude);
    
    fprintf (fp, "%% begin inclusion of %s\n", filename);

    while ((c = fgetc (fpInclude)) != EOF)
	putc (c, fp);

    fprintf (fp, "%% end inclusion of %s\n", filename);

    fclose (fpInclude);

    return;
}

doEpsEpilog ()
{
}

doEpsTechnology (project, techDef, techFile, order_return, restroke_return)
DM_PROJECT * project;
char * techDef;
char * techFile;
int * order_return;
int * restroke_return;
{
    int i, j;
    char *name;
    char buf[100];
    char * p;
    DM_PROCDATA * process;

    process = (DM_PROCDATA *) dmGetMetaDesignData (PROCESS, project);

    fpTech = openTechFile (project, techDef, techFile);

    for (i = 0; i < process -> nomasks; i++) {
	order_return[i] = -1;
	restroke_return[i] = -1;
    }

    while (fgets (buf, sizeof (buf), fpTech) == buf) {
        if (strncmp (buf, "%%Order:", 8) == 0) {
	    p = buf + 8;
	    j = 0;
	    while (name = strtok (p, " \t\n")) {
		p = NULL;
		for (i = 0; i < process -> nomasks; i++) {
		    if (strsame (name, process -> mask_name[i])) {
			restroke_return[j] = i;
			order_return[j++] = i;
			break;
		    }
		}
		if (i == process -> nomasks) {
		    say ("Illegal mask name '%s' in %s directive",
			name, "%%Order");
		}
	     }
	 }
        if (strncmp (buf, "%%Filled:", 9) == 0) {
	    p = buf + 9;
	    j = 0;
	    while (name = strtok (p, " \t\n")) {
		p = NULL;
		for (i = 0; i < process -> nomasks; i++) {
		    if (strsame (name, process -> mask_name[i])) {
			order_return[j++] = i;
			break;
		    }
		}
		if (i == process -> nomasks) {
		    say ("Illegal mask name '%s' in %s directive",
			name, "%%Filled");
		}
	     }
	 }
	 else if (strncmp (buf, "%%Restroked:", 12) == 0) {
	     p = buf + 12;
	     j = 0;
	     while (name = strtok (p, " \t\n")) {
		 p = NULL;
		 for (i = 0; i < process -> nomasks; i++) {
		     if (strsame (name, process -> mask_name[i])) {
			 restroke_return[j++] = i;
			 break;
		     }
		}
		if (i == process -> nomasks) {
		    say ("Illegal mask name '%s' in %s directive",
			name, "%%Stroked");
		}
	     }
	 }
    }
}

#define TBASENM "epslay"
#define TSUFFIX "def"

private FILE * openTechFile (dmproject, techDef, techFile)
DM_PROJECT * dmproject;
char * techDef;
char * techFile;
{
    FILE * cfopen ();

    if (techDef == NULL)
	techDef = TSUFFIX;

    if (techFile == NULL) {
	techFile = dmGetMetaDesignData (PROCPATH, dmproject,
		    mprintf ("%s.%s", TBASENM, techDef));

	if (access (techFile, 0) != 0) {
	    say ("%s.%s: no such element definition in %s",
		TBASENM, techDef,
		dmGetMetaDesignData (PROCPATH, dmproject, ""));
	    die ();
	}
    }

    if (techFile) {
	verbose ("technology file: %s\n", techFile);
	return (cfopen (techFile, "r"));
    }

    say ("can't open technology file");
    die ();

    return (NULL);
}
