
var nbsp = 160;		// non-breaking space char
var node_text = 3;	// DOM text node-type
var emptyString = /^\s*$/ ;
var numberString = /^\d+\.?\d*$/ ;
var decimalString = /^\.\d*$/ ;

var lang = "nothing";


function getLanguage(){
	if(lang == "nothing"){
		lang = document.getElementById("language").innerHTML;
		if(lang != "eng" && lang != "fre"){lang = "eng";}
	}
	return lang;
}

function commonCheck    (valfield,   // element to be validated
                         outputId)  // id of element to receive output info
{
  if (!document.getElementById) 
    return true;  // not available on this browser
  var elem = document.getElementById(outputId);
  if (!elem.firstChild) return true;  // not available on this browser 
  if (elem.firstChild.nodeType != node_text) return true;  // outputId is wrong type of node  


  if (decimalString.test(valfield.value)) {
      valfield.value = "0" + valfield.value;
  }

  if (!numberString.test(valfield.value)) {
	
      if(getLanguage() == "fre"){
		msgOut(outputId, "Inscrire un chiffre valide.");
	  }
	  else{
		msgOut(outputId, "Please enter a valid number.");  
      }
	  return false;
  }
  
  msgOut(outputId, "");
  
  return true;
}

function msgOut(outputId, // id of element to display message in
				message)  // string to display
{
	// setting an empty string can give problems if later set to a 
	// non-empty string, so ensure a space present. (For Mozilla and Opera one could 
	// simply use a space, but IE needs a non-breaking space.)
	var dispmessage;
	if (emptyString.test(message)) 
	dispmessage = String.fromCharCode(nbsp);    
	else  
	dispmessage = message;

	var elem = document.getElementById(outputId);
	elem.firstChild.nodeValue = dispmessage;
}


function validateAvgDenNorWood(valfield, outputId, boolRecalc){
	var density;
	if(commonCheck(valfield, outputId)){
		density = parseFloat(valfield.value);
		if(density >= 1.15){
			if(getLanguage() == "fre"){
				msgOut(outputId, "Mise en garde : Normalement inf" +  charCode(233) + "rieure " +  charCode(224) + " 1,15."); 
			}
			else{
				msgOut(outputId, "Warning: Normally less than 1.15."); 
			}
		}
		
		if(boolRecalc) {calculateADU(true);}
		return true;
	}
	else{
		return false;
	}
}

function validateActualDensity(valfield, outputId, boolRecalc){
	var density;
	if(commonCheck(valfield, outputId)){
		density = parseFloat(valfield.value);
		if(density >= 1.15){
			if(getLanguage() == "fre"){
				msgOut(outputId, "Mise en garde : Normalement inf" +  charCode(233) + "rieure " +  charCode(224) + " 1,15."); 
			}
			else{
				msgOut(outputId, "Warning: Normally less than 1.15.");
			}
		}
		
		if(validateAvgDenNorWood(document.getElementById('AvgDenNorWoodValue'),'infoAvgDenNorWood', false)){
			var AvgDenNorWood = getValue('AvgDenNorWoodValue');
			if(AvgDenNorWood < density){
				if(getLanguage() == "fre"){
					msgOut(outputId, "Erreur: La densit" +  charCode(233) + " r" +  charCode(233) + "elle doit " + charCode(234) + "tre inf" + charCode(233) + "rieure " + charCode(224) + " la densit" + charCode(233) + " normale.");
				}
				else{
					msgOut(outputId, "Error: Actual density must be less than normal density.");
				}
				return false;
			}
		}
		
		if(boolRecalc) {calculateADU(true);}
		return true;
	}
	else{
		return false;
	}
}

function validateMaxWaterContent(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		if(boolRecalc) {calculateADU(true);}
		return true;
	}
	else{
		return false;
	}
}

function validateWeightAirWater(valfield, outputId, boolRecalc){
	var weiWat = document.getElementById('weightWaterValue');
	var weiAir = document.getElementById('weightAirValue');
	
	if(commonCheck(weiAir, outputId)){
		if(commonCheck(weiWat, outputId)){
			if(boolRecalc) {calculateADU(true);}
			return true;
		}
		else{
			if(getLanguage() == "fre"){
				msgOut(outputId, "Inscrire un chiffre valide pour le poids en suspension dans l'eau.");
			}
			else{
				msgOut(outputId, "Please enter a valid number for Weight in Water.");
			}
			return false;
		}
	}
	else{
		if(getLanguage() == "fre"){
			msgOut(outputId, "Inscrire un chiffre valide pour le poids dans l'air.");
		}
		else{
			msgOut(outputId, "Please enter a valid number for Weight in Air.");
		}
		return false;
	}
}

function validateWeightWater(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		if(boolRecalc) {calculateADU(true);}
		return true;
	}
	else{
		return false;
	}
}

function validateWeightAir(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		if(boolRecalc) {calculateADU(true);}
		return true;
	}
	else{
		return false;
	}
}


function validateMCatFSP(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		if(boolRecalc) {calculateADU(true);}
		return true;
	}
	else{
		return false;
	}
}

function optionChange(radioOption){
	msgOut('infoActDen','');
	msgOut('infoMaxWatCon','');
	msgOut('infoWeiAirWat','');
	msgOut('infoActDenUsed','');
	
	setValue('actualDensityUsed',"");
	
	var result400 = document.getElementById('result400Num');
	result400.innerHTML =  "";
	
	var result3350 = document.getElementById('result3350Num');
	result3350.innerHTML = "";
	
	document.getElementById('rowOne').style.cssText = "";
	document.getElementById('rowTwo').style.cssText = "";
	document.getElementById('rowThree').style.cssText = "";
	
	
	var cssString = 'background-color:lightgrey;';
	radioOption.parentNode.parentNode.style.cssText = cssString;
	radioOption.parentNode.parentNode.setAttribute('style',cssString);
	
	calculateADU(true);
}

function calculateADU(validationNeeded){
	
	var radioElemOne = document.getElementById('actualDensity');
	var radioElemTwo = document.getElementById('maxWaterContent');
	var radioElemThree = document.getElementById('weightWaterAir');
	
	var result;
	
	if(radioElemOne.checked == true){
		if(!validateActualDensity(document.getElementById('actualDensityValue'),'infoActDen', false)){return false;}

		result = document.getElementById('actualDensityValue').value;

	}
	else if(radioElemTwo.checked == true){
		if(!validateMaxWaterContent(document.getElementById('maxWaterContentValue'),'infoMaxWatCon', false)){return false;}

		var value = getValue('maxWaterContentValue');
		result = 100 / (value + 66.6667);
        result = Int(result * 1000 + 0.5) / 1000;
	}
	else if(radioElemThree.checked == true){
		//Validate weight water and wieght air
		var x;
		var y;
		x = !validateWeightWater(document.getElementById('weightWaterValue'),'infoWeiAirWat', false);
		y = !validateWeightAir(document.getElementById('weightAirValue'),'infoWeiAirWat', false);
		if(x || y){return false;}

		//The validation succeded so get the values
		var valueWater = getValue('weightWaterValue');
		var valueAir = getValue('weightAirValue');
		
		//Make sure the weight in water is GT or EQ to the weight in air
		if(valueWater >= valueAir){
			
			if(getLanguage() == "fre"){
				msgOut('infoWeiAirWat',"Erreur: Le poids dans l'eau doit " + charCode(234) + "tre inf" + charCode(233) + "rieur " + charCode(224) + " ce lui dans l'air.");
			}
			else{
				msgOut('infoWeiAirWat',"Error: The weight in water must be less than the weight in air.");
			}
			return false;
		}
		
		var Ws;
		var Um;
		
		//Do the calculation for actual density
		Ws = valueWater * 3;
        Um = 100 * (valueAir - Ws) / Ws;
        Um = Int(Um * 10 + 0.5) / 10;
        result = 100 / (Um + 66.6667);
        result = Int(result * 1000 + 0.5) / 1000;
	}
	
	result = result.toString();
	result = result.substr(0,result.indexOf(".")+4);

	setValue('actualDensityUsed', result)
	

	
	if(validateAvgDenNorWood(document.getElementById('AvgDenNorWoodValue'),'infoAvgDenNorWood', false)){
		var ADU = result
		var AvgDenNorWood = getValue('AvgDenNorWoodValue');
		if(AvgDenNorWood < ADU){
			if(getLanguage() == "fre"){
				msgOut('infoActDenUsed', "Erreur: La densit" + charCode(233) + " r" + charCode(233) + "elle doit " + charCode(234) + "tre inf" + charCode(233) + "rieure " + charCode(224) + " la densit" + charCode(233) + " normale.");
			}
			else{
				msgOut('infoActDenUsed', "Error: Actual density must be less than normal density");
			}
			return false;
		}
		else{
			msgOut('infoActDenUsed', "");
		}
	}
	

	return true;
}

function suggestMCatFSP(){
	if(!validateAvgDenNorWood(document.getElementById('AvgDenNorWoodValue'), 'infoAvgDenNorWood',false)){return false;}
	
	var valueAvgNorDen = getValue('AvgDenNorWoodValue');
	var result = Math.pow(10, (1.454 - 0.384 * Math.log(valueAvgNorDen) / 2.3026));
	
	result = result.toString();
	result = result.substr(0,result.indexOf(".")+4);
	
	setValue('MCatFSPValue',result)
}

function calculatePEG(fixEutectic){
	var c200;
	var c3350;
	
	var ConstOfOnePointFive = 1.5;
	var PcDvalue = 1;
	
	//First validate the entries
	if (!calculateADU(true)){return false;}
	if(!validateAvgDenNorWood(document.getElementById('AvgDenNorWoodValue'),'infoAvgDenNorWood', false)){return false;}
	if(!validateMCatFSP(document.getElementById('MCatFSPValue'),'infoMCatFSP', false)){return false;}
	
	//Get the values
	var ADU = getValue('actualDensityUsed');
	var AvgDenNorWood = getValue('AvgDenNorWoodValue');
	var MCatFSP = getValue('MCatFSPValue');
	
	if(AvgDenNorWood < ADU){
		if(getLanguage() == "fre"){
			msgOut('infoActDenUsed', "Erreur: La densit" + charCode(233) + " r" + charCode(233) + "elle doit " + charCode(234) + "tre inf" + charCode(233) + "rieure " + charCode(224) + " la densit" + charCode(233) + " normale.");
		}
		else{
			msgOut('infoActDenUsed', "Error: Actual density must be less than normal density");
		}
		return false;
	}

	// check  divide by zero
	while(true){
        if ((ADU == ConstOfOnePointFive) || ((ADU * (1 + 1.5 * MCatFSP / 100)) == ConstOfOnePointFive))
            ConstOfOnePointFive = ConstOfOnePointFive + 0.00001
		else
			break;
	}
	
	c200 = MCatFSP * ADU * 1.5 / (ConstOfOnePointFive - ADU)
	c200 = Int(c200 * 10 + 0.5) / 10
	c200 = c200 * PcDvalue

	c3350 = 107.2 * (AvgDenNorWood - ADU) / (ConstOfOnePointFive - ADU * (1 + 1.5 * MCatFSP / 100))
	c3350 = Int(c3350 * 10 + 0.5) / 10
	
	if(c3350<0){c3350=0;}
	
	if(((c200 + c3350) >= 45) && ((c200 + c3350) <= 65)){

		if(!fixEutectic){
			if(getLanguage() == "fre"){
				fixEutectic = confirm("Mise en garde : Proximité du point eutectique - D" + charCode(233) + "sirez-vous r" + charCode(233) + "duire la densit" + charCode(233) + " normale aux concentrations recalcul" + charCode(233) + "es afin d'" + charCode(233) + "viter l'eutectique? (OK)");
			}
			else{
				fixEutectic = confirm("Eutectic Proximity Warning - Do you wish the normal density reduced and the concentrations recalculated to avoid the eutectic? (OK)");
			}
		}
		
		if (fixEutectic){
			setValue('AvgDenNorWoodValue', formatNum(getValue('AvgDenNorWoodValue') - 0.01));
			suggestMCatFSP();
			return calculatePEG(true);
		}
	}

	
	var result400 = document.getElementById('result400Num');
	result400.innerHTML =  c200;
	
	var result3350 = document.getElementById('result3350Num');
	result3350.innerHTML = c3350;
	
	setValue('fin400conValue', c200);
	setValue('fin400con3350Value', c200);
	setValue('fin3350conValue', c3350);
	
	return true;
}

function openLibrary(){

	if(getLanguage() == "fre"){
		var lib= window.open('lib-bib-fra.aspx','popup_form','scrollbars=1,height=600,width=1100'); //menubar=no,status=no,
	}
	else{
		var lib= window.open('lib-bib-eng.aspx','popup_form','scrollbars=1,height=600,width=1100'); //menubar=no,status=no,
	}
}

function clearPEG() {
	msgOut('infoAvgDenNorWood','');
	msgOut('infoActDen','');
	msgOut('infoMaxWatCon','');
	msgOut('infoWeiAirWat','');
	msgOut('infoActDenUsed','');
	msgOut('infoMCatFSP','');

	setValue('AvgDenNorWoodValue',"");
	setValue('actualDensityValue',"");
	setValue('maxWaterContentValue',"");
	setValue('weightWaterValue',"");
	setValue('weightAirValue',"");
	setValue('actualDensityUsed',"");
	setValue('MCatFSPValue',"");
	
	var result400 = document.getElementById('result400Num');
	result400.innerHTML =  "";
	
	var result3350 = document.getElementById('result3350Num');
	result3350.innerHTML = "";
}


//*******************************

//PEG 400
function validateVolume400(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

function validateStart400Con(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

function validateFin400Con(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

function validateSteps400(valfield, outputId, boolRecalc){//TODO: Make a whole number
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

//PEG 3350
function validateFin400con3350(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

function validateVolume3350(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

function validateStart3350Con(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

function validateFin3350Con(valfield, outputId, boolRecalc){
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

function validateSteps3350(valfield, outputId, boolRecalc){ //TODO: Make a whole number
	if(commonCheck(valfield, outputId)){
		return true;
	}
	else{
		return false;
	}
}

//Calculate PEG 400
function calculatePEG400(){
	var MAX_STEPS = 10;

	if(!validateVolume400(document.getElementById('volume400PValue'),'infoValVol400', false)){return false;}
	if(!validateStart400Con(document.getElementById('start400conValue'),'infoValStart400Con', false)){return false;}
	if(!validateFin400Con(document.getElementById('fin400conValue'),'infoValFin400Con', false)){return false;}
	if(!validateSteps400(document.getElementById('steps400Value'),'infoValSteps400', false)){return false;}
	
	//This routine implements the following equation to determine incremental PEG400 steps
    //Vr = Vt * (c2-c1)/(1-c2)
    //   where Vr = volume of PEG400 to replace
    //         Vt = total volume (constant throughout all steps)
    //        c1 = current PEG400 (effects of percent removed)
    //        c2 = desired PEG400 (effects of percent removed)
	var Vr;
	var Vt = getValue('volume400PValue');
	var start400con = getValue('start400conValue');
	var fin400con = getValue('fin400conValue');
	var steps = getValue('steps400Value');
	
	if(steps > MAX_STEPS){steps = MAX_STEPS;}
	
	var current=new Array(MAX_STEPS);
	var desired=new Array(MAX_STEPS);
	var replace=new Array(MAX_STEPS);

	current[0] = start400con;
	
	var dIncr = (fin400con - current[0])/steps; 
	
	
	for(i=0; i < steps; i++) {
		desired[i] = current[0] + (i+1) * dIncr;
	}
	
	for(i=0; i < MAX_STEPS; i++){
		c1 = current[i] / 100;
		c2 = desired[i] / 100;
            
		Vr = Vt * (c2 - c1) / (1 - c1);
		
		replace[i] = Vr;
		
		current[i + 1] = desired[i];
	}
	
	
	var strOut;
	
	if(getLanguage() == "fre"){
		strOut = "<table><tr><td>Actuelle % v/v</td><td>D" + charCode(233) + "sir"+ charCode(233) + "e % v/v</td><td>Rempla" + charCode(231) + "er L</td></tr>";
	}
	else{
		strOut = "<table><tr><td>Current % v/v</td><td>Desired % v/v</td><td>Replace L</td></tr>";
	}

	for(i=0; i < steps; i++){
		strOut = strOut + "<tr><td>" + formatNum(current[i]) + "</td><td>" + formatNum(desired[i]) + "</td><td>" + formatNum(replace[i]) + "</td></tr>";
	}
	
	strOut = strOut + "</table>";
	insertTableData(strOut, "PEG400Table");
}

function clearPEG400(){ 
	msgOut('infoValVol400','');
	msgOut('infoValStart400Con','');
	msgOut('infoValFin400Con','');
	msgOut('infoValSteps400','');

	setValue('volume400PValue', '');
	setValue('start400conValue', '');
	setValue('fin400conValue', '');
	setValue('steps400Value', '');
	
	insertTableData('', "PEG400Table");
}

//Calculate PEG 3350
function calculatePEG3350(){

	var MAX_STEPS = 10;

	if(!validateFin400con3350(document.getElementById('fin400con3350Value'),'infoValFin400Con3350', false)){return false;}
	if(!validateVolume3350(document.getElementById('volume3350PValue'),'infoValVol3350', false)){return false;}
	if(!validateStart3350Con(document.getElementById('start3350conValue'),'infoValStart3350Con', false)){return false;}
	if(!validateFin3350Con(document.getElementById('fin3350conValue'),'infoValFin3350Con', false)){return false;}
	if(!validateSteps3350(document.getElementById('steps3350Value'),'infoValSteps3350', false)){return false;}
	
	// Dim v As Double     'volume in liters
    // Dim m As Double     'litres of 400 to add
    // Dim n As Double     'kilos of 3350 to add
    // Dim r As Double     'litres of solution to remove
    
    // Dim rr As Double    'Original common factor
    // Dim f1 As Double    'common factor 1
    // Dim f2 As Double    'common factor 2
    // Dim f3 As Double    'common factor 3
    
    // Dim c1 As Double    'These values are being used temporarily to match the Original Program to
    // Dim c2 As Double    'make it easier to confirm the formulas match
    // Dim cn As Double
	
	var v = getValue('volume3350PValue');
	var m;
	var n;
	var r;
	
	var rr;
	var f1;
	var f2;
	var f3;
	
	var c1 = getValue('fin400con3350Value');
	var c2;
	var cn;
	
	c1 = c1 / 100;
	
	var start3350con = getValue('start3350conValue');
	var fin3350con = getValue('fin3350conValue');
	var steps = getValue('steps3350Value');
	
	if(steps > MAX_STEPS){steps = MAX_STEPS;}
	
	var current=new Array(MAX_STEPS);
	var desired=new Array(MAX_STEPS);
	var remove=new Array(MAX_STEPS);
	var add3350=new Array(MAX_STEPS);
	var add400=new Array(MAX_STEPS);

	
	current[0] = start3350con;
	
	var dIncr = (fin3350con - current[0])/steps; 
	
	
	for(i=0; i < steps; i++) {
		desired[i] = current[0] + (i+1) * dIncr;
	}
	
	for(i=0; i < MAX_STEPS; i++){
		c2 = current[i] / 100;
		cn = desired[i] / 100;
            
		f1 = 1 - c1 - (c2 / 1.072); 	
		f2 = 1.072 * f1;
		f3 = c2 / f2;
		
		r = (cn - c2) * v / 1.072 * (1 + c1 / f1 + f3);      //litres to remove
		n = (cn - c2) * v * (1 + f3);                        //kilos of 3350 to add
		m = (cn - c2) * v * c1 / f2;                         //litres of 400 to add
		
		// f1 = 1 - c1 - (c2 / 1.072)  'Original rr with the effect of percent in c1 and c2 removed
		// f2 = 1.072 * f1             'a common factor
		// f3 = c2 / f2                'a common factor
		
		// r = (cn - c2) * v / 1.072 * (1 + c1 / f1 + f3)      'litres to remove
		// n = (cn - c2) * v * (1 + f3)                        'kilos of 3350 to add
		// m = (cn - c2) * v * c1 / f2                         'litres of 400 to add
		
		remove[i] = r;
		add3350[i] = n;
		add400[i] = m;
		
		current[i + 1] = desired[i];
	}
	
	
	var strOut;

	if(getLanguage() == "fre"){
		strOut = "<table><td>Actuelle % p/v</td><td>D" + charCode(233) + "sir"+ charCode(233) + "e % p/v</td><td>Enlever L</td><td>Ajouter 3350 kg</td><td>Ajouter 400 L</td></tr>";
	}
	else{
		strOut = "<table><td>Current % w/v</td><td>Desired % w/v</td><td>Remove L</td><td>Add 3350 kg</td><td>Add 400 L</td></tr>";
	}
	
	for(i=0; i < steps; i++){
		strOut = strOut + "<tr><td>" + formatNum(current[i]) + "</td><td>" + formatNum(desired[i]) + "</td><td>" + formatNum(remove[i]) + "</td><td>" + formatNum(add3350[i]) + "</td><td>" + formatNum(add400[i]) + "</td></tr>";
	}
	
	strOut = strOut + "</table>";
	insertTableData(strOut, "PEG3350Table");
}

function clearPEG3350(){ 
	msgOut('infoValFin400Con3350','');
	msgOut('infoValVol3350','');
	msgOut('infoValStart3350Con','');
	msgOut('infoValFin3350Con','');
	msgOut('infoValSteps3350','');

	setValue('volume3350PValue', '');
	setValue('fin400con3350Value', '');
	setValue('start3350conValue', '');
	setValue('fin3350conValue', '');
	setValue('steps3350Value', '');
	
	insertTableData('', "PEG3350Table");
}


//*****************************************
//General Use Functions
//*****************************************

function charCode(x){
	return String.fromCharCode(x);
}

function formatNum(x){
	if(isNaN(x) || x == undefined){return " ";}

	return x.toFixed(2).toString();
}

function formatNum3(x){
	if(isNaN(x) || x == undefined){return " ";}

	return x.toFixed(5).toString();
}

//Common functions
function getValue(id){
	return parseFloat(document.getElementById(id).value);
}

function setValue(id, val){
	document.getElementById(id).value = val;
}

function Int(num){
	num = num.toString();
	num = parseInt(num);
	if(num<0){num = num - 1;} //TODO: dont minus whole numbers
	return num;
}

//inserts the display data into the page
function insertTableData(str, id){
	var p = document.getElementById(id);
	p.innerHTML = str;

	return;
}