#include <stdio.h>
#include "colour.h"

#define sput(string)	fputs(string,stdout)

/*
 * global variables - so we can keep track of where we are, etc.
 */
static	int	curr_x;		/* current x position 0-767 */
static	int	curr_y;		/* current y position 0-511 */
static	int	curr_hue;	/* current colour, 0-15 */
static	int	real_x;		/* where we really are */
static	int	real_y;
static	int	real_hue;

char	shades[MAXCOLOURS][6] = {
		"000",		/* Black	*/
		"0F0",		/* Green	*/
		"00F",		/* Blue 	*/
		"F00",		/* Red  	*/
		"0FF",		/* Cyan 	*/
		"F0F",		/* Magenta	*/
		"F80",		/* Orange	*/
		"FF0",		/* Yellow	*/
		"AFA",		/* Lt. Green	*/
		"AAF",		/* Lt. Blue	*/
		"FAA",		/* Pink		*/
		"0A0",		/* Dark Green	*/
		"00A",		/* Dark Blue	*/
		"A00",		/* Dark Red	*/
		"AAA",		/* Grey		*/
		"FFF"		/* White	*/
};

char hexvalue[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

/*
 * turn the graphics screen off, and the alpha screen on.
 */
alpha_on()
{
	sput("GBAA");
}

/*
 * turn the graphics screen on, and the alpha screen off.
 */
graphics_on()
{
	sput("ABGA");
}

/*
 * turn graphics cursor on
 */
cursor_on()
{
	sput("CA");
}

/*
 * turn graphics cursor off
 */
cursor_off()
{
	sput("CB");
}

/*
 * change current colour to hue.
 */
colour(hue)
int hue;
{
	curr_hue = hue;
}

/*
 * fill space at the current position with the current colour,
 * to a boundary of colour hue.
 */
fill(hue)
int hue;
{
	xyflush();
	printf("JK%c", hexvalue[hue]);
}

/*
 * disc plots a disc of colour hue at (x, y) with given radius.
 */
disc(radius)
int radius;
{
	xyflush();
	printf("JN%3d0", radius + 100);
	/* Where do dev_x, dev_y end up? */
}

/*
 * greyscale - set up the video transformation tables to a simple grey scale
 */
greyscale()
{
	register int i;
	register char c;

	for (i = 0; i < MAXCOLOURS; ++i) {
		c = hexvalue[i];
		printf("JG%c%c%c%c0", c, c, c, c);
	}
}

/*
 * colourscale - set up the video transformation tables to the
 *		 colour scale, defined in colour.h
 */
colourscale()
{
	register int i;

	for (i = 0; i < MAXCOLOURS; ++i) {
		printf("JG%c%s0", hexvalue[i], shades[i]);
	}
}

#ifdef SPHERE
/*
 * sphere - plot a three-dimensional-looking sphere, by drawing lots
 * of circles of decreasing radius, and increasing brightness, on top
 * of each other.
 *
 * greyscale() should be called first, to obtain 3-D effect.
 *
 * These defines determine what range of shades is used for the spheres:
 */

#define LOW	5
#define HIGH	(MAXCOLOURS - 1)

sphere(x, y, radius)
int x, y, radius;
{
	register int hue;	/* hue of circle being plotted */
	register int r;		/* radius of circle being plotted */
	register int depth;	/* how far out circle is from centre of sphere */
	register int jump;	/* difference between successive depths */
	register int rad_squared;
	double sqrt();

	jump = (radius / (HIGH - LOW));
	rad_squared = radius * radius;
	hue = LOW;
	for (depth = 0; depth < radius && hue <= HIGH; ++hue, depth += jump) {
		r = (int) sqrt((double) (rad_squared - (depth * depth)));
		disc(x, y, r, hue);
	}
}

#endif
 
/*******************************************************
 *						       *
 * DIGS - compatible stuff (well, mostly) STARTS HERE  *
 *						       *
 *******************************************************/

/*
 * initialise the sigma for graphics - alpha screen off - graphics screen on
 */
init()
{
	initty();
	sput("\r+-*/DD000ABGA");
	colourscale();
	fflush(stdout);
	real_x = real_y = -12345;
	curr_hue = WHITE;
	real_hue = -1;
}

/*
 * we've finished, so reset the terminal.
 */
finish()
{
	alpha_on();
	resetty();
}

/*
 * clear the graphics display
 */
clear()
{
	sput("DA");
}

/*
 * make sure the screen is updated.
 */
update()
{
	xyflush();
	fflush(stdout);
}

/*
 * move to a given screen position (x, y)
 */
moveto(x, y)
int x, y;
{
	curr_x = x;
	curr_y = y;
}

/*
 * plot a line from the current position to (x, y) in the current colour
 * clipping it on the screen if necessary
 */
clippedlineto(x,y)
register int x,y;
{
	int x1, y1, x2, y2; /* NOT registers */

	x1 = curr_x; x2 = x;
	y1 = curr_y; y2 = y;
	if (clip(&x1, &y1, &x2, &y2) == 0) {
		moveto(x1,y1);
		xyflush();
		printf("%3d%3d", x2 + 100, y2 + 100 );
		real_x = x2; real_y = y2;
	}
	curr_x = x; curr_y = y;
}

/* unclipped lineto */
lineto(x,y)
register int x,y;
{
	xyflush();
	printf("%3d%3d",x+100,y+100);
	real_x = curr_x = x;
	real_y = curr_y = y;
}

/*
 * move current position to x+dx, y+dy.
 */
moveby(dx, dy)
int dx, dy;
{
	moveto(curr_x + dx, curr_y + dy);
}

/*
 * draw a line from current x, y -> x+dx, y+dy.
 */
lineby(dx, dy)
int dx, dy;
{
	lineto(curr_x + dx, curr_y + dy);
}

/*
 * plot a circle at current position with given radius.
 */
circle(radius)
int radius;
{
	xyflush();
	printf("JM%3d0", radius + 100);
	real_x += radius;
}

/*
 * message - print the given string in the top-left-hand corner.
 */
message(string,a1,a2,a3,a4,a5,a6,a7,a8,a9)
char *string;
{
	char c;

	sput("AA\n\f");
	printf(string,a1,a2,a3,a4,a5,a6,a7,a8,a9);
	fflush(stdout);
	read(0,&c,1);
	sput("\f\r+-*/AB");
	fflush(stdout);
}

xyflush()
{
	if ((curr_x != real_x) || (curr_y != real_y)) {
		printf("GI%3d%3dGJ", curr_x + 100, curr_y + 100);
		real_x = curr_x; real_y = curr_y;
	}
	if (curr_hue != real_hue) {
		printf("HI%c", hexvalue[curr_hue]);
		real_hue = curr_hue;
	}
}

extern int maxx, maxy, minx, miny;

#define CLIP_MINX 1
#define CLIP_MAXX 2
#define CLIP_MINY 4
#define CLIP_MAXY 8
#define code(x,y) ( ((x) < minx ? CLIP_MINX : 0) | \
		    ((x) > maxx ? CLIP_MAXX : 0) | \
		    ((y) < miny ? CLIP_MINY : 0) | \
		    ((y) > maxy ? CLIP_MAXY : 0) )
int
clip(x1,y1,x2,y2)
int *x1, *y1, *x2, *y2;
{
	register int c, c1, c2;
	register int x, y;

	c1 = code (*x1, *y1);
	c2 = code (*x2, *y2);
	if (c1 & c2) return(1); /* both on same side of window */
	while (c1 || c2) {
		c = (c1 != 0 ? c1 : c2);
		if ( c & CLIP_MINX ) {
			y = *y1 + (*y2-*y1)*(minx-*x1)/(*x2-*x1);
			x = minx ;
		} else if ( c & CLIP_MAXX ) {
			y = *y1 + (*y2-*y1) * (maxx - *x1 )/(*x2-*x1);
			x = maxx ;
		} else if ( c & CLIP_MINY ) {
			x = *x1 + (*x2-*x1)*(miny -*y1)/(*y2-*y1);
			y = miny;
		} else if ( c & CLIP_MAXY ){
			x = *x1 + (*x2-*x1)*(maxy-*y1)/(*y2-*y1);
			y = maxy ;
		}
		if (c == c1) {
			*x1 = x; *y1 = y;
			c1 = code(x,y);
		} else {
			*x2 = x; *y2 = y;
			c2 = code(x,y);
		}
		if (c1 & c2) return(1);
	}
	return(0);
}
