// JavaScript Document
<!-- 
	/* Author: Richard Laffers
	 * Some rights reserved. Creative Commons.
	 */	 
	function clearResults() {
		document.getElementById("errorMsg").style.display = "none";
		document.getElementById("resultMsg").style.display = "none";
	}
	/* Variables for handling units */
	var numUnit;  //Global. Function formatNumber() works with this variable. Default unit is one, i.e. standard SI unit. Function diluteSolution() uses the value of numUnit
	function insertUnits(one, milli, micro, nano) {
		// object constructor used for creating an array of units ("units") for conversion operations
		this.one = one;
		this.milli = milli;
		this.micro = micro;
		this.nano = nano;
	}
	//
	var units = new Array();
		units["weight"] = new insertUnits("kg", "g", "mg", "ug");
		units["volume"] = new insertUnits("L", "mL", "ul", "nL");
		units["molality"] = new insertUnits("mol/kg", "mmol/kg", "umol/kg", "nmol/kg");
	//
	var invalidFormat = false;  //this global is for checkNumber()
	//
	function checkNumber(num, boxId) {
		document.getElementById(boxId).style.backgroundColor = "";
		var numPattern = "^[0-9]*[.]?[0-9]*$";
		if(!num.match(numPattern)) {
			if(!invalidFormat) invalidFormat = true;  //if it was still false, it becomes true
			document.getElementById(boxId).style.backgroundColor = "#FFCFD5";
		}
	}
	//
	function whatIsUnit(str) {
		var pattern1 = "^.?molal$";
		var pattern2 = "^.?molar$";
		if(str.match(pattern1)) return "molal";
		if(str.match(pattern2)) {
			return "molar";
		} else {
			//unexpected error
			return false;
		}
	}
	//
	function whatCalculationToUse(str1,str2) {
		var pattern1 = "^.?molal$";
		var pattern2 = "^.?molar$";
		if(str1.match(pattern1) && str2.match(pattern1)) {
			// both are molalities
			return 1;
		}
		if(str1.match(pattern2) && str2.match(pattern2)) {
			// both are molarities
			return 2;
		}
		if(str1.match(pattern2) && str2.match(pattern1)) {
			// molarity --> molality
			return 3;
		} 
		if(str1.match(pattern1) && str2.match(pattern2)) {
			// molality --> molarity
			return 4;
		}
		else {
			// not supported or unexpected arguments
			return false;
		}
	}
	//
	function formatNumber(num, digitsToFix) {
		numUnit = "one";  //Global defined earlier. The default is "one" denoting a standard SI unit.
		if(num < 1) {
			num = num * 1000;
			numUnit = "milli";  //milli = gram, mmol, milliliter etc.
		}
		if(num < 1) {
			num = num * 1000;
			numUnit = "micro";  //micro = milligram, umol, microliter etc.
		}
		if(num < 1) {
			num = num * 1000;
			numUnit = "nano";  //nano = microgram, nanomol, nanoliter etc.
		} 
		if(digitsToFix) {
			var num = new Number(num);
			return num.toFixed(digitsToFix);
		} else {
			// don't fix the digits to the right of the decimal point
			return num;
		}
	}
	//
	function diluteSolution(obj) {		
		var par1 = obj.solA_conc.value; // stock solution concentration
		var par2 = obj.solA_unit.value;  // stock solution concentration unit
		var par3 = obj.molw.value;  // mol. weight of dissolved substance
		var par4 = obj.molw_unit.value;  // mol.weight unit
		var par5 = obj.solB_conc.value;  // desired solution concentration
		var par6 = obj.solB_unit.value;  // desired solution concentration unit
		var par7 = obj.solB_amount.value;  //desired solution amount
		var par8 = obj.solB_amount_unit.value;  //desired solution amount unit
		/* Check that all required parameters were passed */		
		if(isEmpty(par1) || isEmpty(par2) || isEmpty(par3) || isEmpty(par4) || isEmpty(par5) || isEmpty(par6) || isEmpty(par7) || isEmpty(par8)) {
			alert("Please enter all required parameters");
			clearResults();
			return false;
		}
		/********************/
		/* Validate numbers */
		/********************/
		invalidFormat = false;  //reset the value to false before checking
		checkNumber(par1, "solA_conc");
		checkNumber(par3, "molw");
		checkNumber(par5, "solB_conc");
		checkNumber(par7, "solB_amount");
		if(invalidFormat) {
			alert("Some of the values you entered are invalid. Please enter valid numbers.");
			clearResults();
			return false;
		}
		/************************************/
		/* Convert all units to standard SI */
		/************************************/
		var convFactor = new Array();
		convFactor["molal"] = 1;
		convFactor["mmolal"] = 0.001;
		convFactor["umolal"] = 0.000001;
		convFactor["molar"] = 1;
		convFactor["mmolar"] = 0.001;
		convFactor["umolar"] = 0.000001;
		convFactor["kg"] = 1;
		convFactor["g"] = 0.001;
		convFactor["L"] = 1;
		convFactor["mL"] = 0.001;
		convFactor["uL"] = 0.000001;
		convFactor["gmol"] = 0.001;
		var solA_conc = par1 * convFactor[par2];
		var molw = par3 * convFactor[par4];
		var solB_conc = par5 * convFactor[par6];
		var solB_amount = par7 * convFactor[par8];
		/**************************************************************************/
		/* Compare the concentration values if both numbers are in the same units */
		/**************************************************************************/
		var calculationType = whatCalculationToUse(par2,par6);
		if( (calculationType == 1) || (calculationType == 2) ) {
			if(solB_conc > solA_conc) {
				alert("Target concentration is higher than that of the stock solution.\n Unless you are an alchemist of great skill and power, this is impossible!");
				clearResults();
				return false;
			}
			if(solB_conc == solA_conc) {
				alert("No diluting is necessary. You already have what you want.");
				clearResults();
				return false;
			}
		}
		/****************/
		/* Calculations */
		/****************/
		// molality --> molality
		if(calculationType == 1) {
			var resultSolA_amount = (solB_amount * solB_conc * ((solA_conc * molw) + 1))/(solA_conc * (1 + (solB_conc * molw)));
		}
		// molarity --> molarity
		if(calculationType == 2) {
			var resultSolA_amount = solB_amount * (solB_conc / solA_conc);
		}
		// molarity --> molality
		if(calculationType == 3) {
			var resultSolA_amount = (solB_conc * solB_amount) / (solA_conc * ((molw * solB_conc) + 1));
		} 
		// molality --> molarity
		if(calculationType == 4) {
			var resultSolA_amount = solB_conc * solB_amount * ((1/solA_conc) + molw);
		}
		if(calculationType == false) {
			alert("Not supported!");
			clearResults();
			return false;
		}
		/*************************/
		/* Format the result */
		/*************************/
		var roundResultSolA_amount = formatNumber(resultSolA_amount, 5);  // fix to 5 decimal digits
		if(calculationType == 1 || calculationType == 4) {
			// for molality --> molality/molarity calculations (1., 4.)
			//var roundResultSolA_unit = units["weight"].eval(numUnit); 
			// fix
			if(numUnit == "one") var roundResultSolA_unit = units["weight"].one; 
			if(numUnit == "milli") var roundResultSolA_unit = units["weight"].milli; 
			if(numUnit == "micro") var roundResultSolA_unit = units["weight"].micro; 
			if(numUnit == "nano") var roundResultSolA_unit = units["weight"].nano; 
		} else { 
			// for molarity --> molarity/molality calculations (2., 3.)
			//var roundResultSolA_unit = units["volume"].eval(numUnit);  
			if(numUnit == "one") var roundResultSolA_unit = units["volume"].one; 
			if(numUnit == "milli") var roundResultSolA_unit = units["volume"].milli; 
			if(numUnit == "micro") var roundResultSolA_unit = units["volume"].micro; 
			if(numUnit == "nano") var roundResultSolA_unit = units["volume"].nano; 
		}
		//
		var roundSolB_amount = formatNumber(solB_amount); 
		// solB_unit is the same as it has been entered. Not everything is implemented yet, therefore the restrictions below!!!
		if(calculationType == 2 || calculationType == 4) {
			//for molarity --> molarity calculations (2., 4.)
			//var roundSolB_unit = units["volume"].eval(numUnit);
			if(numUnit == "one") var roundSolB_unit = units["volume"].one; 
			if(numUnit == "milli") var roundSolB_unit = units["volume"].milli; 
			if(numUnit == "micro") var roundSolB_unit = units["volume"].micro; 
			if(numUnit == "nano") var roundSolB_unit = units["volume"].nano; 
		} else {
			//for molality/molarity --> molality calculations (1., 3.)
			//var roundSolB_unit = units["weight"].eval(numUnit);  
			if(numUnit == "one") var roundSolB_unit = units["weight"].one; 
			if(numUnit == "milli") var roundSolB_unit = units["weight"].milli; 
			if(numUnit == "micro") var roundSolB_unit = units["weight"].micro; 
			if(numUnit == "nano") var roundSolB_unit = units["weight"].nano; 
		}
		/**********************/
		/* Display the result */
		/**********************/
		if(navigator.appName == "Microsoft Internet Explorer") alert("To prepare the desired solution, measure "+roundResultSolA_amount+roundResultSolA_unit+" of the stock solution \nand add distilled water up to "+roundSolB_amount+roundSolB_unit+" (total).");
		if(roundResultSolA_amount) {
			document.getElementById("resSolA_amount").value = roundResultSolA_amount;
			document.getElementById("resSolA_unit").childNodes[0].nodeValue = roundResultSolA_unit;
			document.getElementById("totalMass").childNodes[0].nodeValue = roundSolB_amount + " " + roundSolB_unit;
			document.getElementById("resultMsg").style.display = "block";
		} else {
			document.getElementById("errorMsg").style.display = "block";
		}
		return false; //*/
	}
	//-->