/****************************************************************************/
/*   Program: Graph It II	(The C Program)									*/
/*   SubModule:	func.c  1-7-87												*/
/*   CopyRight By Flynn D. Fishman  January 1987							*/
/*	Feel Free to copy and alter this source									*/
/****************************************************************************/
/* This function includes all of the math related subroutines to solve all
	the graph related problems												*/

#include "graph.h"
static char *(functions[]) = {"xx", "tt", "yy", "zz", "((", "))",
							  "++", "--", "//", "^^", "==", "**",
                              "ccos", "ssin", "Ttan", "eexp", "PPI", "EE",
                              "aatan", "Sasin", "Cacos", "lln", "Aabs", "Ll",
							  "end"};

double Solve(formula)
struct Formula_Master *formula;
  {
  extern double x, y, z, t;
  double lop, a, b, total;
  char func;     

  a = 0;
  b = 0;
  total = Value(formula);

  while (formula->equation[formula->position] != '0' )
    {
    func = formula->equation[formula->position++];
	if (func == 0) break;

    switch (func)
      {
      case '+':
        total = total + Value(formula);
       break;

      case '-':
        total = total - Value(formula);
       break;

      case '*':
        total = total * Value(formula);
       break;

      case '/':
        a = Value(formula);
        if (a != 0) total = total / a;
        else total = INFINITY;
       break;

      case '^':
        total = pow(total, Value(formula) );
       break;

      case '=':
        total = (total == Value(formula) );
       break;

	  case '\)':
	    return(total);
	   break;

      default:
	  	formula->error = INVALID;
        return(0);

      } /* end of case */
    }  /* end of while */

  return (total);
  }  /* end of Solve */

double Value(formula)
struct Formula_Master *formula;
	{
	extern double x, y, z, t;
	int whichfunc, position;
	double a,b;
	char test, bitmask, tmp, lowmask, highbit;

	position = formula->position;

	test = formula->equation[formula->position];
	if (test == '\(')
		{
		formula->position++;
		return(Solve(formula));
		}

	tmp = (test & HIGHBIT);
	if (tmp != 0)
		{
		return (
		        formula->constants[
				   LOWMASK & formula->equation[formula->position++]
				                  ]
				);
		}
	formula->position++;

	switch (test)
	{
    case '\(':  /* ( */ 
      return(Solve(formula));
    break;

    case 'x':  /* X */ 
      return(x);
    break;

    case 'y':  /* Y */
      return(y);
    break;

    case 't':  /* T */
      return(t);
    break;

    case 'z':  /* Z */
      return(z);
    break;

    case 'c':  /* Cos */
      return (cos ( Value (formula) ) );
    break;

    case 's':  /* Sin */
      return (sin ( Value (formula) ) );
    break;

    case 'T':  /* Tan */
      return (tan ( Value (formula) ) );
    break;

    case 'e':  /* E to the x */
      return ( exp ( Value(formula) ) );
    break;

    case 'P':  /* PI */
      return ( PI );
    break;

    case 'E':  /* E to the x */
      return ( exp (1.0) );
    break;

    case 'l': /* ln */
      return ( log ( Value(formula) ) );
    break;

    case 'a': /* Atan */
      return ( atan ( Value(formula) ) );
    break;

    case 'S': /* Asin */
      return ( asin ( Value(formula) ) );
    break;

    case 'C': /* Acos */
      return ( acos ( Value(formula) ) );
    break;

    case 'A': /* abs */
      return ( abs ( Value(formula) ) );
    break;

    default:
	  formula->error = UNKNOWN;
      return(0);
    } /* end of switch */

  } /* end of routine */

GetFunction(infile, formula)
FILE *infile;
struct Formula_Master *formula;
	{
    char text[50], inchar;
	double a;
    int position, lasttype, function, constants, whichfunc;

	position = 0;
	function = 0;
	constants = 0;

	while ( (inchar = getc(infile) ) == ' ');
	lasttype = Type(inchar);
	for ever
      {
	  if ((lasttype == Type(inchar)) && (inchar != ' '))
	  	{
	  	text[position++] = inchar;
		}
	else
		{
		text[position] = 0;

		if (lasttype == ALPHA) 
			{
  			for (whichfunc = 0;
  			     strcmp(text, &functions[whichfunc][1]) ;
  			     whichfunc++)
    			{
    			if (!strcmp( functions[whichfunc], "end") )
      				{
      				return(FALSE);
      				}
    			}
  			formula->equation[function++] = functions[whichfunc][0];
			}

			if (lasttype == NUMERIC) 
				{
				formula->equation[function++] = (HIGHBIT | constants);
				sscanf(text, "%f", &a );
				formula->constants[constants++] =  a;
				}

			if (lasttype == OTHER) 
				{
				position = 0;
				while (text[position] !=0)
					{
					formula->equation[function++] = text[position++];
					}
				}

			if (inchar == ' ') while ( (inchar = getc(infile) ) == ' ');
			position = 0;
			text[position++] = inchar;
			lasttype = Type(inchar);
			}  /* end of else */

		if (lasttype == END) break;
		inchar = getc(infile);

  		}	  /* end of forever */

	formula->equation[function] = 0;
	if (function == 0)
		{
		FreeFunction(formula);
		return(FALSE);
		}
	return(TRUE);
	}		/* end of routine */

Type(character)
char character;
	{
	if(character >= 'a' && character <= 'z') return (ALPHA);
	if(character >= 'A' && character <= 'Z') return (ALPHA);
	if(character >= '0' && character <= '9') return (NUMERIC);
	if(character == '.') return (NUMERIC);
   	if(character == ';' || character == '\n' || character == '\r'
		|| character == EOF) return(END);
	return(OTHER);
	}

SetDefaults(parameters)
struct Graph_Parameters *parameters;
	{
	parameters->end = FALSE;

	parameters->xstart = -5.0;
	parameters->ystart = -5.0;
	parameters->zstart = -5.0;
	parameters->tstart = -5.0;

	parameters->xend = 5.0;
	parameters->yend = 5.0;
	parameters->zend = 5.0;
	parameters->tend = 5.0;

	parameters->xlabels = 1.0;
	parameters->ylabels = 1.0;
	parameters->zlabels = 1.0;

	parameters->detail = 1.0;
	}

GetVariables(Window, parameters, infile)
struct Window *Window;
struct Graph_Parameters *parameters;
FILE *infile;
	{
	char inchar, variable, command;
	double number;
	long int minx, miny, maxx, maxy;

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

	for ever
		{
		DrawRectangle(Window, 1l, minx, miny, maxx, miny+110);
		DisplayVariables(Window, parameters);
		variable = getc(infile);
		if (variable == '\r' || variable == '\n' || variable == 'e') break;
		if (variable != 'd' || variable != 'h' ) command = getc(infile);
		if (command == '=' || variable == 'h') command = '1';
		else while ( (inchar = getc(infile) ) != '=' );

		if (command < '0' || command > '9')
			{
			number = GetNum(infile);
			if (number != 0.0)
				{
				if(variable== 'd') parameters->detail = number;
				if(variable== 'h')
					parameters->hidden = (parameters->hidden) ? FALSE : TRUE;

				if(variable== 'x' && command== 's')parameters->xstart = number;
				if(variable== 'x' && command== 'e')parameters->xend = number;
				if(variable== 'x' && command== 'l')parameters->xlabels =number;

				if(variable== 'y' && command== 's')parameters->ystart = number;
				if(variable== 'y' && command== 'e')parameters->yend = number;
				if(variable== 'y' && command== 'l')parameters->ylabels =number;

				if(variable== 'z' && command== 's')parameters->zstart = number;
				if(variable== 'z' && command== 'e')parameters->zend = number;
				if(variable== 'z' && command== 'l')parameters->zlabels =number;

				if(variable== 't' && command== 's')parameters->tstart = number;
				if(variable== 't' && command== 'e')parameters->tend = number;
				} /* end of 0.0 else */
			}    /* end of if not equation */
		else	/* Its a formula */
			{
			if (variable == 'x')
				{
				if (!parameters->xon) parameters->x1 = AllocateFunction();
				if (parameters->x1 != NULL)
					{
					if (!GetFunction(infile, parameters->x1))
						{
						parameters->xon = FALSE;
						error(Window, FALSE);
						}
					else
						{
						parameters->xon = TRUE;
						parameters->x1->position=0;
						parameters->x1->error = FALSE;
						Solve(parameters->x1);
						if (parameters->x1->error != FALSE)
							error(Window, parameters->x1->error);
						}
					}
				}	/* end of x = */
			if (variable == 'y')
				{
				if (!parameters->yon) parameters->y1 = AllocateFunction();
				if (parameters->y1 != NULL)
					{
					if (!GetFunction(infile, parameters->y1))
						{
						parameters->yon = FALSE;
						error(Window, FALSE);
						}
					else
						{
						parameters->yon = TRUE;
						parameters->y1->position=0;
						parameters->y1->error = FALSE;
						Solve(parameters->y1);
						if (parameters->y1->error != FALSE)
							error(Window, parameters->y1->error);
						}
					}
				}	/* end of y = */
			if (variable == 'z')
				{
				if (!parameters->zon) parameters->z1 = AllocateFunction();
				if (parameters->z1 != NULL)
					{
					if (!GetFunction(infile, parameters->z1))
						{
						parameters->zon = FALSE;
						error(Window, FALSE);
						}
					else
						{
						parameters->zon = TRUE;
						parameters->z1->position=0;
						parameters->z1->error = FALSE;
						Solve(parameters->z1);
						if (parameters->z1->error != FALSE)
							error(Window, parameters->z1->error);
						}
					}
				}	/* end of z = */
			}  /* end of else */

		} /* end of for ever */
	}     /* end of command */

error(Window, error)
struct Window *Window;
int error;
	{
	long int minx, miny, maxx, maxy;

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

	DrawRectangle(Window, 3l, minx, miny+10, maxx, miny+115);
	SetAPen(Window->RPort, 1l);
	if (error == INVALID) Print(Window, "Invalid Function was entered", 13l);
	else if (error == UNKNOWN)
			Print(Window, "An unknown Function was entered", 13l);
	else if (error == FALSE)
			Print(Window, "An unknown Function was entered", 13l);
	}

double GetNum(infile)
FILE *infile;
	{
	char inchar, text[20];
	int position;
	double a;

	position = 0;
	inchar = getc(infile);
	while (Type(inchar) != END)
		{
    	text[position++] = inchar;
		inchar = getc(infile);
		}
	text[position] = 0;
	sscanf(text, "%f", &a );
	return(a);
	}

char *AllocateFunction()
	{
	struct Formula_Master *formula;

	formula = AllocMem( (long) sizeof(struct Formula_Master), 0);
	if (formula == NULL) return(0);

	formula->equation = AllocMem(sizeof(char) * FSIZE , 0);
	if (formula->equation == NULL) return(0);

	formula->constants = AllocMem(sizeof(double) * CONSTANTS , 0);
	if (formula->constants == NULL) return(0);

	return(formula);
	}

FreeFunction(formula)
struct Formula_Master *formula;
	{
	FreeMem(formula->equation, sizeof(char) * FSIZE);
	FreeMem(formula->constants, sizeof(double) * CONSTANTS);
	FreeMem(formula, sizeof (struct Formula_Master) );
	}

GetCommand(Window, parameters)
struct Window *Window;
struct Graph_Parameters *parameters;
	{
	FILE *infile;
	char list[80];

	infile = fopen("con:0/140/640/36/Enter Command", "r");
	if (infile == NULL)
		{
		parameters->error = WINDOW;
		return(0);
		}

	GetVariables(Window, parameters, infile);

	fclose(infile);
	}

LoadFile(Window, parameters)
struct Window *Window;
struct Graph_Parameters *parameters;
	{
	FILE *infile;
	char line[80], file[40];

	GetFileName(line);

	infile = fopen(line, "r");
	if (infile == NULL) return();

	GetVariables(Window, parameters, infile);
	fclose(infile);
	}

SaveFile(Window, parameters)
struct Window *Window;
struct Graph_Parameters *parameters;
	{
	FILE *outfile;
	char line[80], file[40];

	GetFileName(line);

	outfile = fopen(line, "w");
	if (outfile == NULL) return();

	fprintf(outfile, "xstart=%f\n", parameters->xstart);
	fprintf(outfile, "ystart=%f\n", parameters->ystart);
	fprintf(outfile, "zstart=%f\n", parameters->zstart);
	fprintf(outfile, "tstart=%f\n", parameters->tstart);
	fprintf(outfile, "xend=%f\n", parameters->xend);
	fprintf(outfile, "yend=%f\n", parameters->yend);
	fprintf(outfile, "zend=%f\n", parameters->zend);
	fprintf(outfile, "tend=%f\n", parameters->tend);
	fprintf(outfile, "xlabels=%f\n", parameters->xlabels);
	fprintf(outfile, "ylabels=%f\n", parameters->ylabels);
	fprintf(outfile, "zlabels=%f\n", parameters->zlabels);
	fprintf(outfile, "detail=%f\n", parameters->detail);

	if(parameters->xon)
		{
		Expand(parameters->x1, line);
		fprintf(outfile, "x1=%s\n", line);
		}
	if(parameters->yon)
		{
		Expand(parameters->y1, line);
		fprintf(outfile, "y1=%s\n", line);
		}
	if(parameters->zon)
		{
		Expand(parameters->z1, line);
		fprintf(outfile, "z1=%s\n", line);
		}

	fprintf(outfile,"e\n");

	fclose(outfile);
	}

GetFileName(line)
char line[];
	{
	FILE *infile;
	char inchar;
	int position;

	infile = fopen("con:0/140/640/24/Please Enter Filename:", "r");
	if (infile == NULL) return(0);

	position = 0;
	inchar = getc(infile);
	while ( Type(inchar) != END)
		{
		line[position++] = inchar;
		inchar = getc(infile);
		}

	line[position] = 0;
	fclose(infile);
	}

DisplayVariables(Window, parameters)
struct Window *Window;
struct Graph_Parameters *parameters;
	{
	char line[80], tmp[80];

	SetAPen(Window->RPort, 3l);
	SetBPen(Window->RPort, 0l);
	SetDrMd(Window->RPort, JAM2);
	Print(Window, "Current Variable Settings", 0);
	sprintf(line, "  start        end          labels       other       ");
	Print(Window, line, 1);
	sprintf(line,"x:%4.6f %4.6f %4.6f",parameters->xstart, parameters->xend,
										 parameters->xlabels);
	Print(Window, line, 2);
	sprintf(line, "y:%4.6f %4.6f %4.6f", parameters->ystart, parameters->yend,
										 parameters->ylabels);
	Print(Window, line, 3);
	sprintf(line, "z:%4.6f %4.6f %4.6f", parameters->zstart, parameters->zend,
										 parameters->zlabels);
	Print(Window, line, 4);
	sprintf(line, "t:%4.6f %4.6f  N/A", parameters->tstart, parameters->tend);
	Print(Window, line, 5);

	sprintf(line, "Detail is %4.6f", parameters->detail);
	Print(Window, line, 6);

	if(parameters->hidden) Print(Window, "Hidden lines is ON ", 7);
	else Print(Window, "Hidden lines is OFF", 7);

	if (parameters->xon)
		{
		Expand(parameters->x1, line);
		sprintf(tmp, "x=");
		strcat (tmp, line);
		strcat (tmp, "  ");
		Print(Window, tmp, 9);
		}
	if (parameters->yon)
		{
		Expand(parameters->y1, line);
		sprintf(tmp, "y=");
		strcat (tmp, line);
		strcat (tmp, "  ");
		Print(Window, tmp, 10);
		}
	if (parameters->zon)
		{
		Expand(parameters->z1, line);
		sprintf(tmp, "z=");
		strcat (tmp, line);
		strcat (tmp, "  ");
		Print(Window, tmp, 11);
		}
	}

Expand(formula, line)
struct Formula_Master *formula;
char line[];
	{
	int loop, position;
	char tmp[30];

	line[0]=0;

	for (position = 0; position < strlen(formula->equation); position++)
		{
		if ((formula->equation[position] & HIGHBIT) != 0)
			{
			sprintf(tmp, "%f",
				formula->constants[LOWMASK & formula->equation[position]]);
			strcat(line, tmp);
			}
		else
			{
			loop = 0;
			/* is this wrong ?	*/
			while (strcmp(functions[loop], "end") )
				{
				if (functions[loop][0] == formula->equation[position])
					strcat(line, &functions[loop][1]);
				loop++;
				}	/* end of while	*/
			}	/* end of else	*/
		}	/* end of for	*/
	}		/* end of the routine	*/
