#include "graph.h"

#define ANGLEX	45

long int xcenter, ycenter;
long int minx, miny, maxx, maxy;
double xconversion, yconversion;
double SINX, COSX;

Plot3dGraph(Window, parameters)
struct Graph_Parameters *parameters;
struct Window *Window;
	{
	extern double x,y,z,t;
	extern long int xcenter, ycenter;
	extern double xconversion, yconversion;
	extern double SINX, COSX;
	extern long int minx, miny, maxx, maxy;

	double a, x1, x2, y1, y2, z1, z2, xnext, ynext, xtemp, ytemp;
	double xstep, ystep, minz, maxz;
	double xsize, ysize, top, bottom, left, right;

/* the stuff needed for hidden lines					*/
	WORD *areabuffer;
	struct TmpRas tmpras;
	struct TmpRas *lasttmp;
	struct AreaInfo myAreaInfo;
	char *raster;

    minx = Window->BorderLeft;
    miny = Window->BorderTop;
    maxx = Window->Width - Window->BorderRight - XBORDER;
    maxy = Window->Height - Window->BorderBottom - YBORDER;

/* setup things for whats is needed for hidden		*/
	if (parameters->hidden)
		{
		areabuffer = AllocMem(sizeof(WORD) * 750l, MEMF_CHIP);
		if (areabuffer == NULL) parameters->hidden = FALSE;
		else
			{
			InitArea(&myAreaInfo, areabuffer, 300l);
			Window->RPort->AreaInfo = &myAreaInfo;

			raster = AllocRaster(maxx, maxy);
			if (raster == NULL) parameters->hidden = FALSE;
			else
				{
				lasttmp = Window->RPort->TmpRas;
				InitTmpRas(&tmpras, raster, RASSIZE(maxx, maxy));
				Window->RPort->TmpRas = &tmpras;
				}
			}
		}

	a=ANGLEX * PI / 180;	/* I hate to do this but my doubles do not	*/
	SINX = sin(a);			/* work right under Manx 3.30				*/
	COSX = cos(a);

	left = 0;
	right = 0;

	if (parameters->xend > 0 ) left = parameters->xend * COSX;
	if (parameters->xstart < 0 ) right = -parameters->xstart * COSX;

	if (parameters->ystart < 0) left   -= parameters->ystart;
	if (parameters->yend   > 0) right  += parameters->yend;

	xsize = left + right;
	ysize = parameters->yend - parameters->ystart;

	xconversion = (maxx - minx) / xsize; 
	yconversion = (maxy - miny) / ysize; 

	xstep = parameters->detail / xconversion;
	ystep = parameters->detail / yconversion;

/* analyze the graph to determine the max hight and min hight	*/
	minz =  INFINITY;
	maxz = -INFINITY;

	SetAPen(Window->RPort, 1l);
	SetBPen(Window->RPort, 0l);
	SetDrMd(Window->RPort, JAM2);
	Print(Window, "Please Wait Analyzing Graph", 1);

	y = parameters->ystart;
	while ( y < parameters->yend )
		{
		x = parameters->xstart;
		while ( x < parameters->xend )
			{
			parameters->z1->position = 0;
			z1 = Solve(parameters->z1);
			x += xstep; 
			z  = (z1 - x * COSX);
			minz = min(minz, z);
			maxz = max(maxz, z);
			} /* end of  xwhile */
		y += parameters->ylabels;
		}    /* end of y loop */

	ysize = maxz - minz;
	yconversion = (maxy - miny) / ysize;

	ystep = parameters->detail / yconversion;

	if (left > 0 ) xcenter = left * xconversion + minx + 2;
	else xcenter = -left * xconversion + minx + 2;

	ycenter = maxy + minz * yconversion;

/* Draw the Graph rectangle area	*/

	SetAPen(Window->RPort, 0);
	SetOPen(Window->RPort, 2);
	SetDrMd(Window->RPort, JAM2);
	DrawRectangle(Window, 1, minx, miny, maxx, maxy);

	xconversion *= 0.90;
	yconversion *= 0.90;

	Line3d(Window, 2l, 0.0, 0.0, 0.0, parameters->xend, 0.0, 0.0);
	Line3d(Window, 2l, 0.0, 0.0, 0.0, 0.0, parameters->yend, 0.0);
	Line3d(Window, 2l, 0.0, 0.0, 0.0, 0.0, 0.0, parameters->zend);

	ynext = parameters->ystart;
	while (ynext < parameters->yend)
		{
		xnext = parameters->xstart;
		while (xnext < parameters->xend)
			{
			parameters->z1->position = 0;
			x = xnext;
			y = ynext;
			x1 = x;
			y1 = y;
			z1 = Solve(parameters->z1);
			InitVertices(Window, parameters, 1l, x1, y1, z1);

			while (x < xnext + parameters->xlabels)
				{
				parameters->z1->position = 0;
				x += xstep; 
				x1 = x;
				y1 = y;
				z1 = Solve(parameters->z1);
				AddVertice(Window, parameters, x1, y1, z1);
				} /* end of xblock while */

			xtemp = x1;
			while (y < ynext + parameters->ylabels)
				{
				parameters->z1->position = 0;
				y += ystep; 
				x1 = x;
				y1 = y;
				z1 = Solve(parameters->z1);
				AddVertice(Window, parameters, x1, y1, z1);
				} /* end of yblock while */

			ytemp = y1;
			if (parameters->hidden || xnext == parameters->xstart
				|| y >= parameters->yend)
				{
				while (x > xnext)
					{
					parameters->z1->position = 0;
					x -= xstep; 
					x1 = x;
					y1 = y;
					z1 = Solve(parameters->z1);
					AddVertice(Window, parameters, x1, y1, z1);
					} /* end of xblock while */
				}    /* end of the check to see if valid */

			if (parameters->hidden || xnext == parameters->xstart)
				{
				while (y > ynext)
					{
					parameters->z1->position = 0;
					y -= ystep; 
					x1 = x;
					y1 = y;
					z1 = Solve(parameters->z1);
					AddVertice(Window, parameters,  x1, y1, z1);
					} /* end of yblock while */
				}    /* end of the if */

			DrawVertices(Window, parameters);
			xnext = xtemp;
			} /* end of  xmaster */
		ynext = ytemp;
		}    /* end of ymaster */

	if (parameters->hidden)
		{
		FreeRaster(raster, maxx, maxy);
		FreeMem(areabuffer, sizeof(WORD) * 750l);
		Window->RPort->TmpRas = lasttmp;
		}
	return();
	}

Line3d(Window, colour, x1, y1, z1, x2, y2, z2)
struct Window *Window;
long int colour;
double x1, y1, z1, x2, y2, z2;
	{
	extern long int xcenter, ycenter;
	extern double xconversion, yconversion;
	extern double SINX, COSX;

	long int xa, ya, xb, yb;

	xa = xcenter + (x1 * SINX - y1) * xconversion;
	ya = ycenter - (x1 * COSX - z1) * yconversion;

	xb = xcenter + (x2 * SINX - y2) * xconversion;
	yb = ycenter - (x2 * COSX - z2) * yconversion;

	Line(Window, colour, xa, ya, xb, yb);
	}

long int lastx, lasty;
int points;

InitVertices(Window, parameters, colour, x1, y1, z1)
struct Window *Window;
struct Graph_Parameters *parameters;
long int colour;
double x1, y1, z1;
	{
	extern long int xcenter, ycenter;
	extern double xconversion, yconversion;
	extern double SINX, COSX;
	extern long minx, miny, maxx, maxy;
	extern int lastx, lasty;
	extern int points;

	long int xa, ya;

	xa = xcenter + (x1 * SINX - y1) * xconversion;
	ya = ycenter - (x1 * COSX - z1) * yconversion;

	lastx = xa;
	lasty = ya;

	if (!(xa > minx && xa < maxx && ya > miny && ya < maxy) ) return();

	SetOPen(Window->RPort, colour);
	SetAPen(Window->RPort, 0l);

	points = 1;
	if (parameters->hidden) AreaMove(Window->RPort, xa, ya);
	else
		{
		Move(Window->RPort, xa, ya);
		SetAPen(Window->RPort, colour);
		}
	}

AddVertice(Window, parameters, x1, y1, z1)
struct Window *Window;
struct Graph_Parameters *parameters;
double x1, y1, z1;
	{
	extern long int xcenter, ycenter;
	extern double xconversion, yconversion;
	extern double SINX, COSX;
	extern long minx, miny, maxx, maxy;
	extern long int lastx, lasty;
	extern int points;

	long int xa, ya;

	xa = xcenter + (x1 * SINX - y1) * xconversion;
	ya = ycenter - (x1 * COSX - z1) * yconversion;

	if (lastx == xa && lasty == ya) return();

	lastx = xa;
	lasty = ya;

	if (!(xa > minx && xa < maxx && ya > miny && ya < maxy) ) return();

	if (parameters->hidden)
		{
		AreaDraw(Window->RPort, xa, ya);
		points++;
		}
	else Draw(Window->RPort, xa, ya);
	}

DrawVertices(Window, parameters)
struct Window *Window;
struct Graph_Parameters *parameters;
	{
	extern int points;

	if (parameters->hidden) AreaEnd(Window->RPort);
	}
