// JavaScript Document
<!--
	/********************/
	/* Global variables */
	/********************/
	
	function highlight(boxId) {
		document.getElementById(boxId).style.backgroundColor = "#FFCFD5";
	}
	
	function unhighlight(boxId) {
		document.getElementById(boxId).style.backgroundColor = "";
	}

	function checkNumber(boxId,format) {
		num = document.getElementById(boxId).value;
		if(format=="notNegative") var numPattern = "^(0|(0\.[0-9]+)|([1-9]+[0-9]*\.[0-9]+)|([1-9]+[0-9]*))([eE][+-]?[0-9]{1,2})?$";
		else if(format=="notZero") var numPattern = "^[-]?((0\.[0-9]+)|([1-9]+[0-9]*\.[0-9]+)|([1-9]+[0-9]*))([eE][+-]?[0-9]{1,2})?$";
		else if(format=="positive") var numPattern = "^((0\.[0-9]+)|([1-9]+[0-9]*\.[0-9]+)|([1-9]+[0-9]*))([eE][+-]?[0-9]{1,2})?$";
		else var numPattern = "^[-]?(0|(0\.[0-9]+)|([1-9]+[0-9]*\.[0-9]+)|([1-9]+[0-9]*))([eE][+-]?[0-9]{1,2})?$";
		if(!num.match(numPattern) && !isEmpty(num)) {
			return false;
		} else {
			return true;
		}
	}
	function show_hide_elems(mode) {
		document.getElementById("x_val").style.visibility = "visible";
		document.getElementById("x_err").style.visibility = "visible";
		document.getElementById("y_val").style.visibility = "visible";
		document.getElementById("y_err").style.visibility = "visible";
		document.getElementById("x_val_l").style.visibility = "visible";
		document.getElementById("x_err_l").style.visibility = "visible";
		document.getElementById("y_val_l").style.visibility = "visible";
		document.getElementById("y_err_l").style.visibility = "visible";
		// reset label names
		document.getElementById("y_val_l").childNodes[0].nodeValue = "Y value";
		if(mode=="log" || mode=="antilog") {
			document.getElementById("x_val").style.visibility = "hidden";
			document.getElementById("x_err").style.visibility = "hidden";
			document.getElementById("x_val_l").style.visibility = "hidden";
			document.getElementById("x_err_l").style.visibility = "hidden";
		}
		if(mode=="exponential") {
			document.getElementById("y_err").style.visibility = "hidden";	
			document.getElementById("y_err_l").style.visibility = "hidden";	
			// rename label
			document.getElementById("y_val_l").childNodes[0].nodeValue = "a (constant)";
		}
	}
	function show_preview(obj) {
		operator = obj.operator.value;
		/*****************/
		/* Check formats */
		/*****************/
		//
		// Values
		if(isEmpty(obj.x_val.value) || !checkNumber("x_val")) {
			highlight("x_val");
			x_val = "X";
		} else {
			unhighlight("x_val");
			x_val = obj.x_val.value;
		}
		if(isEmpty(obj.y_val.value) || (!checkNumber("y_val") || (operator=="/" && !checkNumber("y_val","notZero")) || ((operator=="ln" || operator=="log") && !checkNumber("y_val","positive")))) {
			highlight("y_val");
			y_val = "Y";
		} else {
			unhighlight("y_val");
			y_val = obj.y_val.value;
		}
		//
		// Errors
		if(!isEmpty(obj.x_err.value) && !checkNumber("x_err","notNegative")) {
			highlight("x_err");			
			x_err = "dX";
		} else {
			unhighlight("x_err");
			if(!isEmpty(obj.x_err.value)) x_err = obj.x_err.value;
			else x_err = 0;
		}
		if(!isEmpty(obj.y_err.value) && !checkNumber("y_err","notNegative")) {
			highlight("y_err");
			y_err = "dY";
		} else {
			unhighlight("y_err");
			if(!isEmpty(obj.y_err.value)) y_err = obj.y_err.value;
			else y_err = 0;
		}
		//
		/******************************/
		/* Convert strings to numbers */
		/******************************/
		if(x_val!="X") x_val = (+x_val);  // other methods are: =x_val*1 || =parseFloat(x_val) ||=Number(x_val) || =x_val*1  etc
		if(y_val!="Y") y_val = (+y_val);
		if(x_err!="dX") x_err = (+x_err);
		if(y_err!="dY") y_err = (+y_err);
		//
		/************************************/
		/* Construct the preview expression */
		/************************************/
		//displayed operator
		displayedOperator = operator;
		if(displayedOperator=="-") displayedOperator = "&minus;";
		if(displayedOperator=="*") displayedOperator = "&times;";
		if(displayedOperator=="/") displayedOperator = "&divide;";
		//deviations
		if(x_err!=0) x_err_prev = "&plusmn;"+x_err;
		else x_err_prev = "";
		if(y_err!=0) y_err_prev = "&plusmn;"+y_err;
		else y_err_prev = "";
		// a) Simple operations
		if(operator=="+" || operator=="-" || operator=="*" || operator=="/") 
			prev_expression = "("+x_val+x_err_prev+") "+displayedOperator+" ("+y_val+y_err_prev+")";
			// Show all elements
			show_hide_elems("simple");
		// b) Logarithms
		if(operator=="ln" || operator=="log") {
			//if(y_val=="Y") y_val="X";  // otherwise it would have looked like log(Y)
			prev_expression = operator+"("+y_val+y_err_prev+")";
			// Hide irrelevant elements
			show_hide_elems("log");			
		}
		// c) Antilogarithms
		if(operator=="10^y") {
			//if(y_val=="Y") y_val="X";  // otherwise it would have looked like 10^Y
			prev_expression = "10<sup>("+y_val+y_err_prev+")</sup>";
			// Hide irrelevant elements
			show_hide_elems("antilog");
		}
		if(operator=="e^y") {
			//if(y_val=="Y") y_val="X";  // otherwise it would have looked like e^Y
			prev_expression = "e<sup>("+y_val+y_err_prev+")</sup>";
			// Hide irrelevant elements
			show_hide_elems("antilog");
		}
		// d) Exponentiation
		if(operator=="x^a") {
			if(y_val=="Y") y_val="a";  // otherwise it would have looked like x^Y
			prev_expression = "("+x_val+x_err_prev+")<sup>"+y_val+"</sup>";
			// Hide irrelevant elements
			show_hide_elems("exponential");
		}
		//
		/******************/
		/* Update preview */
		/******************/
		document.getElementById("prev_expr").innerHTML = prev_expression;
		//		
	}
	function compute_error() {
		/*************************************************************/
		/* Check that all required values were entered and are valid */
		/*************************************************************/
		var stopCalculation = false;
		if(operator=="ln" || operator=="log" || operator=="e^y" || operator=="10^y") {
			// y_val is required and must be >= 0
			if(y_val=="Y" || y_err=="dY") stopCalculation = true;
		} else {
			// both x_val and y_val are required
			if(x_val=="X" || y_val=="Y" || x_err=="dX" || y_err=="dY") stopCalculation = true;
		}
		if(stopCalculation) {
			alert("Missing or invalid numbers!");
			return false;
		}
		//
		/*****************************/
		/* Calculate Z and dZ values */
		/*****************************/
		// a) Addition or subtraction
		if(operator=="+" || operator=="-") {
			if(operator=="-" && y_val<0) z_val = eval(x_val+(-1*y_val));
			else z_val = eval(x_val+operator+y_val);
			z_err = Math.sqrt(Math.pow(x_err,2)+Math.pow(y_err,2));
		}
		// Multiplication or division
		if(operator=="*" || operator=="/") {
			z_val = eval(x_val+operator+y_val);
			z_err = z_val*(Math.sqrt(Math.pow((x_err/x_val),2)+Math.pow((y_err/y_val),2)));
		}
		// c) Natural logarithm
		if(operator=="ln") {
			z_val = Math.log(y_val);
			z_err = y_err/y_val;
		}
		// d) Decimal logarithm
		if(operator=="log") {
			z_val = Math.LOG10E*Math.log(y_val);
			z_err = Math.LOG10E*(y_err/y_val);
		}
		// e) AntiLN
		if(operator=="e^y") {
			z_val = Math.exp(y_val);
			z_err = z_val*y_err;
		}
		// f) AntiLOG
		if(operator=="10^y") {
			z_val = Math.pow(10,y_val);
			z_err = (1/Math.LOG10E)*z_val*y_err;
		}
		// g) Exponentiation
		if(operator=="x^a") {
			z_val = Math.pow(x_val,y_val);
			z_err = z_val*y_val*(x_err/x_val);
		}
		//	
		/*******************/
		/* Display results */
		/*******************/
		document.getElementById("z_val").value = z_val;
		document.getElementById("z_err").value = z_err;
		
		return false;
	}	
	function resetBoxes() {
		/******************/
		/* Update preview */
		/******************/
		document.getElementById("prev_expr").innerHTML = "(X&plusmn;dX) + (Y&plusmn;dY)";
		/****************************/
		/* Reset colors, visibility */
		/****************************/
		unhighlight("x_val");
		unhighlight("x_err");
		unhighlight("y_val");
		unhighlight("y_err");
		document.getElementById("x_val").style.visibility = "visible";
		document.getElementById("x_err").style.visibility = "visible";
		document.getElementById("y_val").style.visibility = "visible";
		document.getElementById("y_err").style.visibility = "visible";
		document.getElementById("x_val_l").style.visibility = "visible";
		document.getElementById("x_err_l").style.visibility = "visible";
		document.getElementById("y_val_l").style.visibility = "visible";
		document.getElementById("y_err_l").style.visibility = "visible";
	}
	
	/********************/
	/* Memory functions */
	/********************/
	function z2m() {
		if(isEmpty(document.getElementById("z_val").value)) return false;
		document.getElementById("mem_val").value = document.getElementById("z_val").value;
		document.getElementById("mem_err").value = document.getElementById("z_err").value;
		document.getElementById("z_val").value = "";
		document.getElementById("z_err").value = "";
	}
	function mRecallX() {
		if(isEmpty(document.getElementById("mem_val").value)) return false;
		document.getElementById("x_val").value = document.getElementById("mem_val").value;
		document.getElementById("x_err").value = document.getElementById("mem_err").value;
		show_preview(document.getElementById('errPropagCalc'));
	}
	function mRecallY() {
		if(isEmpty(document.getElementById("mem_val").value)) return false;
		document.getElementById("y_val").value = document.getElementById("mem_val").value;
		document.getElementById("y_err").value = document.getElementById("mem_err").value;
		show_preview(document.getElementById('errPropagCalc'));
	}
	function mClear() {
		if(isEmpty(document.getElementById("mem_val").value)) return false;
		document.getElementById("mem_val").value = "";
		document.getElementById("mem_err").value = "";
	}
	//-->