

/* ******************************************************* */
/* Calculus Functions */
/* ******************************************************* */
function ndfdx(funct, x) {

	var h = x + 0.001;
	var top = compute(funct, h) - compute(funct, x);
	var bottom = h-x;

	//writeOutput(x+", "+Math.floor((top/bottom)*1000)/1000);
	return Math.round((top/bottom)*1000)/1000;

}

/* ******************************************************* */
function n2dfdx(funct, x) {

	var h = x + 0.001;
	var h2 = x + 0.002;
	var top = (compute(funct, h2) - compute(funct, h) - 
			compute(funct, h) + compute(funct, x));
	var bottom = (h-x)*(h-x);
	
	return Math.round((top/bottom)*1000)/1000;
}

/* ******************************************************* */
function simpsonsRule(funct, a, b) {

	/* ***************************************************
	 This function estimates the numerical integral of
	 a function on the interval [a,b] using Simpson's
	 Rule.
	*************************************************** */

	var n = 100.0;
	var total = 0;
	var h = Math.Abs(b-a)/n;

	var l = new Array(120);
	
	var x = a;
	l[0] = compute(funct, x);

	var count = 1;
	while (count < n) {
		x = a + count * h;
		
		if (count%2 == 0) {
			l[count] = 2*compute(funct, x);
		}
		else {
			l[count] = 4*compute(funct, x);
		} 		
		count++;
	}
	
	x = b;
	l[count] = compute(funct, x);
	
	var i = 0;
	
	for (i = 0; i <=count; i++) {
		total = total + l[i];
	}
	return Math.round(((total*h)/3) * 1000)/1000;			
}

/* ******************************************************* */
/* Scale Functions by Allen Murphy 2008 */
/* ******************************************************* */
function zoomIn() {
	window.document.functionform.xmin.value = window.document.functionform.xmin.value/2; 
	window.document.functionform.xmax.value = window.document.functionform.xmax.value/2; 
	window.document.functionform.ymin.value = window.document.functionform.ymin.value/2; 
	window.document.functionform.ymax.value = window.document.functionform.ymax.value/2; 
	window.document.functionform.xscale.value = window.document.functionform.xscale.value/2; 
	window.document.functionform.yscale.value = window.document.functionform.yscale.value/2; 
	drawClicked();
}

/* ******************************************************* */
function zoomOut() {
	window.document.functionform.xmin.value = window.document.functionform.xmin.value*2; 
	window.document.functionform.xmax.value = window.document.functionform.xmax.value*2; 
	window.document.functionform.ymin.value = window.document.functionform.ymin.value*2; 
	window.document.functionform.ymax.value = window.document.functionform.ymax.value*2; 
	window.document.functionform.xscale.value = window.document.functionform.xscale.value*2; 
	window.document.functionform.yscale.value = window.document.functionform.yscale.value*2; 
	drawClicked();
}

/* ******************************************************* */
function moveUp() {
	window.document.functionform.ymin.value = window.document.functionform.ymin.value*1 + window.document.functionform.yscale.value*1; 
	window.document.functionform.ymax.value = window.document.functionform.ymax.value*1 + window.document.functionform.yscale.value*1;
	drawClicked();
}

/* ******************************************************* */
function moveDown() {
	window.document.functionform.ymin.value = window.document.functionform.ymin.value*1 - window.document.functionform.yscale.value*1; 
	window.document.functionform.ymax.value = window.document.functionform.ymax.value*1 - window.document.functionform.yscale.value*1; 
	drawClicked();
}

/* ******************************************************* */
function moveLeft() {
	window.document.functionform.xmin.value = window.document.functionform.xmin.value*1 + window.document.functionform.xscale.value*1; 
	window.document.functionform.xmax.value = window.document.functionform.xmax.value*1 + window.document.functionform.xscale.value*1; 
	drawClicked();
}

/* ******************************************************* */
function moveRight() {
	window.document.functionform.xmin.value = window.document.functionform.xmin.value*1 - window.document.functionform.xscale.value*1; 
	window.document.functionform.xmax.value = window.document.functionform.xmax.value*1 - window.document.functionform.xscale.value*1; 
	drawClicked();
}

/* ******************************************************* */
/* Drawing Functions */
/* ******************************************************* */
function DrawAxes(xmax, xmin, xscale, ymax, ymin, yscale, im_height, im_width) {
	jg.setStroke(2);
	jg.setColor("#000000");

	/* draw axes */
	jg.drawLine(xplot(xmin,xmax, xmin, im_width)+1, yplot(0,ymax, ymin, im_height), xplot(xmax,xmax, xmin, im_width)-1, yplot(0,ymax, ymin, im_height));
	jg.drawLine(xplot(xmin,xmax, xmin, im_width)+1,yplot(0,ymax, ymin, im_height)+1,xplot(xmax,xmax, xmin, im_width)-1,yplot(0,ymax, ymin, im_height)+1);
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymin,ymax, ymin, im_height)-1,xplot(0,xmax, xmin, im_width),yplot(ymax,ymax, ymin, im_height)+1);
	jg.drawLine(xplot(0,xmax, xmin, im_width)+1,yplot(ymin,ymax, ymin, im_height)-1,xplot(0,xmax, xmin, im_width)+1,yplot(ymax,ymax, ymin, im_height)+1);

	/* draw axes' arrows */
	jg.drawLine(xplot(xmin,xmax, xmin, im_width)+8,yplot(0,ymax, ymin, im_height)+8,xplot(xmin,xmax, xmin, im_width)+1,yplot(0,ymax, ymin, im_height));
	jg.drawLine(xplot(xmin,xmax, xmin, im_width)+9,yplot(0,ymax, ymin, im_height)+8,xplot(xmin,xmax, xmin, im_width)+2,yplot(0,ymax, ymin, im_height));
	jg.drawLine(xplot(xmin,xmax, xmin, im_width)+8,yplot(0,ymax, ymin, im_height)-8,xplot(xmin,xmax, xmin, im_width)+1,yplot(0,ymax, ymin, im_height));
	jg.drawLine(xplot(xmin,xmax, xmin, im_width)+9,yplot(0,ymax, ymin, im_height)-8,xplot(xmin,xmax, xmin, im_width)+2,yplot(0,ymax, ymin, im_height));
	
	jg.drawLine(xplot(xmax,xmax, xmin, im_width)-8,yplot(0,ymax, ymin, im_height)+8,xplot(xmax,xmax, xmin, im_width)-1,yplot(0,ymax, ymin, im_height));
	jg.drawLine(xplot(xmax,xmax, xmin, im_width)-9,yplot(0,ymax, ymin, im_height)+8,xplot(xmax,xmax, xmin, im_width)-2,yplot(0,ymax, ymin, im_height));
	jg.drawLine(xplot(xmax,xmax, xmin, im_width)-8,yplot(0,ymax, ymin, im_height)-8,xplot(xmax,xmax, xmin, im_width)-1,yplot(0,ymax, ymin, im_height));
	jg.drawLine(xplot(xmax,xmax, xmin, im_width)-9,yplot(0,ymax, ymin, im_height)-8,xplot(xmax,xmax, xmin, im_width)-2,yplot(0,ymax, ymin, im_height));
	
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymin,ymax, ymin, im_height)-1,xplot(0,xmax, xmin, im_width)+8,yplot(ymin,ymax, ymin, im_height)-8);
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymin,ymax, ymin, im_height)-2,xplot(0,xmax, xmin, im_width)+8,yplot(ymin,ymax, ymin, im_height)-9);
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymin,ymax, ymin, im_height)-1,xplot(0,xmax, xmin, im_width)-8,yplot(ymin,ymax, ymin, im_height)-8);
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymin,ymax, ymin, im_height)-2,xplot(0,xmax, xmin, im_width)-8,yplot(ymin,ymax, ymin, im_height)-9);
	
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymax,ymax, ymin, im_height)+1,xplot(0,xmax, xmin, im_width)+8,yplot(ymax,ymax, ymin, im_height)+8);
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymax,ymax, ymin, im_height)+2,xplot(0,xmax, xmin, im_width)+8,yplot(ymax,ymax, ymin, im_height)+9);
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymax,ymax, ymin, im_height)+1,xplot(0,xmax, xmin, im_width)-8,yplot(ymax,ymax, ymin, im_height)+8);
	jg.drawLine(xplot(0,xmax, xmin, im_width),yplot(ymax,ymax, ymin, im_height)+2,xplot(0,xmax, xmin, im_width)-8,yplot(ymax,ymax, ymin, im_height)+9);

	/* draw scale tic marks */
	jg.setColor("#0000aa");
	jg.setStroke(1);
	for (var x = 0; x < parseFloat(xmax); x = x + parseFloat(xscale)) {
		jg.drawLine(xplot(x,xmax, xmin, im_width), yplot(0,ymax, ymin, im_height)-5, xplot(x,xmax, xmin, im_width), yplot(0,ymax, ymin, im_height)+5);
		jg.drawLine(xplot(x,xmax, xmin, im_width)-1, yplot(0,ymax, ymin, im_height)-5, xplot(x,xmax, xmin, im_width)-1, yplot(0,ymax, ymin, im_height)+5);
	}
	for (x = 0; x > parseFloat(xmin); x = x - parseFloat(xscale)) {
		jg.drawLine(xplot(x,xmax, xmin, im_width),yplot(0,ymax, ymin, im_height)-5,xplot(x,xmax, xmin, im_width),yplot(0,ymax, ymin, im_height)+5);
		jg.drawLine(xplot(x,xmax, xmin, im_width)-1,yplot(0,ymax, ymin, im_height)-5,xplot(x,xmax, xmin, im_width)-1,yplot(0,ymax, ymin, im_height)+5);
	}
	for (y=0; y < parseFloat(ymax); y=y + parseFloat(yscale)) {
		jg.drawLine(xplot(0,xmax, xmin, im_width)-5,yplot(y,ymax, ymin, im_height),xplot(0,xmax, xmin, im_width)+5,yplot(y,ymax, ymin, im_height));
		jg.drawLine(xplot(0,xmax, xmin, im_width)-5,yplot(y,ymax, ymin, im_height)-1,xplot(0,xmax, xmin, im_width)+5,yplot(y,ymax, ymin, im_height)-1);
	}
	for (y=0; y > parseFloat(ymin); y=y - parseFloat(yscale)) {
		jg.drawLine(xplot(0,xmax, xmin, im_width)-5,yplot(y,ymax, ymin, im_height),xplot(0,xmax, xmin, im_width)+5,yplot(y,ymax, ymin, im_height));
		jg.drawLine(xplot(0,xmax, xmin, im_width)-5,yplot(y,ymax, ymin, im_height)-1,xplot(0,xmax, xmin, im_width)+5,yplot(y,ymax, ymin, im_height) - 1);
	}
}

/* ******************************************************* */
function DrawGrid(xmax, xmin, xscale, ymax, ymin, yscale, im_height, im_width) {

	var x = 0;
	
	jg.setStroke(1);
	jg.setColor("#aaaaaa");

	//writeOutput(xmax + "," + xmin + ", " + xscale);

	for (x = 0; x < parseFloat(xmax); x = x + parseFloat(xscale)) {
		jg.drawLine(xplot(x,xmax, xmin, im_width),1,xplot(x,xmax, xmin, im_width),im_height - 2);
	}
	for (x = 0; x > parseFloat(xmin); x = x - parseFloat(xscale)) {
		jg.drawLine(xplot(x,xmax, xmin, im_width),1,xplot(x,xmax, xmin, im_width),im_height - 2);
	}
	for (var y = 0; y < parseFloat(ymax); y = y + parseFloat(yscale)) {
		jg.drawLine(1,yplot(y,ymax, ymin, im_height),im_width - 2,yplot(y,ymax, ymin, im_height));
	}
	for (y = 0; y > parseFloat(ymin); y = y - parseFloat(yscale)) {
		jg.drawLine(1,yplot(y,ymax, ymin, im_height),im_width - 2,yplot(y,ymax, ymin, im_height));
	}
}

/* ******************************************************* */
function xplot(x, xmax, xmin, im_width) {
	var retval = im_width/(xmax - xmin)*(x - xmin);
	//alert(retval);
	return Math.floor(retval);
}

/* ******************************************************* */
function yplot(y, ymax, ymin, im_height) {
	var retval = im_height/(ymax - ymin)*(ymax - y);
	return Math.floor(retval);
}

/* ******************************************************* */
function plotFunction(funct, xmax, xmin, ymax, ymin, im_height, im_width) {
	/* draw function */

	var x = 0;
	var y = 0;
	var y2 = 0;
	
	dx = (parseFloat(xmax) - parseFloat(xmin)) / (parseFloat(im_width)/2);
	writeOutput("Plotting f(x) = " + funct +", dx = " + dx);
	
	for (x = parseFloat(xmin); x < parseFloat(xmax); x = x + dx) {
		y = compute(funct, x);
		y2 = compute(funct, x + dx);

		//writeOutput(y+", " + y2+", " + yplot(y, ymax, ymin, im_height)+", "+yplot(y2, ymax, ymin, im_height));
		
		if (yplot(y, ymax, ymin, im_height) < im_height && yplot(y, ymax, ymin, im_height) > 0 && 
			yplot(y2, ymax, ymin, im_height) < im_height && yplot(y2, ymax, ymin, im_height) > 0) {
		
			jg.drawLine(xplot(x,xmax, xmin, im_width), yplot(y, ymax, ymin, im_height), 
				xplot(x+dx,xmax, xmin, im_width), yplot(y2, ymax, ymin, im_height));
			jg.paint();
			jg.drawLine(xplot(x,xmax, xmin, im_width)+1, yplot(y, ymax, ymin, im_height), 
				xplot(x+dx,xmax, xmin, im_width)+1, yplot(y2, ymax, ymin, im_height));
			jg.paint();
		}	
	}
}

/* ******************************************************* */
function plotDerivative(funct, xmax, xmin, ymax, ymin, im_height, im_width) {
	/* draw function */

	var x = 0;
	var y = 0;
	var y2 = 0;
	
	dx = (parseFloat(xmax) - parseFloat(xmin)) / (parseFloat(im_width)/4);
	writeOutput("Plotting nderive(f(x)) = " + funct +", dx = " + dx);
	
	for (x = parseFloat(xmin); x < parseFloat(xmax); x = x + dx) {
		y = ndfdx(funct, x);
		y2 = ndfdx(funct, x + dx);

		if (yplot(y, ymax, ymin, im_height) < im_height && yplot(y, ymax, ymin, im_height) > 0 && 
			yplot(y2, ymax, ymin, im_height) < im_height && yplot(y2, ymax, ymin, im_height) > 0) {
		
			jg.drawLine(xplot(x,xmax, xmin, im_width), yplot(y, ymax, ymin, im_height), 
				xplot(x+dx,xmax, xmin, im_width), yplot(y2, ymax, ymin, im_height));
			jg.drawLine(xplot(x,xmax, xmin, im_width)+1, yplot(y, ymax, ymin, im_height), 
				xplot(x+dx,xmax, xmin, im_width)+1, yplot(y2, ymax, ymin, im_height));
			jg.paint();
		}	
	}
}

/* ******************************************************* */
function plotSecondDerivative(funct, xmax, xmin, ymax, ymin, im_height, im_width) {
	/* draw function */

	var x = 0;
	var y = 0;
	var y2 = 0;
	
	dx = (parseFloat(xmax) - parseFloat(xmin)) / (parseFloat(im_width)/4);
	writeOutput("Plotting nderive(f(x)) = " + funct +", dx = " + dx);
	
	for (x = parseFloat(xmin); x < parseFloat(xmax); x = x + dx) {
		y = n2dfdx(funct, x);
		y2 = n2dfdx(funct, x + dx);

		if (yplot(y, ymax, ymin, im_height) < im_height && yplot(y, ymax, ymin, im_height) > 0 && 
			yplot(y2, ymax, ymin, im_height) < im_height && yplot(y2, ymax, ymin, im_height) > 0) {
		
			jg.drawLine(xplot(x,xmax, xmin, im_width), yplot(y, ymax, ymin, im_height), 
				xplot(x+dx,xmax, xmin, im_width), yplot(y2, ymax, ymin, im_height));
			jg.drawLine(xplot(x,xmax, xmin, im_width)+1, yplot(y, ymax, ymin, im_height), 
				xplot(x+dx,xmax, xmin, im_width)+1, yplot(y2, ymax, ymin, im_height));
			jg.paint();
		}	
	}
}

/* ******************************************************* */
function drawClicked(mode) {
	//Set cursor to hourglass
	document.body.style.cursor = "wait";

	var im_height = 640;
	var im_width = 640;

	var funct = document.functionform.funct.value;
	var gfunct = document.functionform.gfunct.value;
	var xmin = parseFloat(document.functionform.xmin.value);
	var xmax = parseFloat(document.functionform.xmax.value);
	var ymin = parseFloat(document.functionform.ymin.value);
	var ymax = parseFloat(document.functionform.ymax.value);
	var xscale = parseFloat(document.functionform.xscale.value);
	var yscale = parseFloat(document.functionform.yscale.value);

	//jg.clear();
	jg.paint();
	clearOutput();
	myDrawFunction(mode, funct, gfunct, xmax, xmin, xscale, ymax, ymin, yscale, im_width, im_height);

	//Turn hourglass off
	document.body.style.cursor = "default";
}

/* ******************************************************* */
function firstRun() {
	var im_height = 640;
	var im_width = 640;

	var funct = "";
	var gfunct = "";
	var xmin = parseFloat(document.functionform.xmin.value);
	var xmax = parseFloat(document.functionform.xmax.value);
	var ymin = parseFloat(document.functionform.ymin.value);
	var ymax = parseFloat(document.functionform.ymax.value);
	var xscale = parseFloat(document.functionform.xscale.value);
	var yscale = parseFloat(document.functionform.yscale.value);

	myDrawFunction(0,funct, gfunct, xmax, xmin, xscale, ymax, ymin, yscale, im_width, im_height);
}

/* ******************************************************* */
function clearGrid() {
	var im_height = 640;
	var im_width = 640;

	var funct = "";
	var gfunct = "";
	var xmin = parseFloat(document.functionform.xmin.value);
	var xmax = parseFloat(document.functionform.xmax.value);
	var ymin = parseFloat(document.functionform.ymin.value);
	var ymax = parseFloat(document.functionform.ymax.value);
	var xscale = parseFloat(document.functionform.xscale.value);
	var yscale = parseFloat(document.functionform.yscale.value);

	jg.clear();
	jg.paint();
	myDrawFunction(0,funct, gfunct, xmax, xmin, xscale, ymax, ymin, yscale, im_width, im_height);
	//alert(window.document.getElementById("myCanvas").offsetTop);
}

/* ******************************************************* */
function myDrawFunction(mode, funct, gfunct, xmax, xmin, xscale, ymax, ymin, yscale, im_width, im_height) {
	
	DrawGrid(xmax, xmin, xscale, ymax, ymin, yscale, im_height, im_width);
	DrawAxes(xmax, xmin, xscale, ymax, ymin, yscale, im_height, im_width);

	if (funct != "") {
		if (mode == 0) {
			jg.setColor("#0000aa");	
			plotFunction(funct, xmax, xmin, ymax, ymin, im_height, im_width);
		}
		else if (mode == 1) {
			jg.setColor("#aa0000");	
			plotDerivative(funct, xmax, xmin, ymax, ymin, im_height, im_width);
		}
		else if (mode == 2) {
			jg.setColor("#0099aa");	
			plotSecondDerivative(funct, xmax, xmin, ymax, ymin, im_height, im_width);
		}
	}
	
	if (gfunct != "") {
		jg.setColor("#00aa00");
		plotFunction(gfunct, xmax, xmin, ymax, ymin, im_height, im_width);
	}
	jg.paint(); // draws it!
}

/* ******************************************************* */
function writeOutput(s) {
	window.document.getElementById("myOutput").innerHTML = window.document.getElementById("myOutput").innerHTML + 
	 " <br />" + s;
}

/* ******************************************************* */
function mouseMove(e) {

	var im_height = 640;
	var im_width = 640;

	clearOutput();

	var xmin = parseFloat(document.functionform.xmin.value);
	var xmax = parseFloat(document.functionform.xmax.value);
	var ymin = parseFloat(document.functionform.ymin.value);
	var ymax = parseFloat(document.functionform.ymax.value);

	//writeOutput(e.clientX + ", " + e.clientY);
	var x = (e.clientX - 77) - (im_width / 2);
	/* Adjust for scrolling.  IE different than FF and Opera */
	if (getInternetExplorerVersion() > 0 && getInternetExplorerVersion() < 9) {
		var y = (im_height / 2) - (e.clientY - findPos(window.document.getElementById("myCanvas")) + document.documentElement.scrollTop - 5);
	}
	else {
		var y = (im_height / 2) - (e.clientY - findPos(window.document.getElementById("myCanvas")) + window.pageYOffset - 5);
	}
	x_out = Math.floor(xmin + x*((xmax - xmin) / im_width)*1000)/1000;
	y_out = Math.floor(ymin + y*((ymax - ymin) / im_height)*1000)/1000;
	
	window.document.getElementById("trace").innerHTML = "(" + x_out + ", " + y_out + ")";
}

/* ******************************************************* */
function clearOutput() {
	window.document.getElementById("myOutput").innerHTML = ""; 
}

/* ******************************************************* */
function findPos(obj){

	var posY = obj.offsetTop;

	while(obj.offsetParent){
		posY=posY+obj.offsetParent.offsetTop;
		if(obj==document.getElementsByTagName('body')[0]){break}
		else{obj=obj.offsetParent;}
	}
	return posY;
}


