/* 
Thanks for looking at my source :)
Please don't use it without my permission!
wartex8.com/calc 
*/

//////////////////////////////////
// Modified eval()
//////////////////////////////////
function evalM(a){
	try{
		return eval(a);
	}catch(e){console.log(e);}
}

//////////////////////////////////
// Update Equations
//////////////////////////////////
function updateEquations(){//need a better method, I overwrite the layers always which is bad for performance
	source = "<table width='500'>";
	source += "<tr><td width='45%' align='center'>Input </td><td width='25%' align='center'>f(x)</td><td width='25%' align='center'>f '(x)</td></tr>";
	
	for(var i = 0; i < numberOfEquations; i++){
		source += '<tr><td width="45%"><img src="settings.png" onclick="settings(' + i + ');" style="vertical-align: middle;" /> <img src="erase.png" onclick="removeEquation(' + i +');" style="vertical-align: middle;"/><input id="eq' + i + '" style="background-color:white;vertical-align: middle;" onkeyup="update(' + i + ',this.value);" value="';
		if(unmodifiedInput[i] != undefined) source += unmodifiedInput[i];
		source += '"> = </td><td align="center"><span id="result' + i + '"></span></td><td align="center"><span id="deriv' + i + '"></span></td></tr>';
	}
	
	document.getElementById('equations').innerHTML = source + "</table>";
	
	for(var i = 0; i < numberOfEquations; i++){
		if(unmodifiedInput[i] == undefined) unmodifiedInput[i] = "0";
		update(i, unmodifiedInput[i]+"", 1); //unmodifiedInput should be a string already
	}
	render();
}

//////////////////////////////////
// Remove Equations
//////////////////////////////////
function removeEquation(id){
//going to need to remove trigType, dimensions and coordinateType as well
	if(id == 0 && input.length == 1){
		//need to reset layer
		unmodifiedInput[0] = "";
		input[0] = "";
		updateEquations();
		//need to set layer[0] to null or something
	}
		
	if(id == input.length-1){
		layer.pop();
	}
	
	/*else*/
	if(unmodifiedInput.length > 1){
		indexQuery = unmodifiedInput.indexOf(unmodifiedInput[id]);
		layerQuery = layer.indexOf(layer[id]);
		
		if(indexQuery != -1){
			unmodifiedInput.splice(indexQuery, 1); // Remove
			input.splice(indexQuery, 1); // Remove
			trigType.splice(indexQuery, 1);
			graphType.splice(indexQuery, 1);
			dimensions.splice(indexQuery, 1);
		}
		// this is here only because layers may not be created when there is no variables,
		if(layerQuery != -1) layer.splice(layerQuery, 1);
	
		numberOfEquations--;
		updateEquations(); // the problem is 0,3 -> when you remove 0 the 3 is deleted
	}
}

//////////////////////////////////
// Coordinate Conversion (canvas vs graph)
//////////////////////////////////
function toCanvasX(canvasConvert){ //graphXCoordinates -> canvasXcoordinate
	return (canvasConvert - Xmin)*(width/(Xmax - Xmin));
}

function toCanvasY(canvasConvert){ //graphYCoordinates -> canvasYcoordinate
	return (canvasConvert - Ymax)*(height/(Ymin - Ymax));
}

function toGraphX(graphConvert){ //canvasXCoordinate -> graphXCoordinate
	return (graphConvert*(Xmax - Xmin))/width + Xmin;
}

function toGraphY(graphConvert){ //canvasYCoordinate -> graphYCoordinate
	return (graphConvert*(Ymin - Ymax))/height + Ymax;
}

//////////////////////////////////
// Trailing zero fix
//////////////////////////////////
function trailFix(a, sigFig){  // accuracy of .0000000000005
	//sigFig = 10;
	return (Math.round(a*10e13)/10e13)/1; //do an analysis looking at xTable to see how to determine the trail result (10e12 was the first one used)
}

//////////////////////////////////
// Sanitize
//////////////////////////////////
function sanitize(a){
	return a.replace(/ /g, '').toLowerCase();
}

//////////////////////////////////
// validityCheck: parenthesesCheck + 
//////////////////////////////////
function validityCheck(a){//the problem will be dependent on the extra "variables" a person may add, also sin is valid when it should be sin()
	//if(!parenthesesCheck(a)) return 0; //this is only useful for the help box
	//this needs to be based on graphType
	var x = 1; //some equations may generate errors
	var y = 1;
	var x = 1;
	
	try{
		eval(replace(a));
	} catch(e){return 0;}
	
	return 1;
}

//////////////////////////////////
// parenthesesCheck
//////////////////////////////////
function parenthesesCheck(a){ //this is only useful for the help box
	var c = 0
	for(var i = 0, count = a.length; i < count; i++){
		if(a.charAt(i) == "(") c++;
		else if(a.charAt(i) == ")") c--;
		if(c < 0) return 0;
	}
		if(c == 0) return 1;
}

//////////////////////////////////
// validNumber
//////////////////////////////////
function validNumber(a){// what about +- Infinity
	if(isNaN(a) || a == undefined) return 0;
	else return 1;
}

//////////////////////////////////
// Begin Degree/Radian fix
//////////////////////////////////
function setTrigType(a){
	if(a == "degrees") TrigSetToDegree = true;	
	else TrigSetToDegree = false; //if(a == "radians") 
}

//////////////////////////////////
//  timing function for efficiency testing
//////////////////////////////////

timeDiff  =  {
    setStartTime:function (){
        d = new Date();
        time  = d.getTime();
    },

    getDiff:function (){
        d = new Date();
        return (d.getTime()-time);
    }
}
/*
Usage:
timeDiff.setStartTime();
timeDiff.getDiff();
*/

//////////////////////////////////
// inArray - unused
//////////////////////////////////
function inArray(a,b){
	for(var i = 0; i < b.length; i++){
		if (a == b[i]){
		return 1;
		}
	}
	return 0;
}

//////////////////////////////////
// countElement(a, b) - unused
//////////////////////////////////
function countElement(a, b){
	var c = 0;
	while(a.indexOf(b) != -1){
		a = a.replace(b, "");
		c++;
	}
	return c;
}

//////////////////////////////////
// reduceString(a, b) - unused
//////////////////////////////////
function reduceString(a, b){// what about +- Infinity
	if(!b){
		for(var i = 0, count = functionList.length; i < count; i++)//performance increase by setting the symbolExpression to a variable
			while(a.indexOf(functionList[i]) != -1) a = a.replace(functionList[i], "");
		
		for(var i = 0, count = numberExpression.length; i < count; i++)
			while(a.indexOf(numberExpression[i]) != -1) a = a.replace(numberExpression[i], "");
		
		for(var i = 0, count = symbolExpression.length; i < count; i++)
			while(a.indexOf(symbolExpression[i]) != -1) a = a.replace(symbolExpression[i], "");
	}
	if(b){
		while(a.indexOf("x") != -1) a = a.replace("x", "");
		while(a.indexOf("y") != -1) a = a.replace("y", "");
	}
	return a;
}

//////////////////////////////////
// Solve for y - unused
//////////////////////////////////
function findY(a,b){//find y value b in table a
/*	for(var i = 0; i < xTable.length; i++){
		if(yTable[a][i] == b){
			//debug.innerHTML = xTable[a][i]; //changed dom stuff
		}
	}
*/}

///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
//////////////////////////////////
// Begin math functions
//////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////

function gcd(a,b){  //gcf and gcd are same thing REWRITE THIS...
	m = 1;
	if(a > b){
		a = a + b;
		b = a - b;
		a = a - b;
	}
	if(b == (Math.round(b/a))*a) m = a;
	else{
		for(var i = Math.round(a/2); i > 1; i--){
			if((a == (Math.round(a/i))*i))
			if((b == (Math.round(b/i))*i)){m = i; i = -1;}
		}
	}
	return m;
}

function gcf(a,b){
	return gcd(a, b);
}

function lcm(a,b){
	return a*b/(gcd(a,b));
}

function max(a,b){
	return Math.max(a,b);
}

function min(a,b){
	return Math.min(a,b);
}

function abs(a){
	return Math.abs(a);
}

function ln(a){
	return Math.log(a);
}

function log(a){
	return Math.log(a) / Math.log(10);
}

function sqrt(a){
	return Math.sqrt(a);
}

//////////////////////////////////
// trigModifier - this should be a variable
//////////////////////////////////
function trigModifier(){
	if(TrigSetToDegree) return Math.PI/180;
	else return 1;
}

//////////////////////////////////
//Trig functions
//////////////////////////////////
function sin(a){
	return Math.sin(a*trigModifier());
}

function cos(a){
	return Math.cos(a*trigModifier());
}

function tan(a){
	return Math.tan(a*trigModifier());
}

function csc(a){
	return 1/Math.sin(a*trigModifier());
}

function sec(a){
	return 1/Math.cos(a*trigModifier());
}

function cot(a){
	return 1/Math.tan(a*trigModifier());
}

//////////////////////////////////
// Inverse Trig functions
//////////////////////////////////
function asin(a){
	return Math.asin(a)/trigModifier();
}

function acos(a){
	return Math.acos(a)/trigModifier();
}

function atan(a){
	return Math.atan(a)/trigModifier();
}

function acsc(a){
	return Math.asin(1/a)/trigModifier();
}

function asec(a){
	return Math.acos(1/a)/trigModifier();
}

function acot(a){
	return Math.atan(1/a)/trigModifier();
}

//////////////////////////////////
// Hyperbolic Trig functions  //trigMofifier??
//////////////////////////////////

function sinh(a){
	return .5*(-Math.pow(e,-a) + Math.pow(e,a));
}

function cosh(a){
	return .5*(Math.pow(e,-a) + Math.pow(e,a));
}

function tanh(a){
	return 2/(1+Math.pow(e,(-2*a))) - 1;
}

function csch(a){
	return 1/sinh(a);
}

function sech(a){
	return 1/cosh(a);
}

function coth(a){
	return 1/tanh(a);
}

//////////////////////////////////
// Inverse Hyperbolic Trig functions  //trigMofifier??
//////////////////////////////////
function asinh(a){
	return Math.log(a + Math.sqrt(1+a*a));
}

//function acosh(a){ //crazy formula using inverse Jacobi elliptic function
	//add later
//}

function atanh(a){
	return Math.log(Math.sqrt((1+a)/(1-a)));
}

function acsch(a){
	return Math.log(Math.sqrt((1+a)/(1-a)));
}

//function asech(a){
	//add later
//}

function acoth(a){
	return Math.log(Math.sqrt((1+a)/(a-1)));
}

//////////////////////////////////
//Other functions
//////////////////////////////////
function ceil(a){
	return Math.ceil(a);
}

function floor(a){
	return Math.floor(a);
}

function round(a){
	return Math.round(a);
}

function random(){
	return Math.random();
}

function pow(a,b){
	return Math.pow(a,b);
}
