/*
 * aplot - Apollo plotter.  Reads a Unix plot file on the standard
 *   input, produces a plot on your Apollo node screen.
 *
 *   Written by Jim Rees April 1984
 *   Circles and arcs added March 1990 by Jim Rees
 */

#include "/sys/ins/base.ins.c"
#include "/sys/ins/error.ins.c"
#include "/sys/ins/gpr.ins.c"

#include <stdio.h>

#define MAXSIZE	1024

#define APS(s)	*s, (short) strlen(s)

char *fontname = "/sys/dm/fonts/f5x7";

short wx0, wy0, wx1, wy1;
int wxd, wyd;
int wsize;
int plotted;

/* Keyset of [' ' .. '~'] */
gpr_$keyset_t keyset = { 0, 0, 0, 0, 0x7fffffff, 0xffffffff, 0xffffffff, 0 };

/* Line patterns */
struct {
	char *name;
	short len;
	gpr_$line_pattern_t pat;
} linepats[] = {
	"dotted",	16, { 0x8888, 0, 0, 0 },
	"solid",	16, { 0xffff, 0, 0, 0 },
	"longdashed",	16, { 0xff00, 0, 0, 0 },
	"shortdashed",	16, { 0xf0f0, 0, 0, 0 },
	"dotdashed",	11, { 0x8f00, 0, 0, 0 },
	NULL,		 0, { 0, 0, 0, 0 }
};

main(ac, av)
int ac;
char *av[];
{
	status_$t st;
	gpr_$offset_t size;
	gpr_$bitmap_desc_t bitmap;
	short fontid, plane, count;

	size.x_size = MAXSIZE;
	size.y_size = MAXSIZE;
	gpr_$init(gpr_$direct, ios_$stdout, size, 0, bitmap, st);
	check(st);

        gpr_$load_font_file(APS(fontname), fontid, st);
	check(st);
	gpr_$set_text_font(fontid, st);
	check(st);

	gpr_$enable_input(gpr_$keystroke, keyset, st);
	check(st);

	gpr_$set_auto_refresh(true, st);
	check(st);

	gpr_$set_clipping_active(true, st);
	check(st);

	gpr_$inq_bitmap_dimensions(bitmap, size, plane, st);
	check(st);

	wsize = size.x_size < size.y_size ? size.x_size : size.y_size;

	wx1 = wy1 = wsize;

	gpr_$acquire_display(st);
	check(st);

	dofile();

	gpr_$force_release(count, st);
	check(st);

	gpr_$terminate(false, st);
	check(st);

	exit(0);
}

dofile()
{
	int c;
	short x0, y0, x1, y1;
	char str[80];
	gpr_$position_t pos0, pos1;
	status_$t st;

	while ((c = getchar()) != EOF) {
		switch(c) {
		case 'm':
			getcvpt(&x0, &y0);
			gpr_$move(x0, y0, st);
			check(st);
			break;
		case 'n':
			getcvpt(&x0, &y0);
			gpr_$line(x0, y0, st);
			check(st);
			plotted = 1;
			break;
		case 'p':
			getcvpt(&x0, &y0);
			gpr_$move(x0, y0, st);
			gpr_$line(x0, y0, st);
			check(st);
			plotted = 1;
			break;
		case 'l':
			getcvpt(&x0, &y0);
			gpr_$move(x0, y0, st);
			getcvpt(&x0, &y0);
			gpr_$line(x0, y0, st);
			plotted = 1;
			break;
		case 't':
			getstr(str);
			gpr_$text(str, (short) strlen(str), st);
			check(st);
			plotted = 1;
			break;
		case 'a':
			getcvpt(&pos0.x_coord, &pos0.y_coord);
			getcvpt(&x1, &y1);
			getcvpt(&pos1.x_coord, &pos1.y_coord);
			gpr_$move(x1, y1, st);
			gpr_$arc_c2p(pos0, pos1, gpr_$arc_ccw, gpr_$arc_draw_full, st);
			check(st);
			plotted = 1;
			break;
		case 'c':
			getcvpt(&pos0.x_coord, &pos0.y_coord);
			getnum(&x1);
			cvx(&x1);
			gpr_$circle(pos0, x1, st);
			check(st);
			plotted = 1;
			break;
		case 'e':
			if (plotted) {
				pagewait();
				gpr_$clear(gpr_$background, st);
				plotted = 0;
			}
			break;
		case 'f':
			getstr(str);
			setlinepat(str);
			break;
		case 's':
			getpt(&wx0, &wy0);
			getpt(&wx1, &wy1);
			wxd = (int) wx1 - (int) wx0;
			wyd = (int) wy1 - (int) wy0;
			break;
		case 'z':
			getnum(&x0);
			break;
		}
	}
	pagewait();
}

setlinepat(patname)
char *patname;
{
	int i;
	status_$t st;

	for (i = 0; linepats[i].name != NULL; i++)
		if (!strcmp(patname, linepats[i].name))
			break;
	if (linepats[i].name != NULL)
		gpr_$set_line_pattern((short) 1, linepats[i].pat, linepats[i].len, st);
}

getnum(xp)
short *xp;
{
	*xp = getchar() & 0xff;
	*xp |= getchar() << 8;
}

/* Get a coord pair from stdin in Unixplot format. */

getpt(xp, yp)
short *xp, *yp;
{
	getnum(xp);
	getnum(yp);
}

getcvpt(xp, yp)
short *xp, *yp;
{
	getpt(xp, yp);
	cvxy(xp, yp);
}

pagewait()
{
	gpr_$event_t type;
	char data;
	gpr_$position_t pos;
	status_$t st;

	gpr_$move(0, 0, st);
	gpr_$set_cursor_active(true, st);
	gpr_$event_wait(type, data, pos, st);
	check(st);
	gpr_$set_cursor_active(false, st);
}

/* Convert from user's coords to screen coords. */

cvx(xp)
short *xp;
{
	*xp = (*xp - wx0) * wsize / wxd;
}

cvy(yp)
short *yp;
{
	*yp = (wy1 - *yp) * wsize / wyd;
}

cvxy(xp, yp)
short *xp, *yp;
{
	cvx(xp);
	cvy(yp);
}

/* Get a nl-terminated string from stdin. */

getstr(s)
char *s;
{
	fgets(s, 80, stdin);
	s[strlen(s)-1] = '\0';
}

check(st)
status_$t st;
{
	if (st.all) {
		error_$print(st);
		exit(1);
	}
}
