///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Javascipt for calculators                                                 //
//																			 //
// DHTML ype of all elements in a calculation is <input type ="text"	     //
// Calculation rules are property of name attribute: 						 //
//	Key                = "CALCULATE"								         //
//  Key/value separaor = ":"												 //
//  Value			   = <REF to element names minus eventual CALCULATE part //
//                       with normal arithmic operators and paremtheses	     //
//																			 //
// This script assumes there are no loops in calculations rules              //
//																			 //
//	Copyright IMAREX ASA 2008.												 //	
//																			 //
//	This programming code is copyright of IMAREX ASA. 						 //
//																			 //
//	This source code may not be copied, modified or otherwise repurposed for //
//  use by a third party without the written permission of IMAREX ASA.       //
//																			 //
//	Contact webmaster@imarex.com for information.                            //
//																			 //
//  Author: Gunnar Skogen 01.12.2008                                         //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

var debugLevel = 1;
var doDebug = false;
function debug(str1, str2) {
	if (! doDebug) return;
	prompt(str1, str2);
}

// Global vars
var decimalPlaces = 2;

// Contains only 
var calculationRefs 	 = new Array();

// Eventually do an arr of these if sevaral (main) results
var finalCalcElementName = "TCE";


/**
 *	Structure for calculation ref
 *
 *	@param element pointer to DHTML element
 *  @param name    name of the element, sans eventual CALCULATE part
 */
 function calculationRef(element, name) {
 	this.element	  = element;
 	this.name		  = name;
 	this.value		  = 0;
 	this.calculation  = '';
 	this.dependencies = new Array();
 	//this.dependants   = new Array(); 	
 }


/**
 * initialise s calculator by doing all (sub) calculations
 */ 
function initCalculator() {
	var calculator = document.getElementById("CALCULATOR");
	//prompt("initCalculator>> ", "calculationRefs.length = " + calculationRefs.length + "--id--" + calculator.id);
	setupCalculationRefs(calculator.getElementsByTagName("input"));
	setupCalculationRefs(calculator.getElementsByTagName("select"));	
	calculate();
	
}


  /**
   * validation of input
   * only numeric input
   * remove blanksand replace comma with punctation and only at last
   *
   *    @param element                   the ID of the html object
   */
  function valNumeric(element)  {
  	if (! element ) {
  		return true;
  	}
    if (element.value.length === 0 ) {
        return true;
    }    
    
    if (element.tagName == "SELECT") {
		//prompt("valNumeric(" + element.name + ")", element.value);
    	return true; // not changeable
    }
    var i;
    var ok = true;

    var re = /,/g;
    var decimalSignOk = ".";
    element.value = element.value.replace(re, decimalSignOk);

    // To keep :
    var lastDecimalSign = element.value.lastIndexOf(".");
    // char by char :
    var newValue = "";
    for ( i = 0; i < element.value.length; i++ )  {
        if ((element.value.substr(i, 1) == '.') && (i < lastDecimalSign) ) {
            continue;
        }    
        if (element.value.substr(i, 1) == ' ')  {
            continue;
        }    
        if ( isNaN(parseInt(element.value.substr(i, 1))) && element.value.substr(i, 1) != '.' ) {
            ok = false;
        }
        newValue = newValue + element.value.substr(i, 1);
    }
    if (newValue.length > 14) {
        alert("To many digits in this value..");
        element.focus();
        element.select();
        return false;
    }
    if ( ! ok ) {
        alert("Value here must be a number");
        element.focus();
        element.select();
        return false;
    }
	element.value = round2dec(newValue);
    return true;
  }



/**
 *	INVAR: normalised value xxxxx<.xxxxx> 20.064655172413793
 										     06///4655172413793
 */
function round2dec(value) {
	var retValue = value;
	//prompt("value = " + value, value.toString(10) );
	try {
		value = value.toString(10);
		if (value.indexOf('.') >= 0) {			
			var valArr   = value.split('.');
			if (valArr[1].length > 2) {
					//prompt("rrrround", valArr[1].substr(0,2) + "///" + valArr[1].substr(2) + "==" +
					//       Math.round(valArr[1].substr(0,2) + "." +  valArr[1].substr(2)));
					var frac =  Math.round(valArr[1].substr(0,2) + "." +  valArr[1].substr(2)).toString();
					//prompt("frac len = " + frac.length);
					if (frac.length == 1) {
						frac = "0" + frac;
					}
					valArr[1] = frac;			
				retValue = valArr[0] + '.' + valArr[1];
			}
			else
			if (valArr[1].length < 2) {
				retValue = valArr[0] + '.' + valArr[1] + '0';
			}
		}
		else {
			retValue += ".00";
		}
 	}
	catch(exception) {
		alert("round2dec(" + value + "): Failed") ;
	}

	return retValue;
}
4







/**
 *
 *	Not recursive (in case of loop violations.. 
 */
function setupCalculationRefs(elements) {
	var funcName = "setupCalculationRefs: ";
	
	//prompt(funcName,"elements.length = ", + elements.length); 
	for (i = 0; i < elements.length; i++) {
		//debug(funcName + inputElements[i].name);
		var calcRulePos = elements[i].name.indexOf(";CALCULATE:");
		if (calcRulePos > 0) {
			var calcRule = elements[i].name.substr(calcRulePos + (";CALCULATE:".length));
			var name     = elements[i].name.substr(0,calcRulePos);
			//prompt(funcName + "calcRule:" + calcRule, name);
			var calculationRefObj = new calculationRef(elements[i], name);
			// Find dependencies and dependants:
			calculationRefObj.dependencies = getDependencies(calcRule);
			// Set up Calculation
			calculationRefObj.calculation = calcRule; 
			//calculationRefObj.dependants   = getDependants(name); No need (?)
			//prompt(funcName + ">>" + calculationRefObj.name, "CALC ELEMENT" );
			calculationRefs[calculationRefs.length] = calculationRefObj;			
		}		
		else {
			var calculationRefObj   = new calculationRef(elements[i], elements[i].name);
			calculationRefObj.value = elements[i].value;
			//prompt(funcName + ">>" + calculationRefObj.name, calculationRefObj.value );
			calculationRefs[calculationRefs.length] = calculationRefObj;			
		}
	}
}


/**
 * Get an array og all elements that are calcRule
 */
 function getDependencies(calcRule) {
 	var funcName = "getDependencies";
 	//debug(funcName + "(" + calcRule + ")");
 	
 	var i = 0;
 	var depArr = new Array();
 	var depName = '';
 	for (i = 0; i < calcRule.length; i++ ) {
 		switch ( calcRule.charAt(i) ) {
 			case '*' :
 			case '/' :
 			case '+' :
 			case '-' :
 			case '(' :
 			case ')' :
 				if (depName.length > 0 && isNaN(parseFloat(depName))) {
 					
 					depArr[depArr.length] = depName; //findElement(depName); 					
 				}	
 				depName = '';	
 				break;	
 			default :	
 				depName += calcRule.charAt(i);	
 		}
 	}
	if (depName.length > 0 && isNaN(parseFloat(depName))) {
		depArr[depArr.length] = depName;//findElement(depName);
	}	
 	//debug(funcName + ">>depArr.length=" + depArr.length, calcRule);
 	return depArr;
 }

 
 /**
  *
  *
  function findElement(name) {
  	var funcName = "findElement";
	//debug(funcName + "(" + name + ")");
  	
	var inputElements = CALCULATOR.getElementsByTagName("input");
	var i = 0;
	for (i = 0; i < inputElements.length; i++) {
		if (inputElements[i].type != "text") {
			continue;
		}
		if (name == getName(inputElements[i])) {
			if (name == "WAIT_DAYS")
			//debug(funcName + "GOT: " + inputElements[i].name);
			return inputElements[i];
		}
	}
	alert(funcName + "Not found: " + name);
  	return null;
  }
  */
 
 /**
  *
  *  Invar: element: <input type="text"
  *  Rule : name is all upto eventual ";" in elements name
  */
  function getName(element) {
  	var funcName = "getName";
  	
  	if (! element) {
  		//debug(funcName + ">>element not");
  		return;
  	}
  	
  	//debug(funcName + "(" + element.tagName + ")");
  	var nameLength = element.name.indexOf(";")
  	
  	if ( nameLength == -1 ) {
  		nameLength = element.name.length;  		
  	}
	
	return element.name.substr(0,nameLength);
  }


/** 
 *	Start at final result and work backwards
 */
function calculate(element) {
	if (! valNumeric(element)) {
		return;
	}
	if (calculationRefs.length === 0) {
		//lazy init
		initCalculator();
	}
	//prompt("caculate:" + element.value);
	doCalculate(findElementInRefs(finalCalcElementName));
	//doCalculate(findElementInRefs("NET_INCOME_CTRL"));
	//prompt("debVal:", debVal);	
}


var debVal;
/**
 *	Recursive: get all values needed to run an elements calculation
 *
 *  
 *  No 0 values allowed
 */
function doCalculate(calcElement) {
	var funcName = "doCalculate";
	
	if (calcElement == null) {
		alert(funcName + ":!! calcElement==null");
		return;
	}
	//prompt(funcName + ">>" + calcElement.name, calcElement.element.value);
	var retValue = 0; // keep decimals in ret
	calcElement.value = calcElement.element.value;

	if (calcElement.calculation.length > 0) {
		var i = 0;
		for ( i = 0; i < calcElement.dependencies.length; i++ ) {
			var value = doCalculate(findElementInRefs(calcElement.dependencies[i]));
			if (value === false) {
				return false;
			}	
			eval("var " + calcElement.dependencies[i] + "=" + value + ";");	
		}
		calcElement.value 		  = eval(calcElement.calculation); // unrounded -> calc
		calcElement.element.value = round2dec(calcElement.value);	
		//debVal = debVal + calcElement.name + "=" +calcElement.value + ";";
		//retValue = valNum.toString(10);
	}
	if (calcElement.element.value == 0) {
		//alert(funcName + "Illegal 0 value for " + calcElement.name);
		return false;
	}
	return calcElement.value;
	
}



/**
 *	No 
 */
function findElementInRefs(name) {
	var funcName = "findElementInRefs";
	//prompt("findElementInRefs("+name+")",calculationRefs.length);	
	if (calculationRefs.length === 0) {
		//lazy init
		initCalculator();
	}
	
	var i = 0;
	for (i = 0; i < calculationRefs.length; i++) {
		//prompt(name, calculationRefs[i].name);
		if (calculationRefs[i].name == name) {
			return calculationRefs[i];
		}	
	}
	alert(funcName + "!!! Could not find " + name + " element!!");
	return null;
}

//>>>>>>>>>>>>>>>>>>>> POP up window <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

// the popup window
var oPopup = window.createPopup();
var oPopupBody;
var popUpMaxWidth = 500;


/**
 *  hover on a calcuøatable element: show the calculation and value with all decimals
 */
function showCalc(element) {
	var oPopupBody                   = oPopup.document.body;
	oPopupBody.style.backgroundColor = "lightyellow";
	oPopupBody.style.border          = "solid black 1px";
	oPopupBody.style.marginTop       = "2px";
	oPopupBody.style.marginLeft      = "2px";
	oPopupBody.style.marginBottom    = "2px";
	oPopupBody.style.marginRight     = "2px";
	var infoText                     = getCalcInfo(element);
	
	oPopupBody.innerHTML             = infoText;	
	//prompt("infoText: ", oPopupBody.innerHTML);
	var popWidth                     = infoText.length * 10 + 40;
	var popHeight                    = 24; //(Math.ceil(popWidth / popUpMaxWidt2h) * 20) + 4;
	/*
	if ( popWidth > popUpMaxWidth) {
		popWidth = popUpMaxWidth;
	}    
	*/
	oPopup.show(window.event.clientX + 10 , window.event.clientY + 20 , popWidth, popHeight, document.body);
	
}

/**
 *  hide the popup window
 */
function hideCalc() {
 	oPopup.hide();
}


function getCalcInfo(element) {
    var funcName = "getCalcInfo";
    
	var calcRulePos = element.name.indexOf(";CALCULATE:");
	if (calcRulePos > 0) {
		var calcRule   = element.name.substr(calcRulePos + (";CALCULATE:".length));
		var name       = element.name.substr(0,calcRulePos);
		var refElement = findElementInRefs(name);
		var retStr = refElement.calculation + "=" + refElement.value;
		
		return retStr;
	}
	else {
		return "";
	}
	
}