e['function2'] = function () {
	//all functions are private unless included in return statement
// 'abstract' method implementations (for api)
	function getInterface() {
		var out = "<ul>";
		// title
		out += "<li><h1>Non-Linear Equations</h1></li>";
		// input #1
		out += "<li><label for='degree'>Degree</label></li>";
		out += "<li class='input'><input type='text' id='degree' value='4'/></li>";
		// input #2
		out += "<li><label for='coefficients'>Coefficients</label></li>";
		out += "<li class='input'><input type='text' id='coefficients' value='1 -3 -6 6 6'/></li>";
		// input #3
		out += "<li><label for='coefficients'>Step Size</label></li>";
		out += "<li class='input'><input type='text' id='step' value='.5'/></li>";
		//submit button
		out += "<li>&nbsp;</li>";
		out += "<li class='input'><input id='submit' onclick=\"e['function2'].getHTML(document.getElementById('returnValue'))\" type='submit' value='Calculate'/></li>";

		out += "</ul>";
		return out;
	}

	function getHTML(returnNode) {
		if (validateInput()) {
			// grab input vals
			var coeffs = document.getElementById('coefficients').value.split(" ");
			var step = parseFloat(document.getElementById('step').value);

			//format for output and create html
			var out = "<ul>";
			out += "<li><h1>Results</h1></li>";
			out += e['function1'].getNumOfRoots(coeffs);
			out += e['function1'].getRootsInRange(coeffs);
			out += e['function1'].getRootCount(coeffs);
			out += getIntervals(coeffs, step, parseInt(e['function1'].newtonsRelation(coeffs))+1);
			out += "</ul>";
			out += "<input type='hidden' id='coeffs' value='" + document.getElementById('coefficients').value + "' />";
			returnNode.innerHTML = out;
		} //		out += Html.getError("Error Message", 'errorId');
	}
	function validateInput() {
		return e['function1'].validateInput();
	}

// Program & Presentation Functions
	function getIntervals(coeffs, step, upperRange) {
		var intervals = new Array();
		var x = upperRange * -1;
		var f0 = solveFX(x, coeffs);
		step = Math.abs(step);

		var count = e['function1'].countSignChanges(coeffs, false) + e['function1'].countSignChanges(coeffs, true);

		while (intervals.length < count && typeof(intervals[intervals.length-1]) != 'boolean' ) { // for all possible roots
			intervals[intervals.length] = nextBracket(x, f0, step, coeffs, upperRange);
			printDebug( "found new interval @ " + intervals[intervals.length-1] + " < x < " + (intervals[intervals.length-1] + step));
			f0 = solveFX(intervals[intervals.length-1] + step, coeffs, "f0");
			x = intervals[intervals.length-1] + step;
		}

		var out = new String();
		for (var i = 0; i<intervals.length; i++) {
			if (intervals[i] == false) {
				label = (upperRange * -1) + ' < Root ' + i + ' < ' + upperRange;
				strFunc = "e['function2'].solveRoot('root" + i + "', " + (-1 * upperRange) + ", " + upperRange + "); return false;";
			} else {
				label = intervals[i] + ' < Root' + i + ' < ' + (intervals[i] + step);
				strFunc = "e['function2'].solveRoot('root" + i + "', " + intervals[i] + ", " + (intervals[i]+step) + "); return false;";
			}
			out += "<li class='input'>";
			out += "<span id='root" + i + "' class='right'></span>";
			out += "<input onclick=\"" + strFunc + "\" type='submit' value='" + label + "'/>";
			out += "</li>";
		}
		return "<li><span>Intervals Where Roots Occur</span></li>" + out;
	}

	function solveRoot(callerId, intervalStart, intervalEnd) {
		var coeffs = document.getElementById('coefficients').value.split(" ");
		var root = newtonRaphson((intervalStart+intervalEnd) / 2, coeffs, 0).toFixed(3).toString();
		document.getElementById(callerId).textContent = "= " + (root == "NaN" ? "No Root" : root);
	}

// Math Functions
	function nextBracket(x, fX, h, coeffs, upperRange) { // recursive
		var fXH = solveFX(x+h, coeffs);
		printDebug( '<b>fX=' + fX + ' fXH=' + fXH + '</b>' );
		if ((fX * fXH) <= 0) {
			return (x);
		} else if (x+h >= upperRange) {
			return false; // returns false when no root is found and upperRange is reached
		} else {
			return nextBracket(x + h, fXH, h, coeffs, upperRange);
		}
	}
	function solveFX(x, coeffs) {
		var total = 0;
		var n = 0;
		while (coeffs.length > n) {
			total += parseFloat(coeffs[n]) * Math.pow(x, coeffs.length-(n+1));
			n++;
		}
		printDebug( "x=" + x + " f(x)=" + total );
		return total;
	}

	function solveFpX(x, coeffs) {
		var total = 0;
		var n = 0;
		while (coeffs.length-1 > n) {
			total += ( coeffs.length-(n+1) ) * parseFloat(coeffs[n]) * Math.pow(x, ( coeffs.length-(n+1) ) - 1 );
			n++;
		}
		printDebug( "x=" + x + " f'(x)=" + total );
		return total;
	}

	function newtonRaphson(guess, coeffs, iterations) { //recursive
	//	return solveFX(guess, coeffs);
		var FX = solveFX(guess,coeffs);
		var FpX = solveFpX(guess, coeffs);
		var nGuess = guess - (FX/FpX);
		iterations++;
		if (parseInt(nGuess*1000) == parseInt(guess*1000)) {
			return guess;
		} else if (iterations >= 50) {
			return NaN;
		} else {
			return newtonRaphson(nGuess, coeffs, iterations);
		}
	}

// return public pointers to the private methods
	return {
		getInterface:getInterface,
		getHTML:getHTML,
		validateInput:validateInput,

		solveRoot:solveRoot,
		solveFX:solveFX
	}

}();

