// ***************** COPYRIGHT (c) 2008 STEFAN WANER ******************
// *********************** ALL RIGHTS RESERVED ************************



// ***  IT ALSO REMAINS TO DO THE TOPMATTER


// Globals
// window.onerror = myErrorTrap;
var windowcropTally = 20; 
	// will not cut a window in half if more than this number of 
     // pixels pop out of range as a result



var autoY = true;
var autoGridline = true;

var okToRoll = true;

var theString = "";

var theFunction = ""; // the function


var xGridLines = new Array(); // these are screen coordinates
var yGridLines = new Array();
var xGridLinesActual = new Array(); // these are actual coordinates
var yGridLinesActual = new Array();

// var lineColor = 2; // red
// var lineColorLite = lineColor + 7;

var tminVals = new Array(); 
var tmaxVals = new Array();

var arraysize = 0; // number of functions
var xArraysize = 0; // number of x-values in evalautor
var maxnum = 5;  // max number of functions allowed
var maxnumX = 12; // max number of x-values allowed
var theValues = new makeArray2(maxnumX, maxnum); // copy of evalauator data

var fracMode = false; // fraction mode off default
var numSigDigs = 5;  // rounding of y-values default
var maxDenom = 99999;

// *** end globals


// *** Error Handler ******
function myErrorTrap(message,url,linenumber) {
alert("It looks like you have entered something wrongly (or perhaps need to use an older version). Press 'Show Examples' to see examples of how to format functions.");
return (true);
} // end of on error

// ********************

// **********Utilities to read in the functions *********
// ********************************************************************
function setUp(){

	okToRoll = true;
	with(Math){
		//Step 1: read the inputs into an array and decide
		// how many points there are
		var thexCellName = ""; // these are strings to names x1, x2,.. 

		var theInstruction = ""; // a javascript instuction
		var doIt = 0; // a dummy variable
				
		//Step 2: Fill the y arrays with the functions 
		for (var i = 1; i <= maxnum; i++) { 





			theInstruction = "yVals["+i+"] = stripSpaces(document.theFormA.y"+i+".value);";
			doIt = eval(theInstruction);
			// now take special steps for derivatives
			if ((yVals[i]).substring(0,5) == "deriv") {
				var theLength = (yVals[i]).length;
				var theDerivArg = (yVals[i]).substring(6,theLength-1);
				if (theDerivArg.charAt(0) == "y") {
					var theIndex = parseInt(theDerivArg.charAt(1));
					if (theIndex < i) yVals[i] = stringDeriv(yVals[theIndex]);
					} // is a "yi"
				else yVals[i] = stringDeriv((yVals[i]).substring(6,theLength-1));
// alert(yVals[i]);
				} // if a derivative

	
			
// alert(yVals[i]);
// alert(i);
			} // i
		// Step 3: Compute how many functions there are
		arraysize = maxnum;
// alert(arraysize);
		for (i = 1; i <= maxnum; i++) {
			if (yVals[i] == "") {
// alert(i);
				arraysize = i-1;
				i = maxnum}
			} // i


	} //with math
// Step 4: Read in textarea points
readInTextarea();
if ((arraysize == 0)&&(!plottingPoints)) {alert("You must enter at least one function or one point to plot"); okToRoll = false}
} // setup

// ***********************************************************************
// ************** End of Reading-in Parametric Equations Utility ******
// ***********************************************************************


// ***********************************************************************
// ************** Evaluator Setup Routine ******
// ***********************************************************************
function setUp2() {
	okToRoll = true;
	var aaa = setUp(); // read in the functions
	fracMode = document.theFormC.fracModeButton.checked;
	if(!fracMode) {
		numSigDigs = document.theFormC.acc.value;
		if (isBad(numSigDigs)) {alert("the Number of Significant Digits must be a number. I am setting it back to 5. Change it to another number if you like."); okToRoll = false}
	} // if not fraction mode
	// Now read in the x-values
	with(Math){
		//Step 1: read the inputs into an array and decide
		// how many points there are
		var thexCellName = ""; // these are strings to names x1, x2,.. 

		var theInstruction = ""; // a javascript instuction
		var doIt = 0; // a dummy variable
				
		//Step 2: Fill the x array with the x-values
		// Note: at this point theywill all be strings 
		for (var i = 1; i <= maxnumX; i++) {
			theInstruction = "xVals["+i+"] = stripSpaces(document.theFormC.x"+i+".value);"
			doIt = eval(theInstruction);
			} // i
		// Step 3: Compute how many functions there are
		for (i = 1; i <= maxnumX; i++) {
			if (xVals[i] == "") {
				xArraysize = i-1;
				break
				} // encountered blank
			} // i
		if (xArraysize == 0) {alert("You must enter at least one value of x"); okToRoll = false}
// alert(xArraysize);
	} //with Math
} // end of function setUp2
// ***********************************************************************
// ************** End of Evaluator Setup Routine ******
// ***********************************************************************


// ***********************************************************************
// ************** Evaluate all Routine ******
// ***********************************************************************

function evaluateAll() {
// This evaluates all the functions in nthe table
// we have arraysize many functions and xArraysize many values of x 

var theStrg = ""; // a dummy string for parsed functions
var theInstruction = ""; // a javascript instuction
var doIt = 0; // a dummy action

// First clear the current y-values
for (var i = 1; i <= maxnum; i++) {
	for (var j = 1; j <= maxnumX; j++) {
		theInstruction = "document.theFormC.y"+i+"x"+j+".value = ''";
		doIt = eval(theInstruction)
		} // j
	} // i

// Now Compute the values
 
for (var j = 1; j <= arraysize; j++) {
	theStrg = myParse(yVals[j]);
	for (var i = 1; i <= xArraysize; i++) {
		x = myEval(xVals[i]); // in case there are inputs like "sin(3)"
		y = checkEval(theStrg);
		if (y > infinity) y = "infinity";
		else if (y < -infinity) y = "-infinity";
		if (!fracMode) theInstruction = "document.theFormC.y"+j+"x"+i+".value = roundSigDig(y,numSigDigs)";
		else theInstruction = "document.theFormC.y"+j+"x"+i+".value = toFrac(y, maxDenom)";
		doIt = eval(theInstruction);
// alert(theInstruction);
		} // end i
	} // end j
} // end of evaluateAll

// ***********************************************************************
// ************** End of Evaluate all Routine ******
// ***********************************************************************

// **************** Plot All Curves ********************

function readAndPlotCurves(theGraph){
// alert(a + " , " + b + " , " + c + " , " + d);
var theyString = "";
var thexMin = 0;
var thexMax = 0;
var colorNumber = 0; 
var theGraphArray = new(Array);
// alert(arraysize);
for (var i = 1; i <= arraysize; i++) {

	theyString = yVals[i];

	theGraphArray [i-1] = [theyString, theGraph.window[0], theGraph.window[1]];
	} // i
theGraph.plottedCurves = theGraphArray;
// alert(theGraphArray);

setUpGraph(theGraph);
// alert(myGraph.yGridStep);
plotAllCurves(theGraph);
// alert("here");

// now the plotted points
var pointsX = new(Array);
var pointsY = new(Array);
pointsX[0] = 0; pointsY[0] = 0;
for (var i = 1; i <= numPoints; i++) {
	pointsX[i] = thePlottedPoints[i][1];
	pointsY[i] = thePlottedPoints[i][2]
	} // i points
theGraph.plottedPointsX = pointsX;
theGraph.plottedPointsY = pointsY;
plotPoints(theGraph, "x", false, "")
} // end of plot

// ******************End of Plot All Curves ***********







// ************** GRAPH in EXCANVAS *************



function refreshGraph()  {
// nothing here
} // End of refreshGraph



// ************** DISPLAY GRAPH *************
// For old browsers
function displayTheGraph()  {
// puts up the graph in the appropriate window, and extra things as needed

	// *** Open a window
	var tb="toolbar=0,directories=0,status=0,menubar=0"
	tb+=",scrollbars=1,resizable=1,"
	var tbend="width=350,height=300"
	tb+=tbend
	Win_1 = window.open("","win1",tb);
	Win_1.document.open();
	// ** Window is opened

var theString  = '<html><title>Your Graph</title><body bgcolor = "FFFFFF"><p><center><table><tr>'
theString += '<td></td><td align = center>' + roundSigDig(d,4) + '</td></tr><tr><td valign = center>'+ roundSigDig(a,4)+'</td><td>';

theString += '<table border = 1><tr><td>';
theString += formatGraph2();			// the actual graph
theString += '</td></tr></table>';
theString += '</td><td valign = center>' + roundSigDig(b,4) + '</td></tr><tr><td><td align = center>' + roundSigDig(c,4) + '</td></tr></table></center></body></html>';
Win_1.document.write(theString);
Win_1.document.close();
Win_1.focus();

} // displayTheGraph
// ********** END DISPLAY GRAPH *************


// ************** FORMAT GRAPH *************
// Requires the following global variables:
// 1. theCanvas = the matrix of pixels -- entries are the colors 0-numCols
// 2. numX, numY, the dimensions of the canvas
// 3. theDot: an array of pixel images (gif) -- little swaths of color
// Returns the html for the actual graph

function formatGraph2() {
var theString = "";
var repeats = new Array(); // this contains a list of different rows in theCanvas
var theRow1 = new makeArray(numY);
repeats[1] = 1; // first row
var numRepeats = 1; 
var oldVal = 0;
var newVal = 0;
var theLength = 0;
var theHeight = 0;
for (var k = 1; k <= numY; k++) theRow1[k] = theCanvas[k][1];

for (var i = 1; i <= numY; i++)
	{
// if (i == 100) alert('Here i = ' + i);
	for (var j = i+1; j <= numY; j++)
		{
// if (j == 100) alert('Here j = ' + j);
		for (var k = 1; k <= numX; k++)
			{
// if (k == 100) alert('Here k = ' + k);
			if (theRow1[k] != theCanvas[k][j])
				{
				numRepeats++;
				repeats[numRepeats] = j;
				for (var p = 1; p <= numY; p++) theRow1[p] = theCanvas[p][j]; 
				i = j-1;
				k = numX;
				j = numY;
				} // if
			} // k
		} // j

	} // i
repeats[numRepeats+1] = numY+1; // for last line height
// var theTestString = '';
// for (var i = 1; i <= numRepeats; i++) theTestString += "," + repeats[i];
// document.theForm.output.value += theTestString;
// alert("here. numRepeats = " + numRepeats );
var theRow = 1;
for (var i = 1; i <= numRepeats; i++)
	{ 
	theLength = 1;
	theRow = repeats[i];
	theHeight = repeats[i+1] - repeats[i];
	oldVal = theCanvas[1][theRow];
	for (var j = 2; j <= numX; j++)
		{
		 if ((j == numX)  && ( theCanvas[j][theRow] != oldVal) )
			{
			var LL = theLength-1;
			theString += '<img src = "' + theDot[oldVal].src + '" width = ' + LL + ' height = ' + theHeight + '>'
			theString += '<img src = "' + theDot[theCanvas[j][theRow]].src + '" width = 1 height = ' + theHeight + '>'
			
			} // change on last pixel

		else if(( theCanvas[j][theRow] != oldVal) || (j == numX))
			{
			// saw a change
// alert(i);
// alert(j);
			// make a string of the right length
			theString += '<img src = "' + theDot[oldVal].src + '" width = ' + theLength + ' height = ' + theHeight + '>'
			oldVal = theCanvas[j][theRow];
			theLength = 0;
			} 
		theLength++;
		} // j
	theString += '<br>';
	} // i

return(theString);
} // formatGraph
// ********** END FORMAT GRAPH *************



// ************** SEGMENT *************
// creates a clipped segment in the window
// note that the segment is automatically clipped by excanvas 
// so there is no work for us here
function segment(x1,y1,x2,y2, col) {
// do some clipping for Windoze
var xMin = a;
var xMax = b;
var yMin = c;
var yMax = d;
var noGo = false;
if ((y1 > yMax) && (y2 > yMax)) noGo = true;
else if ((y1 < yMin) && (y2 < yMin)) noGo = true;
if (!noGo) {
	if (col == "magenta") {colr = 200; colg = 0; colb = 100}
	else if (col == "yellow")  {colr = 200; colg = 200; colb = 0}
	else if (col == "black")  {colr = 0; colg = 0; colb = 0}
	else if (col == "blue")  {colr = 0; colg = 0; colb = 255}
	else if (col == "red")  {colr = 255; colg = 0; colb = 0}
	else if (col == "green")  {colr = 0; colg = 255; colb = 0}
	else if (col == "aqua")  {colr = 0; colg = 200; colb = 200}
	else if (col == "purple")  {colr = 200; colg = 0; colb = 250}
	else if (col == "grey")  {colr = 100; colg = 100; colb = 100}
	else if (col == "pink")  {colr = 125; colg = 0; colb = 0}
	else if (col == "orange")  {colr = 255; colg = 125; colb = 0}
	else {colr = 0; colg = 0; colb = 0} // black default

 
// alert(a + " , " + b + " , " + c + " , " + d);
	var x1bar = Math.round(canvasWidth*(x1-xMin)/(xMax-xMin) );
	var x2bar = Math.round(canvasWidth*(x2-xMin)/(xMax-xMin) );
	var y1bar = Math.round(canvasHeight*(yMax-y1)/(yMax-yMin) );
	var y2bar = Math.round(canvasHeight*(yMax-y2)/(yMax-yMin) );
	var style = ["rgb(",colr, ",", colg, ",", colb, ")"].join("");
	ctx.strokeStyle = style;

	ctx.beginPath();
	ctx.moveTo(x1bar, y1bar);
	ctx.lineTo(x2bar, y2bar);
	ctx.stroke();
	ctx.closePath();
	}// if not noGo

} // segment



// **************** DRAWCURVE ******************************
// *** Draws a graph of a given funtion

function drawCurve(theyString, thexMin, thexMax, theCurveColor) {
// alert(a + " , " + b + " , " + c + " , " + d);
// alert("at DrawCurve; theyString = " + theyString + " thexMin = "+ thexMin + " thexMax = "+ thexMax + " theCurveColor = " + theCurveColor);
// Draws curve using function segment(x1,y1,x2,y2, theCurveColor) repeatedly
// a and b are Xmin and Xmax respectively
okToRoll = true;
var theStrg = myParse(theyString);
if (thexMax <= thexMin) {alert("Xmin must be less than Xmax. Correct this and try again."); okToRoll = false}
if (okToRoll) {
			// Search for a place to start the graph 
			// (in case initial y-coords are undefined or infinite.) 
			var deltax = (thexMax - thexMin)/numDivisions;
// alert(deltax);
// deltax = .25; // testing
			x1 = thexMin;
			x = x1;
			y1 = checkEval(theStrg);
// alert(y1);
// alert("x1 = " + x1 + "y1 = "+ y1 + (y1 > infinity));
			if ((isNaN(y1)) || (y1 == Infinity) || (y1 == -Infinity)) {
// alert("**HERE**")
				for (var k = thexMin; k <= thexMax; k+=deltax) {
					x = k;
					x1 = k;
					y1 = checkEval(theStrg);
					if(!isBad(y1)) break;
					} // end count
// alert(x1);
				if (k >= thexMax) {alert("Y is not defined for your given X-range."); okToRoll = false}
				if (y1 > infinity) y1 = infinity;
				else if (y1 < -infinity) y1 = -infinity;
				} // y1 is not a number
			

			} // if OKtoRoll

if (okToRoll) {
		// now plot the points

// alert(x);	

		var thecount = 0; /// testing
		var startingX = x + deltax;
		for (var k = startingX; k <= thexMax; k+=deltax) {
			thecount++;
// if (thecount == 35) alert("thcount = " + thecount + "k = "+k);
// if (thecount == 41) alert("thcount = " + thecount + "k = "+k);
			x2 = k;
			x = x2;
			y2 = checkEval(theStrg);
			if (!isBad(y2)) {
				if (y2 > infinity) y2 = infinity;
				else if (y2 < -infinity) y2 = -infinity; 
// alert(x1 + "," + y1 + "," + x2 + "," + y2);
				var p = segment(x1,y1,x2,y2,theCurveColor);
				x1 = x2;
				y1 = y2;
				} // If second point is defined
			else {
				for (var p = x2+deltax; p <= thexMax; p+=deltax) {
					x = p;
					y1 = checkEval(theStrg);
					if(!isBad(y1)) break;
					} // end count
				k = p; // reset k further along the loop
				x1 = p;  // y1 is already what it is supposed to be
				} // second point was undefined
				
			
if(thecount >= numDivisions + 2) k = thexMax+1;
			} // k
// alert("k over");
	} // if okToRoll
} // function drawCurve


// ************** various miscellaneous routines *************

function rememberValues() {
if (document.theFormC.y1x1.value != "") {
	var theInstruction = ""; // a javascript instuction
	var doIt = 0; // a dummy variable
	for (var i = 1; i <= maxnumX; i++) {
		for (var j = 0; j <= maxnum; j++) {
		if (j > 0) theInstruction = " theValues[i][j] = document.theFormC.y"+j+"x"+i+".value";
		else theInstruction = " theValues[i][j] = document.theFormC.x"+i+".value";
		doIt = eval(theInstruction);
		} // j
	} // i
} // IF THERE IS SOMETHING IN THE FIRST CELL
} // remember values

function bringBackValues() {
	if (document.theFormC.y1x1.value == "") {
		var theInstruction = ""; // a javascript instuction
		var doIt = 0; // a dummy variable
		for (var i = 1; i <= maxnumX; i++) {
			for (var j = 0; j <= maxnum; j++) {
			if (j > 0) theInstruction = " document.theFormC.y"+j+"x"+i+".value = theValues[i][j]";
			else theInstruction = " document.theFormC.x"+i+".value = theValues[i][j]";
			doIt = eval(theInstruction);
			} // j
		} // i
	} // if there is nothing in the first cell
} // remember values


// ********* Added Routines and globals for Plotting Points
var plottingPoints = false;
var tab = unescape( "%09" );	
var cr = unescape( "%0D" );	
var lf = unescape( "%0A" );
var semicolon = unescape( '%3B' );
var comma = ",";
var textareaText = '';
var maxNumPoints = 100; 
var numPoints = 0;
var thePlottedPoints = new makeArray2(maxNumPoints,2);
var yMaxPoints = 0;
var yMinPoints = 0;
var xHeight = 5; // height of the plotted Xs

function rememberValuesPoints() {
if (stripSpaces(document.theFormP.thePoints.value) != '')
textareaText = document.theFormP.thePoints.value;
} // remember values

function restoreValuesPoints() {
if (stripSpaces(document.theFormP.thePoints.value) == '')
document.theFormP.thePoints.value = textareaText;
} // restore values

function readInTextarea() {
// reads in points and calculates maximum and minimum y coords 
var theString = document.theFormP.thePoints.value;
theString = stripSpaces(theString);
theString = replaceChar(theString,comma,tab);
theString = replaceChar(theString,semicolon,cr);
theString = replaceChar(theString,lf,cr);
// now get rid of strings of more than one tab and one cr's in a row
var doubletab = true; var doublecr = true;
while ( (doubletab) || (doublecr) )
	{
	if (checkString(theString,tab+tab,false) == -1) doubletab = false;
	else theString = replaceSubstring(theString,tab+tab,tab);
	if (checkString(theString,cr+cr,false) == -1) doublecr = false;
	else theString = replaceSubstring(theString,cr+cr,cr);
	} // while
theString = replaceSubstring(theString,tab+cr,cr); // get rid of tab + crs
var xyPoints = parser(theString,cr);
var thePoint = new Array;
numPoints = xyPoints[0];
if (theString.indexOf(tab) == -1) numPoints = 0;
if (numPoints > 0) {
	plottingPoints = true;
	for (var i = 1; i <= numPoints; i++) {
		thePoint = parser(xyPoints[i], tab);
		thePlottedPoints[i][1] = parseFloat(thePoint[1]);
		thePlottedPoints[i][2] = parseFloat(thePoint[2]);
		} // i

	// now compute y max and min for these
	yMaxPoints = thePlottedPoints[1][2];
	yMinPoints = yMaxPoints;
	for (var i = 1; i <= numPoints; i++) {
		try
			{
 			if (thePlottedPoints[i][2] > yMaxPoints) yMaxPoints = thePlottedPoints[i][2];
			else if (thePlottedPoints[i][2] < yMinPoints) yMinPoints = thePlottedPoints[i][2];
			}
			catch (error)
			{ 
			}
		} // i
//	alert("numPOints = " + numPoints + "  ; yMax = " + yMaxPoints + "  ; yMin = "+ yMinPoints);
	// now scale up a bit so that not on the edge
	yMinPoints -= .1*Math.abs(yMinPoints);
	yMaxPoints += .1*Math.abs(yMaxPoints);

	} // if more than 0 points
else plottingPoints = false;
} // readInTextarea

function PutX(x1,y1, col) {
var xMin = a;
var xMax = b;
var yMin = c;
var yMax = d;
if (col == "magenta") {colr = 200; colg = 0; colb = 100}
else if (col == "yellow")  {colr = 200; colg = 200; colb = 0}
else if (col == "black")  {colr = 0; colg = 0; colb = 0}
else if (col == "blue")  {colr = 0; colg = 0; colb = 255}
else if (col == "red")  {colr = 255; colg = 0; colb = 0}
else if (col == "green")  {colr = 0; colg = 255; colb = 0}
else if (col == "aqua")  {colr = 0; colg = 200; colb = 200}
else if (col == "purple")  {colr = 200; colg = 0; colb = 250}
else if (col == "grey")  {colr = 100; colg = 100; colb = 100}
else if (col == "pink")  {colr = 125; colg = 0; colb = 0}
else if (col == "orange")  {colr = 255; colg = 125; colb = 0}
else {colr = 0; colg = 0; colb = 0} // black default
var x1bar = Math.round(canvasWidth*(x1-xMin)/(xMax-xMin) );
var y1bar = Math.round(canvasHeight*(yMax-y1)/(yMax-yMin) );
// alert(xMin);
var style = ["rgb(",colr, ",", colg, ",", colb, ")"].join("");
ctx.strokeStyle = style;
ctx.beginPath();

ctx.moveTo(x1bar-xHeight, y1bar-xHeight);
ctx.lineTo(x1bar+xHeight, y1bar+xHeight);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.moveTo(x1bar+xHeight, y1bar-xHeight);
ctx.lineTo(x1bar-xHeight, y1bar+xHeight);
ctx.stroke();
ctx.closePath();

} // putX

// detecting mouse coordinatges on the canvas



function getElementPosition(elemID){
var offsetTrail = document.getElementById(elemID);
var offsetLeft = 0;
var offsetTop = 0;
while (offsetTrail){
offsetLeft += offsetTrail.offsetLeft;
offsetTop += offsetTrail.offsetTop;
offsetTrail = offsetTrail.offsetParent;
}
if (navigator.userAgent.indexOf('Mac') != -1 && typeof document.body.leftMargin != 'undefined'){
offsetLeft += document.body.leftMargin;
offsetTop += document.body.topMargin;
}
return {left:offsetLeft,top:offsetTop};
}


function alertCoord(e) {
if(basicsRead) {
	var canvPos = getElementPosition('cv');
	var xActual = "", yActual = "";
	  if( !e ) {
	    if( window.event ) {
	      //Internet Explorer
	      e = window.event;
	    } else {
	      //total failure, we have no way of referencing the event
	      return;
	    }
	  }
	  if( typeof( e.pageX ) == 'number' ) {
	    //most browsers
	    var xcoord = e.pageX;
	    var ycoord = e.pageY;
	  } else if( typeof( e.clientX ) == 'number' ) {
	    //Internet Explorer and older browsers
	    //other browsers provide this, but follow the pageX/Y branch
	    var xcoord = e.clientX;
	    var ycoord = e.clientY;
	    var badOldBrowser = ( window.navigator.userAgent.indexOf( 'Opera' ) + 1 ) ||
	     ( window.ScriptEngine && ScriptEngine().indexOf( 'InScript' ) + 1 ) ||
	     ( navigator.vendor == 'KDE' );
	    if( !badOldBrowser ) {
	      if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
	        //IE 4, 5 & 6 (in non-standards compliant mode)
	        xcoord += document.body.scrollLeft;
	        ycoord += document.body.scrollTop;
	      } else if( document.documentElement && ( document.documentElement.scrollLeft 	|| document.documentElement.scrollTop ) ) {
	        //IE 6 (in standards compliant mode)
	        xcoord += document.documentElement.scrollLeft;
	        ycoord += document.documentElement.scrollTop;
	      }
	    }
	  } else {
	    //total failure, we have no way of obtaining the mouse coordinates
	    return;
	  }
	xcoord -= canvPos.left;
	ycoord -= canvPos.top;
	// window.alert('Mouse coordinates are ('+xcoord+','+ycoord+')');
	// now get actual coordinates
	xActual = roundSigDig(a + xcoord*(b-a)/canvasWidth,4);
	yActual = roundSigDig((canvasWidth-ycoord)*(d-c)/canvasWidth + c, 4);
	document.getElementById("traceCoords").innerHTML =  '('+ xActual +', '+ yActual +')'
	} // if basicsRead
} // alertCoord

var basicsRead = false;
function readBasics(theGraph) {
// alert("here");
var theStrg = "";  // dummy string for evaluating functions
autoY = document.theFormB.autoYButton.checked;
autoGridline = document.theFormB.autoGridButton.checked;
// get the graph window information
	for (var k = 1; k <= 1; k++)
	{
	var aa = document.theFormB.a.value; 
// alert(aa);
	if (aa == "") { alert("You have not entered a number for xMin."); okToRoll = false; break;}
//alert(aa);
	a = myEval(aa);
	if (isNaN(a) ) { alert("You have not entered a number for xMin."); okToRoll = false; break;}
	var bb = document.theFormB.b.value; 
	if (bb == "") { alert("You have not entered a number for xMax."); okToRoll = false; break}
	b = myEval(bb); 
	if (isNaN(b) ) { alert("You have not entered a number for xMax."); okToRoll = false; break;}
	if ( (okToRoll) && (a >= b)) { alert("xMax should be greater than xMin"); okToRoll = false; break;}
	var ppcTest = document.theFormB.ppc.value;
	if (isNaN(ppcTest) || (ppcTest == '') ) document.theFormB.ppc.value = 1000;
	else myGraph.pointsPerCurve = parseInt(ppcTest);

	if(!autoY) {
// alert("Here autoY is off");
		var cc = document.theFormB.c.value; 
		if (cc == "") { alert("Enter a number for yMin or check 'Auto'."); okToRoll = false; break}
		c = myEval(cc); 
		if (isNaN(c) ) { alert("Enter a number for yMin or check 'Auto'."); okToRoll = false; break;}
		var dd = document.theFormB.d.value; 
		if (dd == "") { alert("Enter a number for yMax or check 'Auto'."); okToRoll = false; break}
		d = myEval(dd); 
		if (isNaN(d) ) { alert("Enter a number for yMax or check 'Auto'."); okToRoll = false; break;}
		if ( (okToRoll) && (c >= d)) { alert("yMax should be greater than yMin"); okToRoll = false; break;}
// alert(a + " , " + b + " , " + c + " , " + d);
		} // end of if autoY
	else {
		document.theFormB.c.value = ''; // cannnot have it both ways
		document.theFormB.d.value = ''; 
		// Must compute ymin and ymax here
		var deltax = (b-a)/theGraph.numX;
// alert(deltax);
		var maxy = 0;
		var miny = 0;
		var firstCheck = true;
		for (var j = 1; j <= arraysize; j++) {
			theStrg = myParse(yVals[j]);
			for (var i = 0; i <= theGraph.numX; i++)
				{
				x = a + i*deltax;
// alert("x = " + x);
				y  = checkEval(theStrg);
				if (!isNaN(y) &&( y < infinity) && (y > -infinity))
					{
					// alert ("y = " + y);
					if (firstCheck) 
						{
						firstCheck = false; 
						maxy = y; 
						miny = y
						}
					if (y > maxy) maxy = y;
					else if (y < miny) miny = y;
					} // end of if y is a legit number
				} // i
// alert(miny);
			} // j
	
// alert("miny = "+miny + "maxy =" + maxy);
			// Now cut down the size of the window if necessary
			// in the case of graphs shooting off to infinity
			// the teqnique is to eliminate "outliers" by cropping 
			// the window.


// *** Why don't we just compute the st deviation and crop to +- 3s
			var cutting_down = true;
			var invisible_tally = 0;
			var maxSteps = 10, steppes = 0;
			while ((cutting_down) && (steppes < maxSteps))
				{
				steppes ++;
				maxy = maxy/2;
				miny = miny/2;
				invisible_tally = 0;
				for (var j = 1; j <= arraysize; j++) {
					theStrg = myParse(yVals[j]);

					for (var i = 0; i <= theGraph.numX; i++)
						{
						x = a + i*deltax;
						y  = checkEval(theStrg);
						if (!isNaN(y) &&( y < infinity) && (y > -infinity))
							{
							if ((y > maxy) || (y < miny))
								{
								invisible_tally++;
								if (invisible_tally > windowcropTally)
									{
									cutting_down = false;
									maxy = 2*maxy;
									miny = 2*miny;
									i = theGraph.numX;
									break;
									} // too many invisible;
								} // if y > ymax
						} // if is a number
					} // i
				} // j
			// by the end of this cutting_down had better be false;
			} // while cutting_down
// alert("miny = "+miny + "maxy =" + maxy);

		
		if (miny == maxy) {miny  = miny-1; maxy += 1}

		// ** following two lines added for plotting points
		if (plottingPoints) {
			if (yMaxPoints > maxy) maxy = yMaxPoints;
			if (yMinPoints < miny) miny = yMinPoints;
			}
		var scalefactor = 150/(maxy - miny); 
// ************
// end of y min and ymax window coords
// ************

		c = eval(roundSigDigUpDown (miny,4, false)); // sets the globals
		d = eval(roundSigDigUpDown (maxy,4, true));
		} // end of else for autoY
// alert("c = " + c + " d = " + d);
// At this point we have the globals a, b, c, d we need
	myGraph.window[0] = a;
	myGraph.window[1] = b;
	myGraph.window[2] = c;
	myGraph.window[3] = d;
	theGraph.xTicsRange = [];
	theGraph.yTicsRange = [];
	if(!autoGridline) {
		var xk = document.theFormB.xg.value;
		if (xk == "") myGraph.xGridStep = 0;
		else myGraph.xGridStep = eval(xk);
		var yk = document.theFormB.yg.value;
		if (yk == "") myGraph.yGridStep = 0;
		else myGraph.yGridStep = eval(yk);
		} // end of if not autoGridline
	else {
		document.theFormB.xg.value = ''; 
		document.theFormB.yg.value = ''; // cannnot have it both ways.
		var pq = (b-a)/10;
		myGraph.xGridStep = pq;
		pq = pq = (d-c)/10;
		myGraph.yGridStep = pq;
		} // end of else for autoGridline
	} // end of single loop (k)
if (okToRoll) basicsRead = true;
//alert(myGraph.yGridStep);
} // readBasics


function makeArray2 (X,Y)
	{
	var count;
	this.length = X+1;
	for (var count = 1; count <= X+1; count++)
		// to allow starting at 1
		this[count] = new makeArray(Y);
	} // makeArray2

function makeArray (Y)
	{
	var count;
	this.length = Y+1;
	for (var count = 1; count <= Y+1; count++)
		this[count] = 0;
	} // makeArray

// ************* miscellaneous fixes
// this cleans up the lower boundary in case of curves tha overshoot

function cleanUp(theGraph) {
with(theGraph) {
	if (surroundColor == "white") ctx.fillStyle =  "rgb(255, 255, 255)";
	else ctx.fillStyle =  "rgb(" + surroundColor [0] + "," + surroundColor [1] + "," + surroundColor [2] + ")";
// alert(" " + theGraph.yLabelMargin + ", " + (theGraph.numY-1) + ", " + theGraph.numX+ theGraph.yLabelMargin+ ", " + 10);

ctx.fillRect(theGraph.yLabelMargin, theGraph.numY-1, theGraph.numX+ theGraph.yLabelMargin, 10);
	} // with theGraph

} // cleanUp
