/*
	grafmain.c		-	Bill Nickerson, 1988.

	This program allows calculations to be made or formulas to be
	graphed. To enter graphing mode,

		graf

	To enter calculator mode,

		graf calc

	Read "graf.doc" for further information.
*/

#include <stdio.h>
#include "main.h"
#include "mmenu.h"
#include "enter.h"

/*
	Imported functions and variables.
*/
extern int OpenLibs();
extern int InitGads();
extern int PickOption();
extern int GetFormula();
extern int PickFormula();
extern void DrawFormula();
extern void CloseLibs();
extern void FreeGads();
extern void parse();
extern double evaluate();
extern int initkw();

extern int iswrong, errno, fnvarused;

/* Formula and bounds (up, down, left, right) storage. */
Formula flist[MAXFORMULAS];
double bnds[4];

/*
	Perform initization. Make a button list for choosing formulas, open
	libraries, and set up data structures.
	Returns nothing.
*/
void Initialize( mode )
int mode;
{
	int i;

	if (mode == GRAF)
	{
		/*
			Allocate memory for buttons used to choose formulas.
			Stop if no memory is available.
		*/
		if (!InitGads())
		{
			puts("No room for gadgets.\n");
			exit(1);
		}
		if (!OpenLibs())
		{
			puts("Couldn't open libraries.\n");
			exit(1);
		}
		/*
			Initialize formula list to empty strings.
		*/
		for (i = 0; i < MAXFORMULAS; i++)
		{
			*(flist[i].form) = '\0';
			flist[i].selected = 0;
		}
		bnds[0] = bnds[3] = 10.0;
		bnds[1] = bnds[2] = -10.0;
	}
	if (!initkw())
	{
		puts("Couldn't initialize keyword table.\n");
		if (mode == GRAF)
			CloseLibs();
		exit(1);
	}
}

/*
	Perform system cleanup. Deallocate button list memory and close
	libraries.
	Returns nothing.
*/
void CleanUp()
{
	FreeGads();
	CloseLibs();
}

/*
	Select formulas and perform graphing.
	Returns nothing.
*/
void Graph()
{
	int i;

	for (i = 0; i < MAXFORMULAS; i++)
		flist[i].selected &= ~FSELECT;
	if (PickFormula(GIMMESOME) < 0)
		return;
	DrawFormula(flist, bnds, 0.0);
}

/*
	Enter formula and/or bounds for graphing.
	Returns nothing.
*/
void Enter()
{
	int choice;

	choice = PickFormula(GIMMEONE);
	GetFormula(&flist[choice], bnds);
}

/*
	Enter calculator mode and instantly evaluate any formula entered
	from standard input.
	Returns nothing.
*/
void Calculate()
{
	int line = 1;
	char buf[160];
	double pcode[160], fnvar, reslt;

	Initialize(CALC);
	puts("\ngrafCalc v1.0 - (c) Bill Nickerson, 1988\n");
	for (; printf("[%d] ", line), (fgets(buf, 159, stdin) != NULL); line++)
	{
		parse(buf, pcode);
		if (iswrong)
			printf("Line %d is wrong.\n", line);
		else
		{
			do
			{
				if (fnvarused)
				{
					fprintf(stdout, "Evaluate at?\n");
					while (scanf("%lf", &fnvar) != 1)
					{
						while(getchar() != '\n')
							;
						fprintf(stdout, "Uh, uh.\n");
					}
					/*
						Ingest the trailing char.
					*/
					if (getchar() != '\n')
					{
						fnvarused = 0;
						while (getchar() != '\n')
							;
					}
				}
				else	fnvar = 0.0;

				reslt = evaluate(pcode, fnvar);
				if (errno == 0)
					printf("== %lf\n", reslt);
				else	printf("Math error on line %d.\n", line);
			}
			while (fnvarused);
		}
	}
	exit(0);
}

/*
	Initialize data and control selections.
*/
void main( argc, argv )
int argc;
char *argv[];
{
	if ((argc > 2) || ((argc == 2) && (strcmp(argv[1], "calc") != 0)))
	{
		printf("usage: %s [calc]\n", *argv);
		exit(1);
	}

	if (argc == 2)
		Calculate();

	Initialize(GRAF);
	while (1)
	{
		switch (PickOption())
		{
		case GBID:
			Graph();
			break;
		case EBID:
			Enter();
			break;
		case QBID:
			CleanUp();
			exit(0);
			break;
		default:
			break;
		}
	}
}
