/*****************************************************************************
*   General routines to	handle the graphics.				     *
*									     *
* Written by:  Gershon Elber			       Ver 0.1, Oct. 1989    *
*									     *
* Support: PostScript to standard output.				     *
*****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#ifdef __MSDOS__
#include <io.h>
#include <fcntl.h>
#include <bios.h>
#include <dos.h>
#include <conio.h>
#include <sys\types.h>
#else
#include <sys/types.h>
#endif /* __MSDOS__ */


#include "program.h"
#include "igraph.h"

#define PS_PSIZE_X 1024                                         /* In points. */
#define PS_PSIZE_Y 640

#define PS_ISIZE_X 10.0                                         /* In inches. */
#define PS_ISIZE_Y 6.25

#define PS_NORMAL_FONT_SIZE	12

static TextOrientationType TextOrientation = TEXT_ORIENT_HORIZ;
static int TextScale = 1;
static TextHorizJustifyType TextXCenter = TEXT_X_CENTER;
static TextVertJustifyType TextYCenter = TEXT_Y_CENTER;

static int CursorX, CursorY;
static int GraphicMode = FALSE;

static void IGSetFontSize(int Size);

/****************************************************************************
* Routine to reset all the system to starting condition	:		    *
****************************************************************************/
void IGInitGraph(void)
{
    static char *PSHeader[] = {
	"%!PS-Adobe-2.0 EPSF-1.2",
	"%%BoundingBox: 36 36 540 756",    /* 7x10 inches, LL at [0.5, 0.5]. */
	"%%Title:",
	"%%Creator: EED-PS",
	"%%CreationDate:",
	"%%EndComments",
	"%%\n",
	"/line {",
	"    newpath",
	"    moveto",
	"    lineto",
	"    stroke",
	"} def\n",
	"gsave",
	"1 setlinewidth",
	"1 setlinecap",
	"1 setlinejoin",
	"72 72 scale\t\t\t\t%% Talk inches",
	"7.0 10.5 translate -90 rotate\t\t%% 0.5 inch border from all sides",
	NULL
    };
    int i;
    time_t time1970 = time(NULL);


    for (i = 0; PSHeader[i] != NULL; i++) {
	if (strcmp(PSHeader[i], "%%Title:") == 0)
	    printf("%s %s\n", PSHeader[i], EEDataFileName);
	else if (strcmp(PSHeader[i], "%%CreationDate:") == 0)
	    printf("%s %s", PSHeader[i], ctime(&time1970));
	else
	    printf("%s\n", PSHeader[i]);
    }

    printf("%lf %lf scale\t\t%% Move to EED coordinates\n",
			PS_ISIZE_X / PS_PSIZE_X, -PS_ISIZE_Y / PS_PSIZE_Y);

    IGSetFontSize(PS_NORMAL_FONT_SIZE);			      /* Select font. */

    GraphicMode = TRUE;
}

/****************************************************************************
* Routine to close and shutdown	graphic	mode :				    *
****************************************************************************/
void IGCloseGraph(void)
{
    if (GraphicMode) {
	printf("showpage\n");
	printf("grestore\n");

	GraphicMode = FALSE;
    }
}
/****************************************************************************
* Routine to set a font size.						    *
****************************************************************************/
static void IGSetFontSize(int Size)
{
    printf("/%s findfont [%d 0 0 -%d 0 0] makefont setfont\n",
	   EEPSFontName, Size, Size);
    printf("/stringheight %d def\n", (int) (0.65 * PS_NORMAL_FONT_SIZE));
}

/****************************************************************************
* Routine to map drawing x coordinate into screen space.		    *
****************************************************************************/
int IGMapX(int x)
{
    return x >> IG_DEFAULT_ZOOM_FACTOR;
}

/****************************************************************************
* Routine to map drawing y coordinate into screen space.		    *
****************************************************************************/
int IGMapY(int y)
{
    return y >> IG_DEFAULT_ZOOM_FACTOR;
}

/****************************************************************************
* Routine to move to a new position, as in Drawing space.		    *
****************************************************************************/
void IGMoveTo(int x, int y)
{
    CursorX = IGMapX(x);
    CursorY = IGMapY(y);
}

/****************************************************************************
* Routine to draw to a new position, as in Drawing space.		    *
****************************************************************************/
void IGLineTo(int x, int y)
{
    int NewX, NewY;

    printf("%d %d %d %d line\n\n", CursorX, CursorY,
					NewX = IGMapX(x), NewY = IGMapY(y));
    CursorX = NewX;
    CursorY = NewY;
}

/****************************************************************************
* Routine to draw a line between the two given points.			    *
****************************************************************************/
void IGLine(int x1, int y1, int x2, int y2)
{
    printf("%d %d %d %d line\n\n", IGMapX(x1), IGMapY(y1),
				   IGMapX(x2), IGMapY(y2));
}

/****************************************************************************
* Routine to draw a new polyline and fill it if Fill.			    *
****************************************************************************/
void IGPoly(int n, int *Points, int Fill)
{
    int i;

    printf("newpath\n");
    printf("%d %d moveto\n", IGMapX(Points[0]), IGMapY(Points[1]));
    for (i = 1; i < n; i++) {
	printf("%d %d lineto\n", IGMapX(Points[i * 2]),
				 IGMapY(Points[i * 2 + 1]));
    }

    if (Fill)
	printf("closepath fill\n\n");
    else
	printf("stroke\n\n");
}

/****************************************************************************
* Routine to draw a bar, as in Drawing space.				    *
****************************************************************************/
void IGBar(int x1, int y1, int x2, int y2)
{
    x1 = IGMapX(x1);
    y1 = IGMapY(y1);
    x2 = IGMapX(x2);
    y2 = IGMapY(y2);
    printf("newpath\n");
    printf("%d %d moveto\n", x1, y1);
    printf("%d %d lineto\n", x1, y2);
    printf("%d %d lineto\n", x2, y2);
    printf("%d %d lineto\n", x2, y1);
    printf("%d %d lineto\n", x1, y1);
    printf("closepath fill\n\n");
}

/****************************************************************************
* Routine to draw a circle, as in Drawing space.			    *
****************************************************************************/
void IGCircle(int x, int y, int r)
{
    printf("newpath %d %d %d 0 360 arc stroke\n\n", IGMapX(x), IGMapY(y),
						r >> IG_DEFAULT_ZOOM_FACTOR);
}

/****************************************************************************
* Routine to draw an arc, as in Drawing space.				    *
* As the Y axes is inverted the Angles should be inverted as well.	    *
****************************************************************************/
void IGArc(int x, int y, int StAngle, int EndAngle, int r)
{
    printf("newpath %d %d %d %d %d arc stroke\n\n", IGMapX(x), IGMapY(y),
				r >> IG_DEFAULT_ZOOM_FACTOR, StAngle, EndAngle);
}

/****************************************************************************
* Routine to draw the given text in current cursor position.		    *
****************************************************************************/
void IGText(char *s)
{
    printf("\n%d %d moveto (%s)\n", CursorX, CursorY, s);

    if (TextScale > 1)
	IGSetFontSize(PS_NORMAL_FONT_SIZE * TextScale);	      /* Select font. */

    switch (TextXCenter) {
	case TEXT_X_LEFT:
	    switch (TextOrientation) {
		case TEXT_ORIENT_HORIZ:
		    break;
		case TEXT_ORIENT_VERT:
		    printf("stringheight 2 add 0 rmoveto\n");
		    break;
	    }
	    break;
	case TEXT_X_CENTER:
	    switch (TextOrientation) {
		case TEXT_ORIENT_HORIZ:
		    printf("dup stringwidth pop 2 div neg 0 rmoveto\n");
		    break;
		case TEXT_ORIENT_VERT:
		    printf("stringheight 2 div 0 rmoveto\n");
		    break;
	    }
	    break;
	case TEXT_X_RIGHT:
	    switch (TextOrientation) {
		case TEXT_ORIENT_HORIZ:
		    printf("dup stringwidth pop neg -2 add 0 rmoveto\n");
		    break;
		case TEXT_ORIENT_VERT:
		    break;
	    }
	    break;
    }

    switch (TextYCenter) {
	case TEXT_Y_BOTTOM:
	    switch (TextOrientation) {
		case TEXT_ORIENT_HORIZ:
		    printf("0 -2 rmoveto\n");
		    break;
		case TEXT_ORIENT_VERT:
		    break;
	    }
	    break;
	case TEXT_Y_CENTER:
	    switch (TextOrientation) {
		case TEXT_ORIENT_HORIZ:
		    printf("0 stringheight 2 div rmoveto\n");
		    break;
		case TEXT_ORIENT_VERT:
		    printf("dup stringwidth pop 2 div 0 exch rmoveto\n");
		    break;
	    }
	    break;
	case TEXT_Y_TOP:
	    switch (TextOrientation) {
		case TEXT_ORIENT_HORIZ:
		    printf("0 stringheight 2 add rmoveto\n");
		    break;
		case TEXT_ORIENT_VERT:
		    printf("dup stringwidth pop 0 exch rmoveto\n");
		    break;
	    }
	    break;
    }

    switch (TextOrientation) {
	case TEXT_ORIENT_HORIZ:
	    printf("show\n");
	    break;
	case TEXT_ORIENT_VERT:
	    printf("gsave -90 rotate show grestore\n");
	    break;
    }

    if (TextScale > 1)
	IGSetFontSize(PS_NORMAL_FONT_SIZE);		      /* Select font. */
    printf("\n");
}

/****************************************************************************
* Routine to set attributes - horiz./vert. and centering.		    *
****************************************************************************/
void IGTextFormat(TextOrientationType Orient, int Scale,
		  TextHorizJustifyType XCenter, TextVertJustifyType YCenter)
{
    TextOrientation = Orient;
    TextScale = Scale;
    TextXCenter = XCenter;
    TextYCenter = YCenter;
}

/****************************************************************************
* Routine to draw the not bar above a negated text.			    *
* As in postscript the font is not fixed size we will let it figure the     *
* second coordinate (x2, y2) accoring to Str real length.		    *
* We assume (x1, y1) are correct.					    *
****************************************************************************/
void IGDrawNotBar(int x1, int y1, int x2, int y2, char *Str)
{
    /* For some reason this special justification is somewhat off so here is */
    /* a kluge to fix this one.						     */
    if (y2 == 0 && x2 < 0) x1 -= 3;

    /* Push first coordinate of line and then push real string width         */
    /* using postscript stringwidth operator.				     */
    printf("%d %d (%s) stringwidth pop ", x1, y1, Str);

    /* Detect the orientation from the coordinates: */
    if (x2 == 0) {				     /* Its a vertical line. */
	if (y2 < 0) {				     /* It is top justified. */
	    printf("neg %d add %d exch line\n", y1, x1);
	}
	else {					  /* It is bottom justified. */
	    printf("%d add %d exch line\n", y1, x1);
	}
    }
    else {					  /* Its an horizontal line. */
	if (x2 < 0) {				   /* It is right justified. */
	    printf("neg %d add %d line\n", x1, y1);
	}
	else {					    /* It is left justified. */
	    printf("%d add %d line\n", x1, y1);
	}
    }
}

/****************************************************************************
* Routine to set color to color within range.				    *
****************************************************************************/
void IGSetColor(int Color)
{
}

/*****************************************************************************
*   Relative line to in screen coordinates.				     *
*****************************************************************************/
void IGLineRelToNoMap(int x, int y)
{
    printf("%d %d %d %d line\n\n", CursorX, CursorY, CursorX + x, CursorY + y);
    CursorX += x;
    CursorY += y;
}

/*****************************************************************************
*   Move to in screen coordinates.					     *
*****************************************************************************/
void IGMoveToNoMap(int x, int y)
{
    CursorX = x;
    CursorY = y;
}

/*****************************************************************************
*   Line in screen coordinates.						     *
*****************************************************************************/
void IGLineNoMap(int x1, int y1, int x2, int y2)
{
    printf("%d %d %d %d line\n\n", x1, y1, x2, y2);
}

/*****************************************************************************
*   Returns text width in screen coordinates.				     *
* We need to approximate here as this is not fixed size font...		     *
*****************************************************************************/
int IGTextWidthNoMap(char *s)
{
    return strlen(s) * 6 * TextScale;
}

/*****************************************************************************
*   Returns text height in screen coordinates.				     *
* We need to approximate here as this is not fixed size font...		     *
*****************************************************************************/
int IGTextHeightNoMap(char *s)
{
    return 8 * TextScale;
}
