/****************************************************************************/
/*   Program: Graph It II	(The C Program)									*/
/*   SubModule:	main.c  1-7-87												*/
/*   CopyRight By Flynn D. Fishman  January 1987							*/
/*	Feel Free to copy and alter this source									*/
/****************************************************************************/
/*  This module includes most of the major routines and the main loop		*/

#include "graph.h"

/******************************************************/
/*                   Main Program                     */
/*      This is the main body of the program.         */
/******************************************************/

main()
	{
	struct Window *Window;
	struct IntuiMessage *NewMessage;
	ULONG class;
	USHORT code, icon_code;
	SHORT x, y, x1, y1, x2, y2;
	SHORT minx, miny, maxx, maxy;
	USHORT MenuNum, ItemNum;
	SHORT  KeepGoing, mode;
	long int lastx, lasty, startx, starty;
	struct Graph_Parameters		parameters;

	Window = openstuff();

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

	SetDrMd( Window->RPort, JAM2 );

	KeepGoing = TRUE;
	lastx	= 0;
	lasty	= 0;
	mode	= ZOOM;

	SetDefaults(&parameters);
	parameters.xon = FALSE;
	parameters.yon = FALSE;
	parameters.zon = FALSE;
	parameters.hidden = FALSE;

	DrawWindow(Window, &parameters);
	PrintPage(Window, 0l);
	InvertIcon(Window, 1l);

	while( KeepGoing )
		{
		Wait( 1 << Window->UserPort->mp_SigBit);
		while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
			{
			class = NewMessage->Class;
			code = NewMessage->Code;
			x = Window->MouseX;
			y = Window->MouseY;

			if( class == SIZEVERIFY )
				{
				Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
				}

			ReplyMsg( NewMessage );

			switch( class )
				{

				case MENUPICK:
				if( code != MENUNULL )
					{
					/* get menu and item numbers from code */
					MenuNum = MENUNUM( code );
					ItemNum = ITEMNUM( code );

					/* determine appropriate action by menu number */
					switch ( MenuNum )
						{
						case 0:
						switch ( ItemNum )
							{
							case 0: /* Load file */
							   LoadFile(Window, &parameters);
							   DrawWindow(Window, &parameters);
							   PlotGraph(Window, &parameters);
							   DrawVariables(Window, &parameters, mode);
							break;

							case 1: /* save file */
							   SaveFile(Window, &parameters);
							break;

							case 2: /* About		*/
							   PrintPage(Window,0l);
							break;

							case 3:	/* Quit			*/
							   KeepGoing = FALSE;
							break;

							default:
							break;

							} /* end of menu 0 switch	*/
						break;

                     case 1:
					 	icon_code = ItemNum+1;
						goto do_icon;
						break;

                     default:
                        /* Menu number unrecognized, do nothing */
                        break;

                     }	/* end of menu switch	*/
				}	/* if code not menunull	*/

				case MOUSEMOVE:
				 if (lastx !=0)
					{
					if (mode == ZOOM) CrossHair(Window, lastx, lasty);
					}
				 if (x < maxx && x > miny + 2 && y < maxy && y > miny + 2)
					{
					lastx = x;
					lasty = y;
					if (mode == ZOOM) CrossHair(Window, lastx, lasty);
					}
				 else
					lastx = 0;
				break;

				case NEWSIZE:
    			 minx = Window->BorderLeft;
    			 miny = Window->BorderTop;
    			 maxx = Window->Width - Window->BorderRight - XBORDER;
    			 maxy = Window->Height - Window->BorderBottom - YBORDER;
				 DrawWindow(Window, &parameters);
				 PlotGraph(Window, &parameters);
				break;

				case CLOSEWINDOW:
				 KeepGoing = FALSE;
				break;

				case MOUSEBUTTONS:
				 switch ( code )
					{
					case SELECTUP:
                    break;

					case SELECTDOWN:
					 if (x > maxx + YEXPANDX + 2) /* it is an icon */
						{
						icon_code = (y - miny) / (ICONY + 2);
do_icon:				InvertIcon(Window, icon_code);
						switch ( icon_code )
							{
							case 1: /* Zoom Icon */
							 if (mode == MOVE) DrawGrid(Window);
							 mode = ZOOM;
							 InvertIcon(Window, icon_code);
							 InvertIcon(Window, 2l);
							break;

							case 2: /* Move Icon */
							 if (mode != MOVE) DrawGrid(Window);
							 mode = MOVE;
							 InvertIcon(Window, icon_code);
							 InvertIcon(Window, 1l);
							break;

							case 3: /* command line */
							 if(GetCommand(Window, &parameters) != NULL)
							 	{
								Print(Window,"Error Opening Window",0);
								}
							 DrawWindow(Window, &parameters);
							 PlotGraph(Window, &parameters);
							 DrawVariables(Window, &parameters, mode);
							break;

							case 4: /* Hidden lines */
							 parameters.hidden =
							 		(parameters.hidden) ? FALSE : TRUE;
							 InvertIcon(Window, icon_code);
							 if (parameters.zon)
							 	{
							 	DrawWindow(Window, &parameters);
							 	PlotGraph(Window, &parameters);
								DrawVariables(Window, &parameters, mode);
								}
							break;

						 	case 5: /* home */
							 SetDefaults(&parameters);
							 DrawWindow(Window, &parameters);
							 PlotGraph(Window, &parameters);
							 DrawVariables(Window, &parameters, mode);
							break;

							case 6: /* quit */
							 KeepGoing = FALSE;
							break;

							case 7: /* help window */
							 Help(Window, &parameters);
							 if (mode == MOVE) DrawGrid(Window);
							 InvertIcon(Window, icon_code);
							break;

							default:
							break;

							} /* end of icon switch */
						}	 /* end of icon if 	 */

					 else if (x > maxx)			  /* It is the y-expand */
					 	{
						yexpand(Window, &parameters);
						if (mode == MOVE) DrawGrid(Window);
						}

					 else if (y > maxy)			  /* It is the x-expand */
					 	{
						xexpand(Window, &parameters);
						if (mode == MOVE) DrawGrid(Window);
						}

					 else if (mode == ZOOM)
					 	{
						Zoom(Window, &parameters, lastx, lasty);
						lastx = 0;
						}
					 else if (mode == MOVE)
					 	{
						MoveGraph(Window, &parameters, lastx, lasty);
						DrawGrid(Window);
						lastx = 0;
						}
					break;

					case MENUDOWN:
					break;

					default:
					continue;
					}
				break;

				case INACTIVEWINDOW:
	               /*   User has de-selected our window, so a
	                *   little bit of cleaning up may be needed
	                *   to prevent untoward events when he comes
	                *   back to it.
    	            */
				break;

				default:
	               /* message class was unrecognized, so do nothing */
				break;
				}
			}   /* this brace ends the while(NewMessage) loop way back when */
		}

	/*   It must be time to quit, so we have to clean
	 *   up and exit.
	 */
	if (parameters.xon) FreeFunction(parameters.x1);
	if (parameters.yon) FreeFunction(parameters.y1);
	if (parameters.zon) FreeFunction(parameters.z1);
	closestuff(Window);
	exit(TRUE);
	}

PlotGraph(Window, parameters)
struct Graph_Parameters *parameters;
struct Window *Window;
	{
	extern double x,y,z,t;
	long int x1, x2, y1, y2, xcenter, ycenter;
	double xconversion, yconversion, steps, tsteps, loop;

	long int minx, miny, maxx, maxy;
	double lastx, lasty;

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

/* Draw the Graph rectangle area	*/
	DrawRectangle(Window, 1, minx, miny, maxx, maxy);
	SetDrMd(Window->RPort, JAM2);

	if (parameters->zon) Plot3dGraph(Window, parameters);

	xconversion = (maxx - minx) / (parameters->xend - parameters->xstart);
	yconversion = (maxy - miny) / (parameters->yend - parameters->ystart);

	xcenter = -parameters->xstart * xconversion + minx + 2;
	ycenter = -parameters->ystart * yconversion + miny + 2;

	if (parameters->yon)
		{
		z = 0.0;

		if (!parameters->zon)
			{
			/* draw the y axis if needed	*/
			if (parameters->xstart * parameters->xend < 0)
				Line(Window, 2l, xcenter, miny, xcenter, maxy);
			/* draw the x axis if needed	*/
			if (parameters->ystart * parameters->yend < 0)
				Line(Window, 2l, minx, ycenter, maxx, ycenter);
			}

		if (parameters->xon)
			{
			tsteps= parameters->detail/(parameters->tend -parameters->tstart);
			t= parameters->tstart;
			parameters->x1->position = 0;
			parameters->y1->position = 0;
			x = Solve(parameters->x1);
			y = Solve(parameters->y1);
			x1 = x * xconversion + xcenter + 2;	
			y1 = ycenter - y * yconversion;
			lastx = x;
			lasty = y;
			while ( t < parameters->tend )
				{
				t += tsteps; 
				parameters->x1->position = 0;
				parameters->y1->position = 0;
				x = Solve(parameters->x1);
				y = Solve(parameters->y1);

				x2 = x * xconversion + xcenter;	
				y2 = ycenter - y * yconversion;

				if (parameters->zon)
					Line3d(Window, 3l, lastx, lasty, z, x, y, z);
				else Line(Window, 1l, x1, y1, x2, y2);

				x1 = x2;
				y1 = y2;
				lastx = x;
				lasty = y;
				}	/* end of while		*/
			}		/* end of xon (parametric) section	*/
		else
			{
			parameters->y1->position = 0;

			x = parameters->xstart;
			y = Solve(parameters->y1);
			x1 = x * xconversion + xcenter + 2;	
			y1 = ycenter - y * yconversion;
			lastx = x;
			lasty = y;
			while ( x < parameters->xend )
				{
				parameters->y1->position = 0;
				x += ( (double) (parameters->detail) ) /xconversion;
				y = Solve(parameters->y1);
				x2 = x * xconversion + xcenter;	
				y2 = ycenter - y * yconversion;

				if (parameters->zon)
						Line3d(Window, 3l, lastx, lasty, z, x, y, z);
				else Line(Window, 1l, x1, y1, x2, y2);

				x1 = x2;
				y1 = y2;
				lastx = x;
				lasty = y;
				} /* end of while */
			} 	/* of xon else */
		}	 /* end of if	 */
	return();
	}

Zoom(Window, parameters, firstx, firsty)
struct Window *Window;
struct Graph_Parameters *parameters;
long int firstx, firsty;
	{
	long int minx, miny, maxx, maxy, lastx, lasty, x, y;
	struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
	ULONG class;                        /* used in message monitor loop */
	USHORT code;                        /* used in message monitor loop */

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

	lastx = 0;

	for ever
		{
		Wait( 1 << Window->UserPort->mp_SigBit);
		while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
			{
			class = NewMessage->Class;
			code = NewMessage->Code;
			x = Window->MouseX;
			y = Window->MouseY;
			ReplyMsg( NewMessage );

			switch( class )
				{
				case MOUSEMOVE:
					if (lastx !=0)
						{
						CrossHair(Window, lastx, lasty);
						}
					if (x < maxx && x > miny + 2 && y < maxy && y > miny + 2)
						{
						lastx = x;
						lasty = y;
						CrossHair(Window, lastx, lasty);
						}
					else
						lastx = 0;
					break;
				break;

				case MOUSEBUTTONS:
				switch ( code )
					{
					case SELECTUP:
					if (lastx == 0) return();
					Real(Window, parameters, firstx, firsty, lastx, lasty);
					PlotGraph(Window, parameters);
					return();
                	break;

					default:
					break;
					} /* end of mousebutton switch */

				default:
				break;
				} /* end of the case switch	*/
			}
		}	/* end of forever	*/
	}

MoveGraph(Window, parameters, firstx, firsty)
struct Window *Window;
struct Graph_Parameters *parameters;
long int firstx, firsty;
	{
	long int minx, miny, maxx, maxy, deltax, deltay, x, y;
	long int changex, changey;
	struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
	ULONG class;                        /* used in message monitor loop */
	USHORT code;                        /* used in message monitor loop */

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

	changex = 0;
	changey = 0;

	deltax = 1;
	deltay = 1;

	if (firstx > maxx / 3 && firstx < maxx * 2 / 3) deltax = 0;
	if (firsty > maxy / 3 && firsty < maxy * 2 / 3) deltay = 0;

	DrawGrid(Window);

	for ever
		{
		Wait( 1 << Window->UserPort->mp_SigBit);
		while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
			{
			class = NewMessage->Class;
			code = NewMessage->Code;
			x = Window->MouseX;
			y = Window->MouseY;
			ReplyMsg( NewMessage );

			switch( class )
				{
				case MOUSEMOVE:
					if (changex !=0 || changey != 0)
						{
						Box(Window, changex, changey);
						}
					if (x < maxx && x > miny + 2 && y < maxy && y > miny + 2)
						{
						changex = (x - firstx) * deltax;
						changey = (y - firsty) * deltay;
						Box(Window, changex, changey);
						}
					else
						changex = 0;
					break;
				break;

				case MOUSEBUTTONS:
				switch ( code )
					{
					case SELECTUP:
					if (changex == 0 && changey == 0) return();
					Shift(Window, parameters, changex, changey);
					DrawWindow(Window, parameters);
					PlotGraph(Window, parameters);
					return();
                	break;

					default:
					break;
					}

				default:
				break;
				}
			}
		}
	}

xexpand(Window, parameters)
struct Window *Window;
struct Graph_Parameters *parameters;
	{
	struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
	ULONG class;                        /* used in message monitor loop */
	USHORT code;                        /* used in message monitor loop */
	long int minx, miny, maxx, maxy, x, y, xlast;
	double xfactor, xfloat, maxfloat;

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

	xlast = minx + XEXPANDX + 1;

	for ever
		{
		Wait( 1 << Window->UserPort->mp_SigBit);
		while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
			{
			class = NewMessage->Class;
			code = NewMessage->Code;
			x = Window->MouseX;
			y = Window->MouseY;
			ReplyMsg( NewMessage );

			switch( class )
				{
				case MOUSEMOVE:
				EraseButton(Window, xlast, maxy + 3);
				if ( x < minx + XEXPANDX + 1) x = minx + XEXPANDX + 1;
				if ( x > maxx - XEXPANDX - BALLWIDTH - 1)
								x = maxx - XEXPANDX - BALLWIDTH - 1;
				xlast = x;
				DrawButton(Window, xlast, maxy + 3);
				break;

				case MOUSEBUTTONS:
				switch ( code )
					{
					case SELECTUP:
					xfloat = xlast;
					maxfloat = maxx;
					xfactor = xfloat/ maxfloat *
								(parameters->xend - parameters->xstart);
					parameters->xstart = parameters->xstart - xfactor;
					parameters->xend = parameters->xend +  xfactor;
					DrawWindow(Window, parameters);
					PlotGraph(Window, parameters);
					return();
                	break;

					default:
					break;
					}

				default:
				break;
				}
			}
		}
	}

yexpand(Window, parameters)
struct Window *Window;
struct Graph_Parameters *parameters;
	{
	struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
	ULONG class;                        /* used in message monitor loop */
	USHORT code;                        /* used in message monitor loop */
	long int minx, miny, maxx, maxy, x, y, ylast;
	double yfactor, yfloat, maxfloat;

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

	ylast = maxy - YEXPANDY - BALLHEIGHT - 1;

	for ever
		{
		Wait( 1 << Window->UserPort->mp_SigBit);
		while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
			{
			class = NewMessage->Class;
			code = NewMessage->Code;
			x = Window->MouseX;
			y = Window->MouseY;
			ReplyMsg( NewMessage );

			switch( class )
				{
				case MOUSEMOVE:
				EraseButton(Window, maxx + 3, ylast);
				if ( y < miny + YEXPANDY + 1) y = miny + YEXPANDY + 1;
				if ( y > maxy - YEXPANDY - BALLHEIGHT -1 )
								y = maxy - YEXPANDY - BALLHEIGHT - 1;
				ylast = y;
				DrawButton(Window, maxx + 3 , ylast);
				break;

				case MOUSEBUTTONS:
				switch ( code )
					{
					case SELECTUP:
					yfloat = maxy - ylast;
					maxfloat = maxy;
					yfactor = yfloat/ maxfloat *
								(parameters->yend - parameters->ystart);
					parameters->ystart = parameters->ystart - yfactor;
					parameters->yend = parameters->yend + yfactor;
					DrawWindow(Window, parameters);
					PlotGraph(Window, parameters);
					return();
                	break;

					default:
					break;
					}

				default:
				break;
				}
			}
		}
	}

DrawVariables(Window, parameters, mode)
struct Window *Window;
struct Graph_Parameters *parameters;
int mode;
	{
	if (mode == MOVE)
		{
		DrawGrid(Window);
		InvertIcon(Window, 2l);
		}
	else InvertIcon(Window, 1l);
	if (parameters->hidden) InvertIcon(Window, 4l);
	}
