www/js/rec_edit.js

Sun, 03 Mar 2019 13:26:28 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 03 Mar 2019 13:26:28 +0100
changeset 311
f6fafccd8a6d
parent 303
98c2afc88780
child 316
82c3bb9a40c2
permissions
-rw-r--r--

Added xml import for fermentables, hops, miscs, yeasts and styles. Fixed update IBU calculation in the editor hop popups.

/*****************************************************************************
 * Copyright (C) 2018-2019
 *
 * Michiel Broek <mbroek at mbse dot eu>
 *
 * This file is part of BMS
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * BrewCloud is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ThermFerm; see the file COPYING.  If not, write to the Free
 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *****************************************************************************/


function createDelElements() {
	$('#eventWindow').jqxWindow({
		theme: theme,
		position: { x: 490, y: 210 },
		width: 300,
		height: 175,
		resizable: false,
		isModal: true,
		modalOpacity: 0.4,
		okButton: $('#delOk'),
		cancelButton: $('#delCancel'),
		initContent: function () {
			$('#delOk').jqxButton({ template: "danger", width: '65px', theme: theme });
			$('#delCancel').jqxButton({ template: "success", width: '65px', theme: theme });
			$('#delCancel').focus();
		}
	});
	$('#eventWindow').jqxWindow('hide');
}


$(document).ready(function () {

	var	to_100 = false;		// Fermentables adjust to 100%
	var	preboil_sg = 0;
//	var	sugarsm = 0;		// Sugars after mash
//	var	sugarsf = 0;		// Sugars after boil
	var     psugar = 0;     	// Percentage real sugars
	var     pcara = 0;      	// Percentage cara/crystal malts
	var	svg = 77;		// Default attenuation
	var	mashkg = 0;		// Malt in mash weight
	var	hop_flavour = 0;
	var	hop_aroma = 0;
	var	mash_infuse = 0;
	var	last_base = '';
	var	last_acid = '';

	var     MMCa = 40.048;
	var     MMMg = 24.305;
	var     MMNa = 22.98976928;
	var     MMCl = 35.453;
	var     MMSO4 = 96.0626;
	var     MMCO3 = 60.01684;
	var     MMHCO3 = 61.01684;
	var     MMCaSO4 = 172.171;
	var     MMCaCl2 = 147.015;
	var     MMCaCO3 = 100.087;
	var     MMMgSO4 = 246.475;
	var     MMNaHCO3 = 84.007;
	var     MMNa2CO3 = 105.996;
	var     MMNaCl = 58.443;
	var     MMCaOH2 = 74.06268;

	var	fermentableRow = 0;
	var	fermentableData = {};
	var	hopRow = 0;
	var	hopData = {};
	var	miscRow = 0;
	var	miscData = {};
	var	yeastRow = 0;
	var	yeastData = {};
	var	mashRow = 0;
	var	mashData = {};

	/*
	 * Remove the top menu so that we MUST use the buttons to leave the editor.
	 */
	$('#jqxMenu').jqxMenu('destroy');

	console.log("record:" + my_record + "  return:" + my_return + "  theme:" + theme);
	$("#jqxLoader").jqxLoader({
		width: 250,
		height: 150,
		isModal: true,
		text: "Laden recept ...",
		theme: theme
	});

	function setReadonly(ro) {
		var rw = ! ro;
		var w100 = 110;
		var w80 = 80;
		if (ro) { // jqxNumberInput width -20 for no spinbuttons
			w100 = 90;
			w80 = 60;
		}
		$("#batch_size").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#boil_size").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#boil_time").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#efficiency").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#est_og").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		// id="st_fg_min" margin-left 15/35 maken
		$("#type").jqxDropDownList({ disabled: ro });
		$("#styleSelect").jqxDropDownList({ disabled: ro });
		$("#color_method").jqxDropDownList({ disabled: ro });
		$("#ibu_method").jqxDropDownList({ disabled: ro });
		$("#Delete").jqxButton({ disabled: ro });
		$("#fermentableGrid").jqxGrid({ editable: rw });
		$("#faddrowbutton").jqxDropDownList({ disabled: ro });
		$("#finstockbutton").jqxCheckBox({ disabled: ro });
		$("#fdeleterowbutton").jqxButton({ disabled: ro });
		$("#hopGrid").jqxGrid({ editable: rw });
		$("#haddrowbutton").jqxDropDownList({ disabled: ro });
		$("#hinstockbutton").jqxCheckBox({ disabled: ro });
		$("#hdeleterowbutton").jqxButton({ disabled: ro });
		$("#miscGrid").jqxGrid({ editable: rw });
		$("#maddrowbutton").jqxDropDownList({ disabled: ro });
		$("#minstockbutton").jqxCheckBox({ disabled: ro });
		$("#mdeleterowbutton").jqxButton({ disabled: ro });
		$("#yeastGrid").jqxGrid({ editable: rw });
		$("#yaddrowbutton").jqxDropDownList({ disabled: ro });
		$("#yinstockbutton").jqxCheckBox({ disabled: ro });
		$("#ydeleterowbutton").jqxButton({ disabled: ro });
		$("#mashGrid").jqxGrid({ editable: rw });
		$("#saddrowbutton").jqxButton({ disabled: ro });
		$("#sdeleterowbutton").jqxButton({ disabled: ro });
		$("#w1_name").jqxDropDownList({ disabled: ro });
		$("#w2_name").jqxDropDownList({ disabled: ro });
		$("#pr_name").jqxDropDownList({ disabled: ro });
		$("#wa_cacl2").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#wa_caso4").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#wa_mgso4").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#wa_nacl").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#mash_ph").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#calc_acid").jqxCheckBox({ disabled: ro });
		$("#wa_base_name").jqxDropDownList({ disabled: ro });
		$("#wa_base").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#wa_acid_name").jqxDropDownList({ disabled: ro });
		$("#wa_acid").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#wa_acid_perc").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w80 });
		$("#sparge_temp").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#sparge_volume").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#sparge_ph").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
		$("#sparge_source").jqxDropDownList({ disabled: ro });
		$("#sparge_acid_type").jqxDropDownList({ disabled: ro });
		$("#sparge_acid_perc").jqxNumberInput({ spinButtons: rw, readOnly: ro, width: w100 });
	};

	function calcFermentables() {
		console.log("calcFermentables()");
		sugarsf = 0;		// fermentable sugars mash + boil
		sugarsm = 0;		// fermentable sugars in mash
		psugar = 0;
		pcara = 0;
		mashkg = 0;
		var vol = 0;		// Volume sugars after boil
		var addedS = 0;		// Added sugars after boil
		var addedmass = 0;	// Added mass after boil
		var mvol = 0;		// mash volume
		var colort = 0;		// Colors srm * vol totals
		var my_100 = false;
		var mashtime = 0;       // Total mash time
		var mashtemp = 0;       // Average mash temperature

		if ((rows = $('#mashGrid').jqxGrid('getrows'))) {
			for (var i = 0; i < rows.length; i++) {
				var row = rows[i];
				if (row.step_type == 0) // Infusion
					mvol += parseFloat(row.step_infuse_amount);
				if (row.step_temp <= 75) { // Ignore mashout
					mashtime += row.step_time;
					mashtemp += row.step_time * row.step_temp;
				}
			}
			mashtemp = mashtemp / mashtime;
		}

		if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
			return; // grid not yet loaded.
		}

		var s = 0;
		for (var i = 0; i < rows.length; i++) {
			var row = rows[i];
			if (row.f_adjust_to_total_100)
				my_100 = true;
			if (row.f_type == 1)		// Sugar
				psugar += row.f_percentage;
			if (row.f_graintype == 2)	// Crystal
				pcara += row.f_percentage;
			var d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
			if (row.f_added == 0) {		// Mash
				if (mvol > 0) { 	// Only if mash already known
					mvol += row.f_amount * row.f_moisture / 100;
					s += d;
				}
				d = parseFloat(dataRecord.efficiency) / 100 * d;
				sugarsm += d;
				mashkg += row.f_amount;
			}
			if (row.f_added == 0 || row.f_added == 1)	// Mash or Boil
				sugarsf += d;
			if (row.f_added == 2 || row.f_added == 3) {
				var x = (row.f_yield / 100) * (1 - row.f_moisture / 100);
				addedS += row.f_amount * x;
				addedmass += row.f_amount;
				vol += (x * sugardensity + (1 - x) * 1) * row.f_amount;
			}
			colort += row.f_amount * ebc_to_srm(row.f_color);
		}
		to_100 = my_100;
		if (to_100) {
			$("#wf_amount").jqxNumberInput({ width: 90, readOnly: true, spinButtons: false  });
		} else {
			$("#wf_amount").jqxNumberInput({ width: 110, readOnly: false, spinButtons: true });
		}

		// Estimate total recipe OG.
		dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size));
		$('#est_og').val(dataRecord.est_og);
		$('#est_og2').val(dataRecord.est_og);

		// Estimate SG in kettle before boil
		preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size));

		// Color of the wort
		var cw = colort / parseFloat(dataRecord.batch_size) * 8.34436;
		var color = kw_to_ebc(dataRecord.color_method, cw);
		dataRecord.est_color = color;
		$('#est_color').val(color);
		$('#est_color2').val(color);
		var scolor = ebc_to_color(color);
		document.getElementById("bcolor").style.background= scolor;
		document.getElementById("bcolor2").style.background= scolor;

		// Progress bars
		pmalts = mashkg / (dataRecord.boil_size / 3) * 100;
		$("#perc_malts").jqxProgressBar('val', pmalts);
		$("#perc_sugars").jqxProgressBar('val', psugar);
		$("#perc_cara").jqxProgressBar('val', pcara);

		// Calculate estimated svg.
		svg = 0; // default.
		var rows = $('#yeastGrid').jqxGrid('getrows');
		for (var i = 0; i < rows.length; i++) {
			var row = rows[i];
			if (row.y_use == 0) {   // Primary
				if (parseFloat(row.y_attenuation) > svg)
					svg = parseFloat(row.y_attenuation);    // Take the highest if multiple yeasts.
			}
			// TODO: brett in secondary ??
		}
		if (svg == 0)
			svg = 77;

		if ((mashkg > 0) && (mash_infuse > 0) && (mashtime > 0) && (mashtemp > 0)) {
			dataRecord.est_fg = estimate_fg(psugar, pcara, mash_infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og);
		} else {
			dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og);
		}
		$('#est_fg').val(dataRecord.est_fg);
		$('#est_fg2').val(dataRecord.est_fg);

		dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg);
		$("#est_abv").val(dataRecord.est_abv);
		$("#est_abv2").val(dataRecord.est_abv);
	};

	function hopFlavourContribution(bt, vol, use, amount) {
		var result;

		if (use == 1) {	// First wort
			result = 0.15;		// assume 15% flavourcontribution for fwh
		} else if (bt > 50) {
			result = 0.10;		// assume 10% flavourcontribution as a minimum
		} else {
			result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) /6, 2));
			if (result < 0.10)
				result = 0.10;	// assume 10% flavourcontribution as a minimum
		}
		result = (result * amount * 1000) / vol;
	//	console.log("hopFlavourContribution("+bt+","+vol+","+use+","+amount+"): "+result);
		return result;
	}

	function hopAromaContribution(bt, vol, use, amount) {
		var result = 0;

		if (bt > 20) {
			result = 0;
		} else if (bt > 7.5) {
			result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) /4, 2));
		} else if (use == 2) {	// Boil
			result = 1;
		} else if (use == 3) {	// Aroma / vlamuit
			result = 1.2;
		} else if (use == 4) { // Whirlpool
			result = 1.2;
		} else if (use == 5) {	// Dry hop
			result = 1.33;
		}
		result = (result * amount * 1000) / vol;
	//	console.log("hopAromaContribution("+bt+","+vol+","+use+","+amount+"): "+result);
		return result;
	}

	function calcIBUs() {
		var total_ibus = 0;
		hop_aroma = hop_flavour = 0;
		var rows = $('#hopGrid').jqxGrid('getrows');
		for (var i = 0; i < rows.length; i++) {
			var row = rows[i];
			total_ibus += toIBU(row.h_useat, row.h_form, preboil_sg, parseFloat(dataRecord.batch_size),
					parseFloat(row.h_amount), parseFloat(row.h_time), parseFloat(row.h_alpha), dataRecord.ibu_method);
			hop_flavour += hopFlavourContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size),
						row.h_useat, parseFloat(row.h_amount));
			hop_aroma += hopAromaContribution(parseFloat(row.h_time), parseFloat(dataRecord.batch_size),
					        row.h_useat, parseFloat(row.h_amount));
		}
		total_ibus = Math.round(total_ibus);
		console.log("calcIBUs(): " + total_ibus + "  flavour: " + hop_flavour + "  aroma: " + hop_aroma);
		dataRecord.est_ibu = total_ibus;
		$('#est_ibu').val(total_ibus);
		$('#est_ibu2').val(total_ibus);
		$("#hop_flavour").jqxProgressBar('val', hop_flavour * 10);
		$("#hop_aroma").jqxProgressBar('val', hop_aroma * 10);
	};

	function adjustHops(factor) {

		console.log("adjustHops("+factor+")");

		var rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount;
		if (rowscount == 0)
			return;

		for (var i = 0; i < rowscount; i++) {
			var row = $("#hopGrid").jqxGrid('getrowdata', i);
			var amount = row.h_amount * factor;
			$("#hopGrid").jqxGrid('setcellvalue', i, "h_amount", amount);
		}
	};

	function adjustMiscs(factor) {

		console.log("adjustMiscs("+factor+")");

		var rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount;
		if (rowscount == 0)
			return;

		for (var i = 0; i < rowscount; i++) {
			var row = $("#miscGrid").jqxGrid('getrowdata', i);
			var amount = row.m_amount * factor;
			$("#miscGrid").jqxGrid('setcellvalue', i, "m_amount", amount);
			switch (row.m_name) {
				case 'CaCl2':           $("#wa_cacl2").val(row.m_amount * 1000);
							break;
				case 'CaSO4':           $("#wa_caso4").val(row.m_amount * 1000);
							break;
				case 'MgSO4':           $("#wa_mgso4").val(row.m_amount * 1000);
							break;
				case 'NaCl':            $("#wa_nacl").val(row.m_amount * 1000);
							break;
				case 'Melkzuur':
				case 'Zoutzuur':
				case 'Fosforzuur':
				case 'Zwavelzuur':      $("#wa_acid").val(row.m_amount * 1000);
							break;
				case 'NaHCO3':
				case 'Na2CO3':
				case 'CaCO3':
				case 'Ca(OH)2':         $("#wa_base").val(row.m_amount * 1000);
							break;
			}
		}
	};

	function adjustYeasts(factor) {

		console.log("adjustYeasts("+factor+")");

		var rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount;
		if (rowscount == 0)
			return;

		for (var i = 0; i < rowscount; i++) {
			var row = $("#yeastGrid").jqxGrid('getrowdata', i);
			if (row.y_form == 1) { // Only adjust dry yeast
				var amount = row.y_amount * factor;
				$("#yeastGrid").jqxGrid('setcellvalue', i, "y_amount", amount);
			}
		}
	};

	function adjustWaters(factor) {

		console.log("adjustWaters("+factor+")");

		var rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount;
		if (rowscount == 0)
			return;

		mash_infuse = 0;
		for (var i = 0; i < rowscount; i++) {
			var row = $("#mashGrid").jqxGrid('getrowdata', i);
			if (row.step_type == 0) { // Infusion
				var amount = Math.round(row.step_infuse_amount * factor * 10) / 10;
				$("#mashGrid").jqxGrid('setcellvalue', i, "step_infuse_amount", amount);
				mash_infuse += amount;
			}
		}
		if (dataRecord.w2_amount == 0) {
			dataRecord.w1_amount = mash_infuse;
			$("#w1_amount").val(mash_infuse);
		} else {
			dataRecord.w1_amount = (dataRecord.w1_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse;
			dataRecord.w2_amount = (dataRecord.w2_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse;
			$("#w1_amount").val(dataRecord.w1_amount);
			$("#w2_amount").val(dataRecord.w2_amount);
		}
		$('#wg_amount').val(mash_infuse);
	};

/*	function GetBUGUMin() {

		var Result = 0;

		if (((dataRecord.st_og_max + dataRecord.st_og_min) > 0) && ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) > 0)) {
			var G = (dataRecord.st_og_max - dataRecord.st_og_min) / ((dataRecord.st_og_max + dataRecord.st_og_min) / 2);
			var B = (dataRecord.st_ibu_max - dataRecord.st_ibu_min) / ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) / 2);
			if (G > B)
				Result = ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) / 2) / (1000 * (dataRecord.st_og_max - 1));
			else
				Result = dataRecord.st_ibu_min / (1000 * (((dataRecord.st_og_max + dataRecord.st_og_min) / 2) - 1));
		}
		console.log("GetBUGUMin(): "+Result);
		return Result;
	}

	function GetBUGUMax() {

		var Result = 0;

		if (((dataRecord.st_og_max + dataRecord.st_og_min) > 0) && ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) > 0) && (dataRecord.st_og_min > 0)) {
			var G = (dataRecord.st_og_max - dataRecord.st_og_min) / ((dataRecord.st_og_max + dataRecord.st_og_min) / 2);
			var B = (dataRecord.st_ibu_max - dataRecord.st_ibu_min) / ((dataRecord.st_ibu_max + dataRecord.st_ibu_min) / 2);
			if (G > B)
				Result = ((dataRecord.st_ibu_min + dataRecord.st_ibu_max) / 2) / (1000 * (dataRecord.st_og_min - 1));
			else
				Result = dataRecord.st_ibu_max / (1000 * (((dataRecord.st_og_max + dataRecord.st_og_min) / 2) - 1));

		}
		console.log("GetBUGUMax(): "+Result);
		return Result;
	} */

	function GetBUGU() {
		var gu = (dataRecord.est_og - 1) * 1000;
		if (gu > 0)
			return dataRecord.est_ibu / gu;
		else
			return 0.5;
	}

	function GetOptClSO4ratio() {
		var BUGU = GetBUGU();
		return (-1.2 * BUGU + 1.4);
	}

	function setWaterAgent(name, amount) {
		console.log("setWaterAgent(" + name + ", " + amount + ")");
		var rows = $('#miscGrid').jqxGrid('getrows');
		if (amount == 0) {
			for (var i = 0; i < rows.length; i++) {
				var row = rows[i];
				if (row.m_name == name) {
					var id = $("#miscGrid").jqxGrid('getrowid', i);
					var commit = $("#miscGrid").jqxGrid('deleterow', id);
				}
			}
		} else {
			var found = false;
			for (var i = 0; i < rows.length; i++) {
				var row = rows[i];
				if (row.m_name == name) {
					found = true;
					$("#miscGrid").jqxGrid('setcellvalue', i, 'm_amount', amount / 1000);
					break;
				}
			}
			if (! found) {
				var miscs = new $.jqx.dataAdapter(miscInvSource, {
					loadComplete: function () {
						var records = miscs.records;
						for (var i = 0; i < records.length; i++) {
							var record = records[i];
							if (record.name == name) {
								var row = {};
								row["m_name"] = record.name;
								row["m_amount"] = amount / 1000;
								row["m_cost"] = record.cost;
								row["m_type"] = record.type;
								row["m_use_use"] = record.use_use;
								row["m_time"] = 0;
								row["m_amount_is_weight"] = record.amount_is_weight;
								row["m_inventory"] = record.inventory;
								row["m_avail"] = 1;
								var commit = $("#miscGrid").jqxGrid('addrow', null, row);
							}
						}
					}
				});
				miscs.dataBind();
				return;
			}
		}
	}

	function setRangeIndicator(ion, rangeCode) {
		if (rangeCode == "low")
			$("#wr_"+ion).html("<img src='images/dialog-error.png'><span style='font-size: 10px; font-style: italic;'>"+rangeCode + "</span>");
		else if (rangeCode == "high")
			$("#wr_"+ion).html("<img src='images/dialog-error.png'><span style='font-size: 10px; font-style: italic;'>"+rangeCode+"</span>");
		else
			$("#wr_"+ion).html("<img src='images/dialog-ok-apply.png'>");
	}

	function mix(v1, v2, c1, c2) {
		if ((v1 + v2) > 0) {
			return ((v1 * c1) + (v2 * c2)) / (v1 + v2);
		}
		return 0;
	}

	// mg/l as CaCO3
	function ResidualAlkalinity(total_alkalinity, calcium, magnesium) {
		return total_alkalinity - (calcium / 1.4 + magnesium / 1.7);
	}

	var Ka1 = 0.0000004445;
	var Ka2 = 0.0000000000468;

	function PartCO3(pH) {
		var H = Math.pow(10, -pH);
		return 100 * Ka1 * Ka2 / (H*H + H * Ka1 + Ka1 * Ka2);
	}

	function PartHCO3(pH) {
		var H = Math.pow(10, -pH);
		return 100 * Ka1 * H / (H*H + H * Ka1 + Ka1 * Ka2);
	}

	function Charge(pH) {
		return (-2 * PartCO3(pH) - PartHCO3(pH));
	}

	//Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH)
	function ZAlkalinity(pHZ) {
		var C43 = Charge(4.3);
		var Cw = Charge(parseFloat($("#wg_ph").jqxNumberInput('decimal')));
		var Cz = Charge(pHZ);
		var DeltaCNaught = -C43+Cw;
		var CT = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal')) / 50 / DeltaCNaught;
		var DeltaCZ = -Cz+Cw;
		return CT * DeltaCZ;
	}

	//Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH)
	function ZRA(pHZ) {

		var Calc = parseFloat($("#wg_calcium").jqxNumberInput('decimal')) / (MMCa / 2);
		var Magn = parseFloat($("#wg_magnesium").jqxNumberInput('decimal')) / (MMMg / 2);
		var Z = ZAlkalinity(pHZ);
		return Z - (Calc / 3.5 + Magn / 7);
	}

	function ProtonDeficit(pHZ) {

		var Result = ZRA(pHZ) * parseFloat($("#wg_amount").jqxNumberInput('decimal'));
		// proton deficit for the grist
		var rows = $('#fermentableGrid').jqxGrid('getrows');
		for (var i = 0; i < rows.length; i++) {
			var row = rows[i];
			if (row.f_added == 0 && row.f_graintype != 6) {	// Added == Mash && graintype != No Malt
				// Check if acid is required
				var C1 = 0;
				if ((row.f_di_ph != 5.7) && ((row.f_acid_to_ph_57 < - 0.1) || (row.f_acid_to_ph_57 > 0.1))) {
					C1 = row.f_acid_to_ph_57 / (row.f_di_ph - 5.7);
				} else {
					// If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid.
					var ebc = row.f_color;
					switch (row.f_graintype) {
						case 0:					// Base, Special, Kilned
						case 3:
						case 5:	C1 = 0.014 * ebc - 34.192;
							break;
						case 2:	C1 = -0.0597 * ebc - 32.457;	// Crystal
							break;
						case 1:	C1 = 0.0107 * ebc - 54.768;	// Roast
							break;
						case 4:	C1 = -149;			// Sour malt
							break;
					}
				}
				x = C1 * (pHZ - row.f_di_ph);	// AcidRequired(ZpH)
	//			console.log(row.f_name+" C1: "+C1+" ZpH: "+pHZ+" di_ph: "+row.f_di_ph+" acid rquired: "+x);
				Result += x * row.f_amount;
			}
		}
	//	console.log("Final: "+Result);
		return Result;
	}

	function MashpH() {
		var n = 0;
		var pH = 5.4;
		var deltapH = 0.001;
		var deltapd = 0.1;
		var pd = ProtonDeficit(pH);
		while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) {
			n++;
			if (pd < -deltapd)
				pH -= deltapH;
			else if (pd > deltapd)
				pH += deltapH;
			pd = ProtonDeficit(pH);
		}
		console.log("MashpH() n: "+n+" pH: "+pH);
		return pH;
	}

	function GetAcidSpecs(AT) {
		switch(AT) {
			case 0:	return {	// Melkzuur
					pK1: 3.08,
					pK2: 20,
					pK3: 20,
					MolWt: 90.08,
					AcidSG: 1214,
					AcidPrc: 0.88
				};
			case 1:	return {	// Zoutzuur
					pK1: -10,
					pK2: 20,
					pK3: 20,
					MolWt: 36.46,
					AcidSG: 1142,
					AcidPrc: 0.28
				};
			case 2:	return {	// Fosforzuur
					pK1: 2.12,
					pK2: 7.20,
					pK3: 12.44,
					MolWt: 98.00,
					AcidSG: 1170,
					AcidPrc: 0.25
				};
			case 3:	return {	// Zwavelzuur
					pK1: -10,
					pK2: 1.92,
					pK3: 20,
					MolWt: 98.07,
					AcidSG: 1700,
					AcidPrc: 0.93
				};
		}
		console.log("Bummer, AT is " + AT);
	}

	// Procedure TFrmWaterAdjustment.CalcWater2;
	function calcWater() {

		console.log("calcWater()");
		var liters = 0;
		var calcium = 0;
		var magnesium = 0;
		var sodium = 0;
		var total_alkalinity = 0;
		var bicarbonate = 0;
		var chloride = 0;
		var sulfate = 0;
		var ph = 0;
		var RA = 0;
		var acid = 0;
		var frac = 0;
		var TpH = 0;
		var protonDeficit = 0;

		if (dataRecord.w1_name == "") {
			return;
		}
		// Check for a recipe too. Fermentables, Mash schedule?

		// If there is a dillute water source, mix the waters.
		if (dataRecord.w2_name != "") {
			liters = dataRecord.w1_amount + dataRecord.w2_amount;
			calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium);
			magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium);
			sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium);
			chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride);
			sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate);
			total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity);
			ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount))  / liters);
		} else {
			liters = dataRecord.w1_amount;
			calcium = dataRecord.w1_calcium;
			magnesium = dataRecord.w1_magnesium;
			sodium = dataRecord.w1_sodium;
			chloride = dataRecord.w1_chloride;
			sulfate = dataRecord.w1_sulfate;
			total_alkalinity = dataRecord.w1_total_alkalinity;
			ph = dataRecord.w1_ph;
		}
		$('#wg_amount').val(liters);
		var wg_calcium = calcium;
		$('#wg_calcium').val(Math.round(calcium * 10) / 10);
		var wg_magnesium = magnesium;
		$('#wg_magnesium').val(Math.round(magnesium * 10) / 10);
		var wg_sodium = sodium;
		$('#wg_sodium').val(Math.round(sodium * 10) / 10);
		var wg_total_alkalinity = total_alkalinity;
		$('#wg_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10);
		var wg_chloride = chloride;
		$('#wg_chloride').val(Math.round(chloride * 10) / 10);
		var wg_sulfate = sulfate;
		$('#wg_sulfate').val(Math.round(sulfate * 10) / 10);
		// Note: brouwhulp has the malts included here in the result.
		var wg_ph = ph;
		$('#wg_ph').val(Math.round(ph * 10) / 10);
		$('#wb_ph').val(Math.round(MashpH() * 10) / 10);
		bicarbonate = total_alkalinity * 1.22;
		var wg_bicarbonate = bicarbonate;

		// Noot: de volgende berekeningen geven bijna gelijke resultaten in Brun'water.
		// Calculate Ca
		RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
		     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4;
		calcium += 1000 * RA / liters;

		// Calculate Mg
		RA = parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMMg / MMMgSO4;
		magnesium += 1000 * RA / liters;

		// Calculate Na
		RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl;
		sodium += 1000 * RA / liters;

		// Calculate SO4
		RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
		     parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4;
		sulfate += 1000 * RA / liters;

		// Calculate Cl
		RA = 2 * parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
		     parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl;
		chloride += 1000 * RA / liters;
		// Einde noot.

		if ($("#wa_acid_name").val() < 0 || $("#wa_acid_name").val() > 3) {
			console.log("fix wa_acid_name");
			$("#wa_acid_name").val(0);
			dataRecord.wa_acid_name = 0;
		}
		if (last_acid == '')
			last_acid = AcidTypeData[$("#wa_acid_name").val()].nl;

		if ($("#wa_base_name").val() < 0 || $("#wa_base_name").val() > 3) {
			console.log("fix wa_base_name");
			$("#wa_base_name").val(0);
			dataRecord.wa_base_name = 0;
		}
		if (last_base == '')
			last_base = BaseTypeData[$("#wa_base_name").val()].nl;

		var AT = dataRecord.wa_acid_name; // parseFloat($("#wa_acid_name").jqxNumberInput('decimal'));
		var BT = dataRecord.wa_base_name; //parseFloat($("#wa_base_name").jqxNumberInput('decimal'));

		var result = GetAcidSpecs(AT);
		var pK1 = result.pK1;
		var pK2 = result.pK2;
		var pK3 = result.pK3;
		var MolWt = result.MolWt;
		var AcidSG = result.AcidSG;
		var AcidPrc = result.AcidPrc;

		if (dataRecord.calc_acid) {
			TpH = parseFloat(dataRecord.mash_ph);
			protonDeficit = ProtonDeficit(TpH);
			console.log("calc_acid tgt: "+TpH+" protonDeficit: "+protonDeficit);
			if (protonDeficit > 0) { // Add acid
				$("#wa_base").val(0);
				setWaterAgent(last_base, 0);
				frac = CalcFrac(TpH, pK1, pK2, pK3);
				Acid = protonDeficit / frac;
				Acid *= MolWt; // mg
				Acidmg = Acid;
				Acid = Acid / AcidSG; // ml

				if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0)
					$("#wa_acid_perc").val(AcidPrc);
				Acid = Acid * AcidPrc / (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
				console.log("Final ml: "+Acid);
				$("#wa_acid").val(Math.round(Acid * 100) / 100);
				setWaterAgent(AcidTypeData[AT].nl, Math.round(Acid * 100) / 100);

				bicarbonate = bicarbonate - protonDeficit * frac / liters;
				total_alkalinity = bicarbonate * 50 / 61;
			} else if (protonDeficit < 0) { //Add base
				$("#wa_acid").val(0);
				setWaterAgent(last_acid, 0);
				var r1d = Math.pow(10, (TpH - 6.38));
				var r2d = Math.pow(10, (TpH - 10.38));
				var f1d = 1 / (1 + r1d + r1d * r2d);
				var f2d = f1d * r1d;
				var f3d = f2d * r2d;
				switch (BT) {
					case 0:	RA = -protonDeficit / (f1d - f3d); //Sodiumbicarbonate, mmol totaal
						RA = RA * MMNaHCO3/1000; //gram
						$("#wa_base").val(Math.round(RA * 100) / 100);
						setWaterAgent('NaHCO3', Math.round(RA * 100) / 100);
						if (liters > 0) {
							// Na
							RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
							RA = 1000 * RA / liters;
							sodium = wg_sodium + RA;
							// HCO3
							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
							RA = 1000 * RA / liters;
							bicarbonate = wg_bicarbonate + RA;
							total_alkalinity = bicarbonate * 50 / 61;
							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
						}
						break;
					case 1:	RA = -protonDeficit / (2 * f1d + f2d); // Sodiumcarbonate, mmol totaal
						RA = RA * MMNa2CO3/1000; //gram
						$("#wa_base").val(Math.round(RA * 100) / 100);
						setWaterAgent('Na2CO3', Math.round(RA * 100) / 100);
						if (liters > 0) {
							RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
							RA = 1000 * RA / liters;
							sodium = wg_sodium + RA;
							// HCO3
							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
							RA = 1000 * RA / liters;
							bicarbonate = wg_bicarbonate + RA;
							total_alkalinity = bicarbonate * 50 / 61;
							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
						}
						break;
					case 2:	RA = -protonDeficit * (f1d - f3d); // Calciumcarbonate, mmol totaal
						RA = RA * MMCaCO3/1000; //gram
						//but only 1/3 is effective, so add 3 times as much
						RA = 3 * RA;
						$("#wa_base").val(Math.round(RA * 100) / 100);
						setWaterAgent('CaCO3', Math.round(RA * 100) / 100);
						if (liters > 0) {
							//Bicarbonate
							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
							RA = 1000 * RA / liters;
							bicarbonate = wg_bicarbonate + RA;
							total_alkalinity = bicarbonate * 50 / 61;
							//Ca precipitates out as Ca10(PO4)6(OH)2
							RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
							     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
							RA = 1000 * RA / liters;
							calcium = wg_calcium + RA;
							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
						}
						break;
					case 3:	RA = -protonDeficit / 19.3; // Calciumhydroxide
						$("#wa_base").val(Math.round(RA * 100) / 100);
						setWaterAgent('Ca(OH)2', Math.round(RA * 100) / 100);
						if (liters > 0) {
							// Bicarbonate
							RA = -protonDeficit / liters;
							total_alkalinity = wg_total_alkalinity + RA;
							bicarbonate = total_alkalinity * 61 / 50;
							// Calcium
							RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
							     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaOH2;
							RA = 1000 * RA / liters;
							calcium = wg_calcium + RA;
							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
						}
						break;
				}
			}
			ph = TpH;
			$('#wb_ph').val(Math.round(ph * 10) / 10);
		} else { // Manual
			console.log("calc_acid no");
			// First add base salts
			if (parseFloat($("#wa_base").jqxNumberInput('decimal')) > 0) {
				if (liters > 0) {
					switch (BT) {
						case 0:	// Sodiumbicarbonate, Na
							RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
							RA = 1000 * RA / liters;
							sodium = wg_sodium + RA;
							// HCO3
							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3;
							RA = 1000 * RA / liters;
							bicarbonate = wg_bicarbonate + RA;
							total_alkalinity = bicarbonate * 50 / 61;
							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
							break;
						case 1:	// Sodiumcarbonate
							RA = parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMNa / MMNaCl +
							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * 2 * MMNa / MMNa2CO3;
							RA = 1000 * RA / liters;
							sodium = wg_sodium + RA;
							// HCO3
							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMHCO3 / MMNa2CO3;
							RA = 1000 * RA / liters;
							bicarbonate = wg_bicarbonate + RA;
							total_alkalinity = bicarbonate * 50 / 61;
							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
							break;
						case 2:	// Calciumcarbonate: Bicarbonate
							RA = parseFloat($("#wa_base").jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3;
							RA = 1000 * RA / liters;
							bicarbonate = wg_bicarbonate + RA;
							total_alkalinity = bicarbonate * 50 / 61;
							RA = ResidualAlkalinity(wb_total_alkalinity, wb_calcium, wb_magnesium);
							// Ca
							RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCa / MMCaCl2 +
							     parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMCa / MMCaSO4 +
							     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMCa / MMCaCO3;
							RA = 1000 * RA / liters;
							calcium = wg_calcium + RA;
							break;
					}
				}
			}

			TpH = parseFloat(dataRecord.mash_ph);
			pHa = MashpH();	// This one is in demi water, should be in adjusted water???
			// Then calculate the new pH with added acids
			if (parseFloat($("#wa_acid").jqxNumberInput('decimal')) > 0) {
				console.log("TpH: "+TpH+" water: "+pHa);
				Acid = parseFloat($("#wa_acid").jqxNumberInput('decimal'));
				if (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) == 0)
					$("#wa_acid_perc").val(AcidPrc);
				Acid = Acid / AcidPrc * (parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')) / 100); // ml
				Acid *= AcidSG; // ml
				Acid /= MolWt;  // mg
				Acidmg = Acid;

				//find the pH where the protondeficit = protondeficit by the acid
				frac = CalcFrac(pHa, pK1, pK2, pK3);
				protonDeficit = Acid * frac;

				var deltapH = 0.001;
				var deltapd = 0.1;
				var pd = ProtonDeficit(pHa);
				var n = 0;
		//		console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa);

				while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 2000)) {
					n++;
					if (pd < (protonDeficit-deltapd))
						pHa -= deltapH;
					else if (pd > (protonDeficit+deltapd))
						pHa += deltapH;
					frac = CalcFrac(pHa, pK1, pK2, pK3);
					protonDeficit = Acid * frac;
					pd = ProtonDeficit(pHa);
				}
				console.log("n: "+n+" pd: "+pd+" protonDeficit: "+protonDeficit+" frac: "+frac+" pHa: "+pHa);
				RA = wg_bicarbonate - protonDeficit * frac / liters;
				bicarbonate = RA;
				total_alkalinity = RA * 50 / 61;
				ph = pHa;
				$('#wb_ph').val(Math.round(ph * 10) / 10);
			}
		}

		if ((AT == 3) && (liters > 0)) {	// Sulfuctic / Zwavelzuur
			RA = parseFloat($("#wa_caso4").jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
			     parseFloat($("#wa_mgso4").jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 +
			     Acidmg / 1000 * MMSO4 / (MMSO4 + 2);
			RA = 1000 * RA / liters;
			sulfate = wg_sulfate + RA;	// Not add to sulfate??
		} else if ((AT == 1) && (liters > 0)) {	// Hydrochloric, Zoutzuur
			RA = parseFloat($("#wa_cacl2").jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
			     parseFloat($("#wa_nacl").jqxNumberInput('decimal')) * MMCl / MMNaCl +
			     Acidmg / 1000 * MMCl / (MMCl + 1);
			RA = 1000 * RA / liters;
			chloride = wg_chloride + RA;
		}

		// 2:1 Sulfate to Chroride IPA's, Pale Ales.
		// 1:1 Sulfate to Chloride Balanced
		// 1:2 Sulfate to Chloride Malty
		$('#tgt_bu').val(Math.round(GetBUGU() * 100) / 100);
		$('#tgt_cl_so4').val(Math.round(GetOptClSO4ratio() * 10) / 10);	// Show real value too
		if (sulfate > 0)
			RA = chloride / sulfate;
		else
			RA = 10;
		var piCLSO4_low = 0.8 * GetOptClSO4ratio();
		var piCLSO4_high = 1.2 * GetOptClSO4ratio();
		console.log("low: "+piCLSO4_low+" val: "+RA+" high: "+piCLSO4_high);

                $('#wb_calcium').val(Math.round(calcium * 10) / 10);
                $('#wb_magnesium').val(Math.round(magnesium * 10) / 10);
                $('#wb_sodium').val(Math.round(sodium * 10) / 10);
                $('#wb_sulfate').val(Math.round(sulfate * 10) / 10);
                $('#wb_chloride').val(Math.round(chloride * 10) / 10);
		$('#wb_total_alkalinity').val(Math.round(total_alkalinity * 10) / 10);

                if (calcium < 40) {
			setRangeIndicator("calcium", "low");
		} else if (calcium > 150) {
			setRangeIndicator("calcium", "high");
		} else {
			setRangeIndicator("calcium", "normal");
		}
                if (magnesium >= 0 && magnesium <= 30) {
			setRangeIndicator("magnesium", "normal");
		} else {
			setRangeIndicator("magnesium", "high");
		}
                if (sodium <= 150) {
			setRangeIndicator("sodium", "normal");
		} else {
			setRangeIndicator("sodium", "high");
		}
                if (chloride <= 100) {
			setRangeIndicator("chloride", "normal");
		} else {
			setRangeIndicator("chloride", "high");
		}
                if (sulfate <= 350) {
			setRangeIndicator("sulfate", "normal");
		} else {
			setRangeIndicator("sulfate", "high");
		}
		if (ph < 5.2) {
			setRangeIndicator("ph", "low");
		} else if (ph > 5.6) {
			setRangeIndicator("ph", "high");
		} else {
			setRangeIndicator("ph", "normal");
		}
		calcSparge();
	}

	function calcSparge() {

		// Code from BrewBuddy/Brouwhulp, who got it from http://www.brewery.org/brewery/library/Acidi0,00fWaterAJD0497.html
		var TargetpH = dataRecord.sparge_ph;
		var Source_pH = dataRecord.w1_ph;
		var Source_alkalinity = dataRecord.w1_total_alkalinity;
		// Select watersource or fallback to the first source.
		if (dataRecord.sparge_source == 1) {	// Source 2
			if (dataRecord.w2_ph > 0.0) {
				Source_pH = dataRecord.w2_ph;
				Source_alkalinity = dataRecord.w2_total_alkalinity;
			} else {
				dataRecord.sparge_source = 0;	// Source 1
				$("#sparge_source").val(0);
			}
		} else if (dataRecord.sparge_source == 2) {	// Mixed
			if (dataRecord.w2_ph > 0.0) {
				Source_pH = parseFloat($("#wg_ph").jqxNumberInput('decimal'));
				Source_alkalinity = parseFloat($("#wg_total_alkalinity").jqxNumberInput('decimal'));
			} else {
				dataRecord.sparge_source = 0;
				$("#sparge_source").val(0);
			}
		}

		console.log("calcSparge() target pH: "+TargetpH+" Source: "+Source_pH+" alkalinity: "+Source_alkalinity);

		// Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH
		var r1 = Math.pow(10, Source_pH - 6.38);
		var r2 = Math.pow(10, Source_pH - 10.33);
		var d = 1 + r1 + r1*r2;
		var f1 = 1/d;
		var f2 = r1/d;
		var f3 = r1 * r2 / d;

		//Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity)
		var r143 = Math.pow(10, 4.3 - 6.38);
		var r243 = Math.pow(10, 4.3 - 10.33);
		var d43 = 1 + r143 + r143*r243;
		var f143 = 1/d43;
		var f243 = r143 / d43;
		var f343 = r143 * r243 / d43;

		//Step 3. Convert the sample alkalinity to milliequivalents/L
		var alkalinity = Source_alkalinity / 50;
		//Step 4. Solve
		alkalinity = alkalinity / ((f143-f1)+(f3-f343));

		//Step 5. Compute mole fractions at desired pH
		var r1g = Math.pow(10, TargetpH - 6.38);
		var r2g = Math.pow(10, TargetpH - 10.33);
		var dg = 1 + r1g + r1g*r2g;
		var f1g = 1/dg;
		var f2g = r1g / dg;
		var f3g = r1g * r2g / dg;

		//Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
		var Acid = alkalinity * ((f1g-f1)+(f3-f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH);  //mEq/l
		if (dataRecord.sparge_acid_type < 0 || dataRecord.sparge_acid_type > 3) {
			dataRecord.sparge_acid_type = 0;
			$("#sparge_acid_type").val(0);
		}
		var AT = dataRecord.sparge_acid_type;
		var result = GetAcidSpecs(AT);
		var pK1 = result.pK1;
		var pK2 = result.pK2;
		var pK3 = result.pK3;
		var MolWt = result.MolWt;
		var AcidSG = result.AcidSG;
		var AcidPrc = result.AcidPrc;
		var fract = CalcFrac(TargetpH, pK1, pK2, pK3);

		//Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid.
		Acid /= fract;

		//Step 10. Multiply by molecular weight of the acid
		Acid *= MolWt; //mg

		Acid = Acid / AcidSG; //ml ; 88% lactic solution
		f1 = dataRecord.sparge_acid_perc;
		if (f1 <= 0.1)
			f1 = AcidPrc;
		Acid = Acid * AcidPrc / (f1 / 100);

		Acid *= dataRecord.sparge_volume; //ml lactic acid total
		Acid = Math.round(Acid * 100) / 100;
		dataRecord.sparge_acid_amount = Acid / 1000;
		$("#sparge_acid_amount").val(Acid);
	}

	/*
	 * Change OG of recipe but keep the water volumes.
	 */
	function calcFermentablesFromOG(OG) {

		console.log("calcFermentablesFromOG("+OG+")");
		var efficiency = parseFloat($("#efficiency").jqxNumberInput('decimal'));
		var sug = sg_to_plato(OG) * parseFloat($("#batch_size").jqxNumberInput('decimal')) * OG / 100;	//total amount of sugars in kg
		var tot = 0;
		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;

		for (var i = 0; i < rowscount; i++) {
			var row = $("#fermentableGrid").jqxGrid('getrowdata', i);
			var d = row.f_percentage / 100 * (row.f_yield / 100) * (1 - row.f_moisture / 100);
			if (row.f_added == 0)	// Mash
				d = efficiency / 100 * d;
			tot += d;
		}
		var	totmass = 0;
		if (tot)
			totmass = sug / tot;

		if (totmass) {
			for (i = 0; i < rowscount; i++) {
				var row = $("#fermentableGrid").jqxGrid('getrowdata', i);
				var amount = row.f_percentage / 100 * totmass;
				$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_amount", amount);
			}
		}
	};

	function calcInit () {
		console.log("calc.init()");

		$("#calc_acid").on('checked', function (event) {
			dataRecord.calc_acid = true;
			calcWater();
		});
		$("#calc_acid").on('unchecked', function (event) {
			dataRecord.calc_acid = false;
			calcWater();
		});
		$("#w1_name").jqxDropDownList('selectItem', dataRecord.w1_name);
		$("#w2_name").jqxDropDownList('selectItem', dataRecord.w2_name);
		// Fix tap water if zero using mash infuse amount.
		if (parseFloat($("#wg_amount").jqxNumberInput('decimal')) == 0 && mash_infuse > 0) {
			$("#w1_amount").val(mash_infuse);
			dataRecord.w1_amount = mash_infuse;
			$("#wg_amount").val(mash_infuse);
			$("#w2_amount").val(0);
			dataRecord.w2_amount = 0;
		}
		calcWater();
		$("#w2_amount").on('change', function (event) {
			var newval = parseFloat(event.args.value);

			if (newval > mash_infuse) {
				$("#w2_amount").val(dataRecord.w2_amount);
				return;
			}
			dataRecord.w1_amount = parseFloat($("#wg_amount").jqxNumberInput('decimal')) - newval;
			$("#w1_amount").val(dataRecord.w1_amount);
			dataRecord.w2_amount = newval;
			console.log("new: "+event.args.value+" w1: "+dataRecord.w1_amount+"  w2: "+dataRecord.w2_amount);
			calcWater();
		});
		$('#wa_cacl2').on('change', function (event) {
			if (event.args) {
				setWaterAgent('CaCl2', 0);	// This can prevent double entries.
				setWaterAgent('CaCl2', event.args.value);
				calcWater();
			}
		});
		$('#wa_caso4').on('change', function (event) {
			if (event.args) {
				setWaterAgent('CaSO4', 0);
				setWaterAgent('CaSO4', event.args.value);
				calcWater();
			}
		});
		$('#wa_mgso4').on('change', function (event) {
			if (event.args) {
				setWaterAgent('MgSO4', 0);
				setWaterAgent('MgSO4', event.args.value);
				calcWater();
			}
		});
		$('#wa_nacl').on('change', function (event) {
			if (event.args) {
				setWaterAgent('NaCl', 0);
				setWaterAgent('NaCl', event.args.value);
				calcWater();
			}
		});
		$('#wa_base_name').on('change', function (event) {
			if (event.args) {
				var index = event.args.index;
				console.log("wa_base_name "+index);
				setWaterAgent(last_base, 0);
				last_base = BaseTypeData[index].nl;
				setWaterAgent(last_base, parseFloat($("#wa_base").jqxNumberInput('decimal')));
				dataRecord.wa_base_name = index;
				calcWater();
			}
		});
		$('#wa_base').on('change', function (event) {
			var name = BaseTypeData[$("#wa_base_name").val()].nl;
			setWaterAgent(name, parseFloat(event.args.value));
			calcWater();
		});
		$('#wa_acid_name').on('change', function (event) {
			if (event.args) {
				var index = event.args.index;
				console.log("wa_acid_name "+index);
				setWaterAgent(last_acid, 0);
				last_acid = AcidTypeData[index].nl;
				setWaterAgent(last_acid, parseFloat($("#wa_acid").jqxNumberInput('decimal')));
				dataRecord.wa_acid_name = index;
				calcWater();
			}
		});
		$('#wa_acid').on('change', function (event) {
			var name = AcidTypeData[$("#wa_acid_name").val()].nl;
			setWaterAgent(name, parseFloat(event.args.value));
			calcWater();
		});
		$('#wa_acid_perc').on('change', function (event) { calcWater(); });

		$('#color_method').on('change', function (event) {
			dataRecord.color_method = event.args.index;
			calcFermentables();
		});
		$('#ibu_method').on('change', function (event) {
			dataRecord.ibu_method = event.args.index;
			calcFermentables();
			calcIBUs(); 
		});
		$('#batch_size').on('change', function (event) {
			console.log("batch_size change:"+event.args.value+" old:"+dataRecord.batch_size);
			var new_boil = parseFloat(event.args.value) + dataRecord.boil_size - dataRecord.batch_size;
			var factor = parseFloat(event.args.value) / dataRecord.batch_size;
			dataRecord.boil_size = new_boil;
			$("#boil_size").val(Math.round(new_boil * 100) / 100);
			dataRecord.sparge_volume *= factor;
			$("#sparge_volume").val(dataRecord.sparge_volume);
			dataRecord.batch_size = parseFloat(event.args.value);
			calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal')));     // Keep the OG
			adjustWaters(factor);
			calcFermentables();
			adjustHops(factor);
			adjustMiscs(factor);
			adjustYeasts(factor);
			calcIBUs();
			calcWater();
			calcSparge();
		});
		$('#boil_time').on('change', function (event) {
			console.log("boil_time change:"+parseFloat(event.args.value)+" old:"+dataRecord.boil_time);
			var old_evap = parseFloat(dataRecord.boil_size) - parseFloat(dataRecord.batch_size);
			var new_evap = old_evap * (parseFloat(event.args.value) / dataRecord.boil_time);
			var new_boil = parseFloat(dataRecord.batch_size) + new_evap;
	//		console.log("old_evap:"+old_evap+" new_evap:"+new_evap+" new_boil:"+new_boil);
			dataRecord.boil_time = parseFloat(event.args.value);
			dataRecord.boil_size = new_boil;
			$("#boil_size").val(Math.round(new_boil * 100) / 100);
			calcFermentables();
			// TODO: adjust the hops, miscs, yeast, water.
			calcIBUs();
		});
		$('#efficiency').on('change', function (event) {
			console.log("efficiency change:"+event.args.value);
			calcFermentables();
			calcIBUs();
		});
		$('#est_og').on('change', function (event) {
			console.log("est_og change:"+event.args.value);
			calcFermentablesFromOG(event.args.value);       // Adjust fermentables amounts
			calcFermentables();                             // Update the recipe details
			calcIBUs();                                     // and the IBU's.
		});
		$('#mash_ph').on('change', function (event) {
			dataRecord.mash_ph = parseFloat(event.args.value);
			calcWater();
		});

		$('#sparge_ph').on('change', function (event) {
			dataRecord.sparge_ph = parseFloat(event.args.value);
			calcSparge();
		});
		$('#sparge_volume').on('change', function (event) {
			dataRecord.sparge_volume = parseFloat(event.args.value);
			calcSparge();
		});
		$('#sparge_source').on('change', function (event) {
			if (event.args) {
				var index = event.args.index;
				dataRecord.sparge_source= index;
				calcSparge();
			}
		});
		$('#sparge_acid_type').on('change', function (event) {
			if (event.args) {
				var index = event.args.index;
				dataRecord.sparge_acid_type = index;
				console.log("new sparge_acid_type: "+dataRecord.sparge_acid_type);
				calcSparge();
			}
		});
		$('#sparge_acid_perc').on('change', function (event) {
			dataRecord.sparge_acid_perc = parseFloat(event.args.value);
			calcSparge();
		});
		$('#locked').on('checked', function (event) {
			setReadonly(true);
		});
		$('#locked').on('unchecked', function (event) {
			setReadonly(false);
		});
//		setReadonly(false);
	};

	$("#styleSelect").jqxDropDownList({
		placeHolder: "Kies bierstijl:",
		theme: theme,
		source: styleslist,
		displayMember: "name",
		width: 180,
		height: 23,
		dropDownVerticalAlignment: 'top',
		dropDownWidth: 500,
		dropDownHeight: 380,
		renderer: function (index, label, value) {
			var datarecord = styleslist.records[index];
			return datarecord.style_guide + " " + datarecord.style_letter+ " " + datarecord.name;
		}
	});
	$("#styleSelect").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = styleslist.records[index];
			$("#st_name").val(datarecord.name);
			$("#st_category").val(datarecord.category);
			$("#st_category_number").val(datarecord.category_number);
			$("#st_letter").val(datarecord.style_letter);
			$("#st_guide").val(datarecord.style_guide);
			$("#st_type").val(StyleTypeData[datarecord.type].nl);
			$("#st_og_min").val(datarecord.og_min);
			$("#st_og_max").val(datarecord.og_max);
			$("#st_fg_min").val(datarecord.fg_min);
			$("#st_fg_max").val(datarecord.fg_max);
			$("#st_ibu_min").val(datarecord.ibu_min);
			$("#st_ibu_max").val(datarecord.ibu_max);
			$("#st_color_min").val(datarecord.color_min);
			$("#st_color_max").val(datarecord.color_max);
			$("#st_carb_min").val(datarecord.carb_min);
			$("#st_carb_max").val(datarecord.carb_max);
			$("#st_abv_min").val(datarecord.abv_min);
			$("#st_abv_max").val(datarecord.abv_max);
		}
	});

	function saveRecord() {
		var fermentablerow = $('#fermentableGrid').jqxGrid('getrows');
		var hoprow = $('#hopGrid').jqxGrid('getrows');
		var miscrow = $('#miscGrid').jqxGrid('getrows');
		var yeastrow = $('#yeastGrid').jqxGrid('getrows');
		var mashrow = $('#mashGrid').jqxGrid('getrows');
		var row = {
			record: my_record,
			uuid: dataRecord.uuid,
			name: $("#name").val(),
			locked: $("#locked").val(),
			notes: $("#notes").val(),
			st_name: $('#st_name').val(),
			st_letter: $('#st_letter').val(),
			st_guide: $('#st_guide').val(),
			st_type: dataRecord.st_type,
			st_category: $('#st_category').val(),
			st_category_number: parseFloat($("#st_category_number").jqxNumberInput('decimal')),
			st_og_min: parseFloat($("#st_og_min").jqxNumberInput('decimal')),
			st_og_max: parseFloat($("#st_og_max").jqxNumberInput('decimal')),
			st_fg_min: parseFloat($("#st_fg_min").jqxNumberInput('decimal')),
			st_fg_max: parseFloat($("#st_fg_max").jqxNumberInput('decimal')),
			st_ibu_min: parseFloat($("#st_ibu_min").jqxNumberInput('decimal')),
			st_ibu_max: parseFloat($("#st_ibu_max").jqxNumberInput('decimal')),
			st_color_min: parseFloat($("#st_color_min").jqxNumberInput('decimal')),
			st_color_max: parseFloat($("#st_color_max").jqxNumberInput('decimal')),
			st_carb_min: parseFloat($("#st_carb_min").jqxNumberInput('decimal')),
			st_carb_max: parseFloat($("#st_carb_max").jqxNumberInput('decimal')),
			st_abv_min: parseFloat($("#st_abv_min").jqxNumberInput('decimal')),
			st_abv_max: parseFloat($("#st_abv_max").jqxNumberInput('decimal')),
			type: $("#type").val(),
			batch_size: parseFloat($("#batch_size").jqxNumberInput('decimal')),
			boil_size: parseFloat($("#boil_size").jqxNumberInput('decimal')),
			boil_time: parseFloat($("#boil_time").jqxNumberInput('decimal')),
			efficiency: parseFloat($("#efficiency").jqxNumberInput('decimal')),
			est_og: parseFloat($("#est_og").jqxNumberInput('decimal')),
			est_fg: parseFloat($("#est_fg").jqxNumberInput('decimal')),
			est_abv: parseFloat($("#est_abv").jqxNumberInput('decimal')),
			est_color: parseFloat($("#est_color").jqxNumberInput('decimal')),
			color_method: $("#color_method").val(),
			est_ibu: parseFloat($("#est_ibu").jqxNumberInput('decimal')),
			ibu_method: $("#ibu_method").val(),
			est_carb: parseFloat($("#est_carb").jqxNumberInput('decimal')),
			mash_name: $("#mash_name").val(),
			mash_ph: parseFloat($("#mash_ph").jqxNumberInput('decimal')),
			sparge_temp: parseFloat($("#sparge_temp").jqxNumberInput('decimal')),
			sparge_ph: parseFloat($("#sparge_ph").jqxNumberInput('decimal')),
			sparge_volume: parseFloat($("#sparge_volume").jqxNumberInput('decimal')),
			sparge_source: $("#sparge_source").val(),
			sparge_acid_type: $("#sparge_acid_type").val(),
			sparge_acid_perc: parseFloat($("#sparge_acid_perc").jqxNumberInput('decimal')),
			sparge_acid_amount: dataRecord.sparge_acid_amount,
			calc_acid: $("#calc_acid").val(),
			w1_name: $("#w1_name").val(),
			w1_amount: parseFloat($("#w1_amount").jqxNumberInput('decimal')),
			w1_calcium: parseFloat($("#w1_calcium").jqxNumberInput('decimal')),
			w1_sulfate: parseFloat($("#w1_sulfate").jqxNumberInput('decimal')),
			w1_chloride: parseFloat($("#w1_chloride").jqxNumberInput('decimal')),
			w1_sodium: parseFloat($("#w1_sodium").jqxNumberInput('decimal')),
			w1_magnesium: parseFloat($("#w1_magnesium").jqxNumberInput('decimal')),
			w1_total_alkalinity: parseFloat($("#w1_total_alkalinity").jqxNumberInput('decimal')),
			w1_ph: parseFloat($("#w1_ph").jqxNumberInput('decimal')),
			w1_cost: dataRecord.w1_cost,
			w2_name: $("#w2_name").val(),
			w2_amount: parseFloat($("#w2_amount").jqxNumberInput('decimal')),
			w2_calcium: parseFloat($("#w2_calcium").jqxNumberInput('decimal')),
			w2_sulfate: parseFloat($("#w2_sulfate").jqxNumberInput('decimal')),
			w2_chloride: parseFloat($("#w2_chloride").jqxNumberInput('decimal')),
			w2_sodium: parseFloat($("#w2_sodium").jqxNumberInput('decimal')),
			w2_magnesium: parseFloat($("#w2_magnesium").jqxNumberInput('decimal')),
			w2_total_alkalinity: parseFloat($("#w2_total_alkalinity").jqxNumberInput('decimal')),
			w2_ph: parseFloat($("#w2_ph").jqxNumberInput('decimal')),
			w2_cost: dataRecord.w2_cost,
			wa_acid_name: $("#wa_acid_name").val(),
			wa_acid_perc: parseFloat($("#wa_acid_perc").jqxNumberInput('decimal')),
			wa_base_name: $("#wa_base_name").val(),
			fermentables: fermentablerow,
			hops: hoprow,
			miscs: miscrow,
			yeasts: yeastrow,
			mashs: mashrow
		};
		var data = "update=true&" + $.param(row);
		$.ajax({
			dataType: 'json',
			url: url,
			cache: false,
			data: data,
			type: "POST",
			success: function (data, status, xhr) {
			},
			error: function(jqXHR, textStatus, errorThrown) {
			}
		});
	};

	var dataRecord = {};
	var url = "includes/db_recipes.php";

	// prepare the data
	var source = {
		datatype: "json",
		cache: false,
		datafields: [
			{ name: 'record', type: 'number' },
			{ name: 'uuid', type: 'string' },
			{ name: 'locked', type: 'bool' },
			{ name: 'st_name', type: 'string' },
			{ name: 'st_letter', type: 'string' },
			{ name: 'st_guide', type: 'string' },
			{ name: 'st_type', type: 'int' },
			{ name: 'st_category', type: 'string' },
			{ name: 'st_category_number', type: 'float' },
			{ name: 'st_og_min', type: 'float' },
			{ name: 'st_og_max', type: 'float' },
			{ name: 'st_fg_min', type: 'float' },
			{ name: 'st_fg_max', type: 'float' },
			{ name: 'st_ibu_min', type: 'float' },
			{ name: 'st_ibu_max', type: 'float' },
			{ name: 'st_color_min', type: 'float' },
			{ name: 'st_color_max', type: 'float' },
			{ name: 'st_carb_min', type: 'float' },
			{ name: 'st_carb_max', type: 'float' },
			{ name: 'st_abv_min', type: 'float' },
			{ name: 'st_abv_max', type: 'float' },
			{ name: 'name', type: 'string' },
			{ name: 'notes', type: 'string' },
			{ name: 'type', type: 'int' },
			{ name: 'batch_size', type: 'float' },
			{ name: 'boil_size', type: 'float' },
			{ name: 'boil_time', type: 'float' },
			{ name: 'efficiency', type: 'float' },
			{ name: 'est_og', type: 'float' },
			{ name: 'est_fg', type: 'float' },
			{ name: 'est_abv', type: 'float' },
			{ name: 'est_color', type: 'float' },
			{ name: 'color_method', type: 'int' },
			{ name: 'est_ibu', type: 'float' },
			{ name: 'ibu_method', type: 'int' },
			{ name: 'est_carb', type: 'float' },
			{ name: 'sparge_temp', type: 'float' },
			{ name: 'sparge_ph', type: 'float' },
			{ name: 'sparge_volume', type: 'float' },
			{ name: 'sparge_source', type: 'int' },
			{ name: 'sparge_acid_type', type: 'int' },
			{ name: 'sparge_acid_perc', type: 'float' },
			{ name: 'sparge_acid_amount', type: 'float' },
			{ name: 'mash_ph', type: 'float' },
			{ name: 'mash_name', type: 'string' },
			{ name: 'calc_acid', type: 'bool' },
			{ name: 'w1_name', type: 'string' },
			{ name: 'w1_amount', type: 'float' },
			{ name: 'w1_calcium', type: 'float' },
			{ name: 'w1_sulfate', type: 'float' },
			{ name: 'w1_chloride', type: 'float' },
			{ name: 'w1_sodium', type: 'float' },
			{ name: 'w1_magnesium', type: 'float' },
			{ name: 'w1_total_alkalinity', type: 'float' },
			{ name: 'w1_ph', type: 'float' },
			{ name: 'w1_cost', type: 'float' },
			{ name: 'w2_name', type: 'string' },
			{ name: 'w2_amount', type: 'float' },
			{ name: 'w2_calcium', type: 'float' },
			{ name: 'w2_sulfate', type: 'float' },
			{ name: 'w2_chloride', type: 'float' },
			{ name: 'w2_sodium', type: 'float' },
			{ name: 'w2_magnesium', type: 'float' },
			{ name: 'w2_total_alkalinity', type: 'float' },
			{ name: 'w2_ph', type: 'float' },
			{ name: 'w2_cost', type: 'float' },
			{ name: 'wa_acid_name', type: 'int' },
			{ name: 'wa_acid_perc', type: 'int' },
			{ name: 'wa_base_name', type: 'int' },
			{ name: 'fermentables', type: 'array' },
			{ name: 'hops', type: 'array' },
			{ name: 'miscs', type: 'array' },
			{ name: 'yeasts', type: 'array' },
			{ name: 'mashs', type: 'array' }
		],
		id: 'record',
		url: url + '?record=' + my_record
	};
	// Load data and select one record.
	var dataAdapter = new $.jqx.dataAdapter(source, {
		loadComplete: function () {
			var records = dataAdapter.records;
			dataRecord = records[0];
			// Hidden record uuid
			$("#name").val(dataRecord.name);
			$("#notes").val(dataRecord.notes);
			$("#locked").val(dataRecord.locked);
			$("#st_name").val(dataRecord.st_name);
			$("#st_letter").val(dataRecord.st_letter);
			$("#st_guide").val(dataRecord.st_guide);
			$("#st_category").val(dataRecord.st_category);
			$("#st_category_number").val(dataRecord.st_category_number);
			$("#st_type").val(StyleTypeData[dataRecord.st_type].nl);
			$("#type").val(dataRecord.type);
			$("#batch_size").val(dataRecord.batch_size);
			$("#boil_size").val(dataRecord.boil_size);
			$("#boil_time").val(dataRecord.boil_time);
			$("#efficiency").val(dataRecord.efficiency);
			$("#est_og").val(dataRecord.est_og);
			$("#est_og2").val(dataRecord.est_og);
			$("#st_og_min").val(dataRecord.st_og_min);
			$("#st_og_max").val(dataRecord.st_og_max);
			$("#est_fg").val(dataRecord.est_fg);
			$("#est_fg2").val(dataRecord.est_fg);
			$("#st_fg_min").val(dataRecord.st_fg_min);
			$("#st_fg_max").val(dataRecord.st_fg_max);
			$("#est_color").val(dataRecord.est_color);
			$("#est_color2").val(dataRecord.est_color);
			$("#est_abv").val(dataRecord.est_abv);
			$("#est_abv2").val(dataRecord.est_abv);
			$("#st_abv_min").val(dataRecord.st_abv_min);
			$("#st_abv_max").val(dataRecord.st_abv_max);
			$("#st_color_min").val(dataRecord.st_color_min);
			$("#st_color_max").val(dataRecord.st_color_max);
			$("#color_method").val(dataRecord.color_method);
			$("#est_ibu").val(dataRecord.est_ibu);
			$("#est_ibu2").val(dataRecord.est_ibu);
			$("#st_ibu_min").val(dataRecord.st_ibu_min);
			$("#st_ibu_max").val(dataRecord.st_ibu_max);
			$("#ibu_method").val(dataRecord.ibu_method);
			$("#est_carb").val(dataRecord.est_carb);
			$("#st_carb_min").val(dataRecord.st_carb_min);
			$("#st_carb_max").val(dataRecord.st_carb_max);
			$("#mash_name").val(dataRecord.mash_name);
			$("#mash_ph").val(dataRecord.mash_ph);
			$("#sparge_temp").val(dataRecord.sparge_temp);
			$("#sparge_ph").val(dataRecord.sparge_ph);
			$("#sparge_volume").val(dataRecord.sparge_volume);
			$("#sparge_source").val(dataRecord.sparge_source);
			$("#sparge_acid_type").val(dataRecord.sparge_acid_type);
			$("#sparge_acid_perc").val(dataRecord.sparge_acid_perc);
			$("#sparge_acid_amount").val(dataRecord.sparge_acid_amount * 1000);
			$("#calc_acid").val(dataRecord.calc_acid);
			$("#w1_name").val(dataRecord.w1_name);
			$("#w1_amount").val(dataRecord.w1_amount);
			$("#w1_calcium").val(dataRecord.w1_calcium);
			$("#w1_sulfate").val(dataRecord.w1_sulfate);
			$("#w1_chloride").val(dataRecord.w1_chloride);
			$("#w1_sodium").val(dataRecord.w1_sodium);
			$("#w1_magnesium").val(dataRecord.w1_magnesium);
			$("#w1_total_alkalinity").val(dataRecord.w1_total_alkalinity);
			$("#w1_ph").val(dataRecord.w1_ph);
			$("#w1_cost").val(dataRecord.w1_cost);
			$("#w2_name").val(dataRecord.w2_name);
			$("#w2_amount").val(dataRecord.w2_amount);
			$("#w2_calcium").val(dataRecord.w2_calcium);
			$("#w2_sulfate").val(dataRecord.w2_sulfate);
			$("#w2_chloride").val(dataRecord.w2_chloride);
			$("#w2_sodium").val(dataRecord.w2_sodium);
			$("#w2_magnesium").val(dataRecord.w2_magnesium);
			$("#w2_total_alkalinity").val(dataRecord.w2_total_alkalinity);
			$("#w2_ph").val(dataRecord.w2_ph);
			$("#w2_cost").val(dataRecord.w2_cost);
			$("#wa_acid_name").val(dataRecord.wa_acid_name);
			$("#wa_acid_perc").val(dataRecord.wa_acid_perc);
			$("#wa_base_name").val(dataRecord.wa_base_name);
			editFermentable(dataRecord);
			editHop(dataRecord);
			editMisc(dataRecord);
			editYeast(dataRecord);
			editMash(dataRecord);
			$('#jqxTabs').jqxTabs('next');
		},
		loadError: function (jqXHR, status, error) {
		},
		beforeLoadComplete: function (records) {
			$('#jqxLoader').jqxLoader('open');
		}
	});
	dataAdapter.dataBind();

	// Inline fermentables editor
	var editFermentable = function (data) {
		var fermentableSource = {
			localdata: data.fermentables,
			datatype: "local",
			cache: false,
			async: false,
			datafields: [
				{ name: 'f_name', type: 'string' },
				{ name: 'f_origin', type: 'string' },
				{ name: 'f_supplier', type: 'string' },
				{ name: 'f_amount', type: 'float' },
				{ name: 'f_cost', type: 'float' },
				{ name: 'f_type', type: 'int' },
				{ name: 'f_yield', type: 'float' },
				{ name: 'f_color', type: 'float' },
				{ name: 'f_coarse_fine_diff', type: 'float' },
				{ name: 'f_moisture', type: 'float' },
				{ name: 'f_diastatic_power', type: 'float' },
				{ name: 'f_protein', type: 'float' },
				{ name: 'f_max_in_batch', type: 'float' },
				{ name: 'f_graintype', type: 'int' },
				{ name: 'f_added', type: 'int' },
				{ name: 'f_dissolved_protein', type: 'float' },
				{ name: 'f_recommend_mash', type: 'int' },
				{ name: 'f_add_after_boil', type: 'int' },
				{ name: 'f_adjust_to_total_100', type: 'int' },
				{ name: 'f_percentage', type: 'float' },
				{ name: 'f_di_ph', type: 'float' },
				{ name: 'f_acid_to_ph_57', type: 'float' },
				{ name: 'f_inventory', type: 'float' },
				{ name: 'f_avail', type: 'int' }
			],
			addrow: function (rowid, rowdata, position, commit) {
				commit(true);
			},
			deleterow: function (rowid, commit) {
				commit(true);
			}
		};
		var fermentableAdapter = new $.jqx.dataAdapter(fermentableSource);
		$("#fermentableGrid").jqxGrid({
			width: 1240,
			height: 500,
			source: fermentableAdapter,
			theme: theme,
			selectionmode: 'singlerow',
			showtoolbar: true,
			rendertoolbar: function (toolbar) {
				var me = this;
				var container = $("<div style='overflow: hidden; position: relative; margin: 5px;'></div>");
				toolbar.append(container);
				container.append('<div style="float: left; margin-left: 165px;" id="faddrowbutton"></div>');
				container.append('<div style="float: left; margin-left: 10px; margin-top: 5px;">In voorraad:</div>');
				container.append('<div style="float: left; margin-left: 10px;" id="finstockbutton"></div>');
				container.append('<input style="float: left; margin-left: 400px;" id="fdeleterowbutton" type="button" value="Verwijder mout" />');
				// add fermentable from dropdownlist.
				$("#faddrowbutton").jqxDropDownList({
					placeHolder: "Kies mout:",
					theme: theme,
					template: "primary",
					source: fermentablelist,
					displayMember: "name",
					width: 150,
					height: 27,
					dropDownWidth: 500,
					dropDownHeight: 500,
					renderer: function (index, label, value) {
						var datarecord = fermentablelist.records[index];
						return datarecord.supplier+ " / " + datarecord.name + " (" + datarecord.color + " EBC)";
					}
				});
				$("#faddrowbutton").on('select', function (event) {
					if (event.args) {
						var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
						var index = event.args.index;
						var datarecord = fermentablelist.records[index];
						var row = {};
						row["f_name"] = datarecord.name;
						row["f_origin"] = datarecord.origin;
						row["f_supplier"] = datarecord.supplier;
						row["f_amount"] = 0;
						row["f_cost"] = datarecord.cost;
						row["f_type"] = datarecord.type;
						row["f_yield"] = datarecord.yield;
						row["f_color"] = datarecord.color;
						row["f_coarse_fine_diff"] = datarecord.coarse_fine_diff;
						row["f_moisture"] = datarecord.moisture;
						row["f_diastatic_power"] = datarecord.diastatic_power;
						row["f_protein"] = datarecord.protein;
						row["f_max_in_batch"] = datarecord.max_in_batch;
						row["f_graintype"] = datarecord.graintype;
						if (datarecord.add_after_boil) {
							row["f_added"] = 2;	// Fermentation
						} else if ((datarecord.type == 1) || (datarecord.type == 4)) {	// Sugar or Adjunct
							row["f_added"] = 1;	// Boil
						} else {
							row["f_added"] = 0;	// Mash
						}
						row["f_dissolved_protein"] = datarecord.dissolved_protein;
						row["f_recommend_mash"] = datarecord.recommend_mash;
						row["f_add_after_boil"] = datarecord.add_after_boil;
						if (rowscount == 0) {
							// The first fermentable
							row["f_adjust_to_total_100"] = 1;
							row["f_percentage"] = 100;
						} else {
							row["f_adjust_to_total_100"] = 0;
							row["f_percentage"] = 0;
						}
						row["f_di_ph"] = datarecord.di_ph;
						row["f_acid_to_ph_57"] = datarecord.acid_to_ph_57;
						row["f_inventory"] = datarecord.inventory;
						var commit = $("#fermentableGrid").jqxGrid('addrow', null, row);
					}
				});

				$("#finstockbutton").jqxCheckBox({ theme: theme, height: 27 });
				$("#finstockbutton").on('change', function (event) {
					fermentableinstock = event.args.checked;
					fermentablelist.dataBind();
				});

				// delete selected fermentable.
				$("#fdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
				$("#fdeleterowbutton").on('click', function () {
					var selectedrowindex = $("#fermentableGrid").jqxGrid('getselectedrowindex');
					var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
					if (selectedrowindex >= 0 && selectedrowindex < rowscount) {
						var id = $("#fermentableGrid").jqxGrid('getrowid', selectedrowindex);
						var percent = $('#fermentableGrid').jqxGrid('getcellvalue', id, "f_percentage");
						var amount = $('#fermentableGrid').jqxGrid('getcellvalue', id, "f_amount");
						var commit = $("#fermentableGrid").jqxGrid('deleterow', id);
					}
					rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
					if (rowscount > 1) {
						if (to_100) {
							for (var i = 0; i < rowscount; i++) {
								var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
								if (rowdata.f_adjust_to_total_100) {
									rowdata.f_percentage += percent;
									rowdata.f_amount += amount;
								}
							}
						} else {
							var tw = 0;
							for (i = 0; i < rowscount; i++) {
								var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
								tw += rowdata.f_amount;
							};
							for (i = 0; i < rowscount; i++) {
								var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
								var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
								$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
							};
						}
					} else {
						$("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
					}
					calcFermentables();
					calcIBUs();
				});
			},
			ready: function() {
				calcFermentables();
				$('#jqxTabs').jqxTabs('next');
			},
			columns: [
				{ text: 'Vergistbaar ingredi&euml;nt', datafield: 'f_name',
				  cellsrenderer:  function (index, datafield, value, defaulvalue, column, rowdata) {
					return "<span style='margin: 3px; margin-top: 6px; float: left;'>" +
						rowdata.f_supplier+" / "+rowdata.f_name+" ("+rowdata.f_color+" EBC)</span>";
				  }
			       	},
				{ text: 'Type', width: 100, datafield: 'f_type',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<span style='margin: 3px; margin-top: 6px; float: left;'>" + FermentableTypeData[value].nl + "</span>";
				  }
				},
				{ text: 'Moment', width: 110, datafield: 'f_added',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<span style='margin: 3px; margin-top: 6px; float: left;'>" + AddedData[value].nl + "</span>";
				  }
				},
				{ text: 'Opbrengst', editable: false, datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
				{ text: 'Gewicht Kg', datafield: 'f_amount', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f3' },
				{ text: 'Voorr. Kg', datafield: 'f_inventory', width: 120, align: 'right',
				  cellsrenderer:  function (row, columnfield, value, defaulthtml, columnproperties, rowdata) {
					var color = '#ffffff';
					if (value < rowdata.f_amount)
						color = '#ff4040';
					return  '<span style="margin: 4px; margin-top: 6px; float: right; color: ' +
						color + ';">' +fermentableAdapter.formatNumber(value, "f3") + '</span>';
				  }
				},
				{ text: 'Procent', datafield: 'f_percentage', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
				{ text: '100%', align: 'center', datafield: 'f_adjust_to_total_100', columntype: 'checkbox', width: 70 },
				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
					return "Wijzig";
				        }, buttonclick: function (row) {
						fermentableRow = row;
						fermentableData = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
						$("#wf_name").val(fermentableData.f_name);
						$("#wf_amount").val(fermentableData.f_amount);
						$("#wf_percentage").val(fermentableData.f_percentage);
						$("#wf_adjust_to_total_100").val(fermentableData.f_adjust_to_total_100);
						$("#wf_added").val(fermentableData.f_added);
						// show the popup window.
						$("#popupFermentable").jqxWindow('open');
					}
				}
			]
		});
	};

	// Inline hops editor
        var editHop = function (data) {
                var hopSource = {
                        localdata: data.hops,
                        datatype: "local",
			cache: false,
			async: false,
                        datafields: [
                                { name: 'h_name', type: 'string' },
                                { name: 'h_origin', type: 'string' },
                                { name: 'h_amount', type: 'float' },
                                { name: 'h_cost', type: 'float' },
				{ name: 'h_type', type: 'int' },
				{ name: 'h_form', type: 'int' },
				{ name: 'h_useat', type: 'int' },
                                { name: 'h_time', type: 'float' },
				{ name: 'h_alpha', type: 'float' },
				{ name: 'h_beta', type: 'float' },
				{ name: 'h_hsi', type: 'float' },
				{ name: 'h_humulene', type: 'float' },
				{ name: 'h_caryophyllene', type: 'float' },
				{ name: 'h_cohumulone', type: 'float' },
				{ name: 'h_myrcene', type: 'float' },
				{ name: 'h_total_oil', type: 'float' },
				{ name: 'h_inventory', type: 'float' },
				{ name: 'h_avail', type: 'int' }
                        ],
                        addrow: function (rowid, rowdata, position, commit) {
                                commit(true);
                        },
                        deleterow: function (rowid, commit) {
                                commit(true);
                        }
                };
                var hopAdapter = new $.jqx.dataAdapter(hopSource);
                $("#hopGrid").jqxGrid({
                        width: 1240,
                        height: 560,
                        source: hopAdapter,
                        theme: theme,
                        selectionmode: 'singlerow',
                        showtoolbar: true,
                        rendertoolbar: function (toolbar) {
                                var me = this;
                                var container = $("<div style='overflow: hidden; position: relative; margin: 5px;'></div>");
                                toolbar.append(container);
                                container.append('<div style="float: left; margin-left: 165px;" id="haddrowbutton"></div>');
				container.append('<div style="float: left; margin-left: 10px; margin-top: 5px;">In voorraad:</div>');
				container.append('<div style="float: left; margin-left: 10px;" id="hinstockbutton"></div>');
                                container.append('<input style="float: left; margin-left: 400px;" id="hdeleterowbutton" type="button" value="Verwijder hop" />');
                                // add hop from dropdownlist.
                                $("#haddrowbutton").jqxDropDownList({
                                        placeHolder: "Kies hop:",
                                        theme: theme,
					template: "primary",
                                        source: hoplist,
                                        displayMember: "name",
                                        width: 150,
                                        height: 27,
                                        dropDownWidth: 500,
					dropDownHeight: 500,
					renderer: function (index, label, value) {
						var datarecord = hoplist.records[index];
						return datarecord.origin+ " / " + datarecord.name + " (" + datarecord.alpha + "% &alpha;)";
					}
                                });
                                $("#haddrowbutton").on('select', function (event) {
                                        if (event.args) {
                                                var index = event.args.index;
                                                var datarecord = hoplist.records[index];
                                                var row = {};
                                                row["h_name"] = datarecord.name;
                                                row["h_origin"] = datarecord.origin;
                                                row["h_amount"] = 0;
                                                row["h_cost"] = datarecord.cost;
                                                row["h_type"] = datarecord.type;
						row["h_form"] = datarecord.form;
						row["h_useat"] = 2;	// Boil
						row["h_time"] = 0;
						row["h_alpha"] = datarecord.alpha;
						row["h_beta"] = datarecord.beta;
						row["h_hsi"] = datarecord.hsi;
						row["h_humulene"] = datarecord.humulene;
						row["h_caryophyllene"] = datarecord.caryophyllene;
						row["h_cohumulone"] = datarecord.cohumulone;
						row["h_myrcene"] = datarecord.myrcene;
						row["h_total_oil"] = datarecord.total_oil;
						row["h_inventory"] = datarecord.inventory;
                                                var commit = $("#hopGrid").jqxGrid('addrow', null, row);
                                        }
					$("#haddrowbutton").jqxDropDownList('clearSelection');
                                });

				$("#hinstockbutton").jqxCheckBox({ theme: theme, height: 27 });
				$("#hinstockbutton").on('change', function (event) {
					hopinstock = event.args.checked;
					hoplist.dataBind();
				});

                                // delete selected hop.
                                $("#hdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                $("#hdeleterowbutton").on('click', function () {
                                        var selectedrowindex = $("#hopGrid").jqxGrid('getselectedrowindex');
                                        var rowscount = $("#hopGrid").jqxGrid('getdatainformation').rowscount;
                                        if (selectedrowindex >= 0 && selectedrowindex < rowscount) {
                                                var id = $("#hopGrid").jqxGrid('getrowid', selectedrowindex);
                                                var commit = $("#hopGrid").jqxGrid('deleterow', id);
                                        }
					calcIBUs();
                                });
                        },
			ready: function() {
				calcIBUs();
				$('#jqxTabs').jqxTabs('next');
			},
                        columns: [
                                { text: 'Hop', datafield: 'h_name',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<span style='margin: 3px; margin-top: 6px; float: left;'>" +rowdata.h_origin+" / "+rowdata.h_name+"</span>";
				  },
			       	},
                                { text: 'Type', width: 90, datafield: 'h_type',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return  '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopTypeData[value].nl + '</span>';
				  }
			       	},
				{ text: 'Vorm', width: 90, datafield: 'h_form',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return  '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopFormData[value].nl + '</span>';
				  }
			       	},
                                { text: 'Alpha', datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
				{ text: 'Gebruik', width: 110, datafield: 'h_useat',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return  '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopUseData[value].nl + '</span>';
				  }
				},
				{ text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var duration = '';
					if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4))   // Boil, Whirlpool
						duration = dataAdapter.formatNumber(value, "f0")+" min.";
					else if (rowdata.h_useat == 5)       // Dry hop
						duration = dataAdapter.formatNumber(value/1440, "f0")+" dagen";
					return  '<span style="margin: 4px; margin-top: 6px; float: right;">' + duration + '</span>';
				  }
				},
				{ text: 'IBU', datafield: 'ibu', width: 80, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
							  parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time),
							  parseFloat(rowdata.h_alpha), $("#ibu_method").val());
					return  '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(ibu, "f1") + '</span>';
				  }
				},
				{ text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var amount = dataAdapter.formatNumber(value, "f1") + ' kg';
					if (value < 1)
						amount = dataAdapter.formatNumber(value * 1000, "f1") + ' gr';
					return  '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>';
				  }
				},
				{ text: 'Voorraad', datafield: 'h_inventory', width: 110, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var color = '#ffffff';
					if (value < rowdata.h_amount)
						color = '#ff4040';
					var amount = dataAdapter.formatNumber(value, "f1") + ' kg';
					if (value < 1)
						amount = dataAdapter.formatNumber(value * 1000, "f1") + ' gr';
					return  '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>';
				  }
				},
				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
					return "Wijzig";
					}, buttonclick: function (row) {
						hopRow = row;
						hopData = $("#hopGrid").jqxGrid('getrowdata', hopRow);
						$("#wh_name").val(hopData.h_name);
						$("#wh_amount").val(hopData.h_amount * 1000);
						var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg,
							parseFloat($("#batch_size").jqxNumberInput('decimal')),
							parseFloat(hopData.h_amount), parseFloat(hopData.h_time),
							parseFloat(hopData.h_alpha), $("#ibu_method").val()
						);
						$("#wh_ibu").val(ibu);
						if (hopData.h_useat == 5)	// Dry hop
							$("#wh_time").val(hopData.h_time / 1440);
						else
							$("#wh_time").val(hopData.h_time);
						$("#wh_useat").val(hopData.h_useat);
						// show the popup window.
						$("#popupHop").jqxWindow('open');
					}
				}
                        ]
                });
        };

	// Inline miscs editor
        var editMisc = function (data) {
                var miscSource = {
                        localdata: data.miscs,
                        datatype: "local",
                        cache: false,
			async: false,
                        datafields: [
                                { name: 'm_name', type: 'string' },
                                { name: 'm_amount', type: 'float' },
                                { name: 'm_cost', type: 'float' },
                                { name: 'm_type', type: 'int' },
                                { name: 'm_use_use', type: 'int' },
                                { name: 'm_time', type: 'float' },
                                { name: 'm_amount_is_weight', type: 'int' },
				{ name: 'm_inventory', type: 'float' },
				{ name: 'm_avail', type: 'int' }
                        ],
                        addrow: function (rowid, rowdata, position, commit) {
                                commit(true);
                        },
                        deleterow: function (rowid, commit) {
                                commit(true);
                        }
                };
                var miscAdapter = new $.jqx.dataAdapter(miscSource, {
			beforeLoadComplete: function (records) {
				var data = new Array();
				for (var i = 0; i < records.length; i++) {
					var row = records[i];
					data.push(row);
					// Initial set water agent values.
					switch (row.m_name) {
						case 'CaCl2':		$("#wa_cacl2").val(row.m_amount * 1000);
									break;
						case 'CaSO4':		$("#wa_caso4").val(row.m_amount * 1000);
									break;
						case 'MgSO4':		$("#wa_mgso4").val(row.m_amount * 1000);
									break;
						case 'NaCl':		$("#wa_nacl").val(row.m_amount * 1000);
									break;
						case 'Melkzuur':	$("#wa_acid_name").val(0);
									$("#wa_acid").val(row.m_amount * 1000);
									$("#wa_acid_perc").val(80);
									last_acid = 'Melkzuur';
									break;
						case 'Zoutzuur':	$("#wa_acid_name").val(1);
									$("#wa_acid").val(row.m_amount * 1000);
									$("#wa_acid_perc").val(80);
									last_acid = 'Zoutzuur';
									break;
						case 'Fosforzuur':	$("#wa_acid_name").val(2);
									$("#wa_acid").val(row.m_amount * 1000);
									$("#wa_acid_perc").val(80);
									last_acid = 'Fosforzuur';
									break;
						case 'Zwavelzuur':	$("#wa_acid_name").val(3);
									$("#wa_acid").val(row.m_amount * 1000);
									$("#wa_acid_perc").val(80);
									last_acid = 'Zwavelzuur';
									break;
						case 'NaHCO3':		$("#wa_base_name").val(0);
									$("#wa_base").val(row.m_amount * 1000);
									last_base = 'NaHCO3';
									break;
						case 'Na2CO3':		$("#wa_base_name").val(1);
									$("#wa_base").val(row.m_amount * 1000);
									last_base = 'Na2CO3';
									break;
						case 'CaCO3':		$("#wa_base_name").val(2);
									$("#wa_base").val(row.m_amount * 1000);
									last_base = 'CaCO3';
									break;
						case 'Ca(OH)2':		$("#wa_base_name").val(3);
									$("#wa_base").val(row.m_amount * 1000);
									last_base = 'Ca(OH)2';
									break;
					}
				}
				return data;
			},
			loadError: function(jqXHR, status, error) {
				$('#err').text(status + ' ' + error);
			},
		});
                $("#miscGrid").jqxGrid({
                        width: 1240,
                        height: 575,
                        source: miscAdapter,
                        theme: theme,
                        selectionmode: 'singlerow',
                        showtoolbar: true,
                        rendertoolbar: function (toolbar) {
                                var me = this;
                                var container = $("<div style='overflow: hidden; position: relative; margin: 5px;'></div>");
                                toolbar.append(container);
                                container.append('<div style="float: left; margin-left: 165px;" id="maddrowbutton"></div>');
				container.append('<div style="float: left; margin-left: 10px; margin-top: 5px;">In voorraad:</div>');
				container.append('<div style="float: left; margin-left: 10px;" id="minstockbutton"></div>');
                                container.append('<input style="float: left; margin-left: 400px;" id="mdeleterowbutton" type="button" value="Verwijder ingredi&euml;nt" />');
                                // add misc from dropdownlist.
                                $("#maddrowbutton").jqxDropDownList({
                                        placeHolder: "Kies ingredi&euml;nt:",
                                        theme: theme,
					template: "primary",
                                        source: misclist,
                                        displayMember: "name",
                                        width: 150,
                                        height: 27,
                                        dropDownWidth: 500,
					dropDownHeight: 500
                                });
                                $("#maddrowbutton").on('select', function (event) {
                                        if (event.args) {
                                                var index = event.args.index;
                                                var datarecord = misclist.records[index];
                                                var row = {};
                                                row["m_name"] = datarecord.name;
                                                row["m_amount"] = 0;
                                                row["m_cost"] = datarecord.cost;
                                                row["m_type"] = datarecord.type;
                                                row["m_use_use"] = datarecord.use_use;
                                                row["m_time"] = 0;
                                                row["m_amount_is_weight"] = datarecord.amount_is_weight;
						row["m_inventory"] = datarecord.inventory;
                                                var commit = $("#miscGrid").jqxGrid('addrow', null, row);
                                        }
                                });
				$("#minstockbutton").jqxCheckBox({ theme: theme, height: 27 });
				$("#minstockbutton").on('change', function (event) {
					miscinstock = event.args.checked;
					misclist.dataBind();
				});
                                // delete selected misc.
                                $("#mdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                $("#mdeleterowbutton").on('click', function () {
                                        var selectedrowindex = $("#miscGrid").jqxGrid('getselectedrowindex');
                                        var rowscount = $("#miscGrid").jqxGrid('getdatainformation').rowscount;
					var type = $("#miscGrid").jqxGrid('getcellvalue', selectedrowindex, "m_type");
                                        if (selectedrowindex >= 0 && selectedrowindex < rowscount && type != 4) {	// Water agent
                                                var id = $("#miscGrid").jqxGrid('getrowid', selectedrowindex);
                                                var commit = $("#miscGrid").jqxGrid('deleterow', id);
                                        }
                                });
                        },
			ready: function() {
				$('#jqxTabs').jqxTabs('next');
			},
			columns: [
                                { text: 'Ingredient', datafield: 'm_name' },
                                { text: 'Type', width: 140, datafield: 'm_type',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<span style='margin: 3px; margin-top: 6px; float: left;'>" + MiscTypeData[value].nl + "</span>";
				  }
			       	},
                                { text: 'Gebruik', width: 140, datafield: 'm_use_use',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<span style='margin: 3px; margin-top: 6px; float: left;'>" + MiscUseData[value].nl + "</span>";
				  }
			       	},
                                { text: 'Tijd', datafield: 'm_time', width: 90, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var duration = '';
					if (rowdata.m_use_use == 2)     // Boil
						duration = dataAdapter.formatNumber(value, "f0")+" min.";
					else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4))  // Primary or Secondary
						duration = dataAdapter.formatNumber(value/1440, "f0")+" dagen";
					return  '<span style="margin: 4px; margin-top: 6px; float: right;">' + duration + '</span>';
				  },
                                },
				{ text: 'Hoeveel', datafield: 'm_amount', width: 110, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var vstr = rowdata.m_amount_is_weight ? "gr":"ml";
					return  '<span style="margin: 4px; margin-top: 6px; float: right;">' +
						dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr + '</span>';
				  },
				},
				{ text: 'Voorraad', datafield: 'm_inventory', width: 110, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var vstr = rowdata.m_amount_is_weight ? "gr":"ml";
					var color = '#ffffff';
					if (value < rowdata.m_amount)
						color = '#ff4040';
					var amount = dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr;
					return  '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>';
				  },
				},
				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
					return "Wijzig";
					}, buttonclick: function (row) {
						miscRow = row;
						miscData = $("#miscGrid").jqxGrid('getrowdata', miscRow);
						if (miscData.m_amount_is_weight)
							$("#wm_pmpt_amount").html("Gewicht gram:");
						else
							$("#wm_pmpt_amount").html("Volume ml:");
						$("#wm_name").val(miscData.m_name);
						$("#wm_amount").val(miscData.m_amount * 1000);
						if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4))	// Primary or Secondary
							$("#wm_time").val(miscData.m_time / 1440);
						else
							$("#wm_time").val(miscData.m_time);
						$("#wm_use_use").val(miscData.m_use_use);
						// show the popup window.
						if (miscData.m_type != 4)
							$("#popupMisc").jqxWindow('open');
					}
				}
                        ]
                });
        };

	// Inline yeasts editor
        var editYeast = function (data) {
                var yeastSource = {
                        localdata: data.yeasts,
                        datatype: "local",
                        cache: false,
			async: false,
                        datafields: [
                                { name: 'y_name', type: 'string' },
				{ name: 'y_laboratory', type: 'string' },
				{ name: 'y_product_id', type: 'string' },
                                { name: 'y_amount', type: 'float' },
                                { name: 'y_cost', type: 'float' },
                                { name: 'y_type', type: 'int' },
                                { name: 'y_form', type: 'int' },
				{ name: 'y_flocculation', type: 'int' },
				{ name: 'y_min_temperature', type: 'float' },
				{ name: 'y_max_temperature', type: 'float' },
				{ name: 'y_attenuation', type: 'float' },
				{ name: 'y_use', type: 'int' },
				{ name: 'y_cells', type: 'float' },
				{ name: 'y_inventory', type: 'float' },
				{ name: 'y_avail', type: 'int' }
                        ],
                        addrow: function (rowid, rowdata, position, commit) {
                                commit(true);
                        },
                        deleterow: function (rowid, commit) {
                                commit(true);
                        }
                };
                var yeastAdapter = new $.jqx.dataAdapter(yeastSource);
                $("#yeastGrid").jqxGrid({
                        width: 1240,
                        height: 350,
                        source: yeastAdapter,
                        theme: theme,
                        selectionmode: 'singlerow',
                        showtoolbar: true,
                        rendertoolbar: function (toolbar) {
                                var me = this;
                                var container = $("<div style='overflow: hidden; position: relative; margin: 5px;'></div>");
                                toolbar.append(container);
                                container.append('<div style="float: left; margin-left: 165px;" id="yaddrowbutton"></div>');
				container.append('<div style="float: left; margin-left: 10px; margin-top: 5px;">In voorraad:</div>');
				container.append('<div style="float: left; margin-left: 10px;" id="yinstockbutton"></div>');
                                container.append('<input style="float: left; margin-left: 400px;" id="ydeleterowbutton" type="button" value="Verwijder gist" />');
                                // add yeast from dropdownlist.
                                $("#yaddrowbutton").jqxDropDownList({
                                        placeHolder: "Kies gist:",
                                        theme: theme,
					template: "primary",
                                        source: yeastlist,
                                        displayMember: "name",
                                        width: 150,
                                        height: 27,
                                        dropDownWidth: 500,
					dropDownHeight: 500,
					renderer: function (index, label, value) {
						var datarecord = yeastlist.records[index];
						return datarecord.laboratory+" "+datarecord.product_id+" "+datarecord.name;
					}
                                });
                                $("#yaddrowbutton").on('select', function (event) {
                                        if (event.args) {
                                                var index = event.args.index;
                                                var datarecord = yeastlist.records[index];
                                                var row = {};
                                                row["y_name"] = datarecord.name;
						row["y_laboratory"] = datarecord.laboratory;
						row["y_product_id"] = datarecord.product_id;
						row["y_type"] = datarecord.type;
						row["y_form"] = datarecord.form;
                                                row["y_amount"] = 0;
                                                row["y_cost"] = datarecord.cost;
                                                row["y_use"] = 0;
						row["y_min_temperature"] = datarecord.min_temperature;
						row["y_max_temperature"] = datarecord.max_temperature;
						row["y_attenuation"] = datarecord.attenuation;
						row["y_flocculation"] = datarecord.flocculation;
						row["y_cells"] = datarecord.cells;
						row["y_inventory"] = datarecord.inventory;
                                                var commit = $("#yeastGrid").jqxGrid('addrow', null, row);
                                        }
					$("#yaddrowbutton").jqxDropDownList('clearSelection');
                                });
				$("#yinstockbutton").jqxCheckBox({ theme: theme, height: 27 });
				$("#yinstockbutton").on('change', function (event) {
					yeastinstock = event.args.checked;
					yeastlist.dataBind();
				});
                                // delete selected yeast.
                                $("#ydeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                $("#ydeleterowbutton").on('click', function () {
                                        var selectedrowindex = $("#yeastGrid").jqxGrid('getselectedrowindex');
                                        var rowscount = $("#yeastGrid").jqxGrid('getdatainformation').rowscount;
                                        if (selectedrowindex >= 0 && selectedrowindex < rowscount) {
                                                var id = $("#yeastGrid").jqxGrid('getrowid', selectedrowindex);
                                                var commit = $("#yeastGrid").jqxGrid('deleterow', id);
                                        }
                                });
                        },
			ready: function() {
				calcFermentables();
				$('#jqxTabs').jqxTabs('next');
			},
                        columns: [
                                { text: 'Gist', datafield: 'y_name' },
				{ text: 'Laboratorium', width: 150, datafield: 'y_laboratory' },
				{ text: 'Code', width: 90, datafield: 'y_product_id' },
                                { text: 'Soort', width: 100, datafield: 'y_form',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return  '<span style="margin: 4px; margin-top: 6px; float: left;">' + YeastFormData[value].nl + '</span>';
				  }
				},
				{ text: 'Min. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' },
				{ text: 'Max. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' },
				{ text: 'Attn. %', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' },
				{ text: 'Voor', width: 120, datafield: 'y_use',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return  '<span style="margin: 4px; margin-top: 6px; float: left;">' + YeastUseData[value].nl + '</span>';
				  }
				},
				{ text: 'Hoeveel', datafield: 'y_amount', width: 100, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var amount = dataAdapter.formatNumber(value*1000, "f0")+" ml";
					if (rowdata.y_form == 0)        // Liquid
						amount = dataAdapter.formatNumber(value, "f0")+" pk";
					else if (rowdata.y_form == 1)   // Dry
						amount = dataAdapter.formatNumber(value*1000, "f1")+" gr";
					return  '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>';
                                  }
                                },
				{ text: 'Voorraad', datafield: 'y_inventory', width: 100, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					var color = '#ffffff';
					if (value < rowdata.y_amount)
						color = '#ff4040';
					var amount = dataAdapter.formatNumber(value*1000, "f0")+" ml";
					if (rowdata.y_form == 0)        // Liquid
						amount = dataAdapter.formatNumber(value, "f0")+" pk";
					else if (rowdata.y_form == 1)   // Dry
						amount = dataAdapter.formatNumber(value*1000, "f1")+" gr";
					return  '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>';
				  }
				},
				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
					return "Wijzig";
					}, buttonclick: function (row) {
						yeastRow = row;
						yeastData = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
						if (yeastData.y_form == 0) {
							$("#wy_pmpt_amount").html("Pak(ken):");
							$("#wy_amount").val(yeastData.y_amount);
							$("#wy_amount").jqxNumberInput({ decimalDigits: 0 });
						} else if (yeastData.y_form == 1) {
							$("#wy_pmpt_amount").html("Gewicht gram:");
							$("#wy_amount").val(yeastData.y_amount * 1000);
							$("#wy_amount").jqxNumberInput({ decimalDigits: 1 });
						} else {
							$("#wy_pmpt_amount").html("Volume ml:");
							$("#wy_amount").val(yeastData.y_amount * 1000);
							$("#wy_amount").jqxNumberInput({ decimalDigits: 0 });
						}
						$("#wy_name").val(yeastData.y_name);
						$("#wy_laboratory").val(yeastData.y_laboratory);
						$("#wy_product_id").val(yeastData.y_product_id);
						$("#wy_use").val(yeastData.y_use);
						// show the popup window.
						$("#popupYeast").jqxWindow('open');
					}
				}
                        ]
                });
        };

	// inline mash editor
        var editMash = function (data) {
		var generaterow = function () {
			var row = {};
			row["step_name"] = "Stap 1";
			row["step_type"] = 0;
			row["step_infuse_amount"] = 15;
			row["step_temp"] = 62.0;
			row['step_time'] = 20.0;
			row['ramp_time'] = 1.0;
			row['end_temp'] = 62.0;
			return row;
		}
                var mashSource = {
                        localdata: data.mashs,
                        datatype: "local",
                        cache: false,
			async: false,
                        datafields: [
                                { name: 'step_name', type: 'string' },
                                { name: 'step_type', type: 'int' },
				{ name: 'step_infuse_amount', type: 'float' },
				{ name: 'step_temp', type: 'float' },
				{ name: 'step_time', type: 'float' },
				{ name: 'ramp_time', type: 'float' },
				{ name: 'end_temp', type: 'float' }
                        ],
                        addrow: function (rowid, rowdata, position, commit) {
                                commit(true);
                        },
                        deleterow: function (rowid, commit) {
                                commit(true);
                        }
                };
                var mashAdapter = new $.jqx.dataAdapter(mashSource, {
			beforeLoadComplete: function (records) {
				mash_infuse = 0;
				var data = new Array();
				for (var i = 0; i < records.length; i++) {
					var row = records[i];
					if (row.step_type == 0)	// Infusion
						mash_infuse += parseFloat(row.step_infuse_amount);
				}
			},	
		});
                $("#mashGrid").jqxGrid({
                        width: 1240,
                        height: 400,
                        source: mashAdapter,
                        theme: theme,
                        selectionmode: 'singlerow',
                        showtoolbar: true,
                        rendertoolbar: function (toolbar) {
                                var me = this;
                                var container = $("<div style='overflow: hidden; position: relative; margin: 5px;'></div>");
                                toolbar.append(container);
                                container.append('<input style="float: left; margin-left: 165px;" id="saddrowbutton" type="button" value="Nieuwe stap" />');
                                container.append('<input style="float: left; margin-left: 565px;" id="sdeleterowbutton" type="button" value="Verwijder stap" />');
				$("#saddrowbutton").jqxButton({ template: "primary", theme: theme, height: 27, width: 150 });
				$("#saddrowbutton").on('click', function () {
					var datarow = generaterow();
					var commit = $("#mashGrid").jqxGrid('addrow', null, datarow);
				});
                                // delete selected yeast.
                                $("#sdeleterowbutton").jqxButton({ template: "danger", theme: theme, height: 27, width: 150 });
                                $("#sdeleterowbutton").on('click', function () {
                                        var selectedrowindex = $("#mashGrid").jqxGrid('getselectedrowindex');
                                        var rowscount = $("#mashGrid").jqxGrid('getdatainformation').rowscount;
                                        if (selectedrowindex >= 0 && selectedrowindex < rowscount) {
                                                var id = $("#mashGrid").jqxGrid('getrowid', selectedrowindex);
                                                var commit = $("#mashGrid").jqxGrid('deleterow', id);
                                        }
                                });
                        },
			ready: function() {
				calcFermentables();
				calcInit();
				$('#jqxLoader').jqxLoader('close');
				$('#jqxTabs').jqxTabs('first');
		//		setReadonly(dataRecord.locked);
			},
                        columns: [
				{ text: 'Stap naam', datafield: 'step_name' },
			        { text: 'Stap type', datafield: 'step_type', width: 175,
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<div style='margin: 4px;'>" + MashStepTypeData[value].nl + "</div>";
				  }
				},
				{ text: 'Start &deg;C', datafield: 'step_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' },
				{ text: 'Eind &deg;C', datafield: 'end_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' },
				{ text: 'Rust min.', datafield: 'step_time', width: 90, align: 'right', cellsalign: 'right' },
				{ text: 'Stap min.', datafield: 'ramp_time', width: 90, align: 'right', cellsalign: 'right' },
				{ text: 'Infuse L.', datafield: 'step_infuse_amount', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' },
				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
					return "Wijzig";
					}, buttonclick: function (row) {
						mashRow = row;
						mashData = $("#mashGrid").jqxGrid('getrowdata', mashRow);
						$("#wstep_name").val(mashData.step_name);
						$("#wstep_type").val(mashData.step_type);
						$("#wstep_infuse_amount").val(mashData.step_infuse_amount);
						$("#wstep_temp").val(mashData.step_temp);
						$("#wend_temp").val(mashData.end_temp);
						$("#wstep_time").val(mashData.step_time);
						$("#wramp_time").val(mashData.ramp_time);
						if (mashData.step_type == 0) {
							$("#wstep_infuse_amount").show();
							$("#wstep_pmpt").show();
						} else {
							$("#wstep_infuse_amount").hide();
							$("#wstep_pmpt").hide();
						}
						// show the popup window.
						$("#popupMash").jqxWindow('open');
					}
				}
                        ]
                });
        };

	// initialize the input fields.
	// Tab 1, Algemeen
	$("#name").jqxTooltip({ content: 'De naam voor dit recept.' });
	$("#name").jqxInput({ theme: theme, width: 640, height: 23 });
	$("#locked").jqxCheckBox({ theme: theme, width: 120, height: 23 });
	$("#notes").jqxTooltip({ content: 'De uitgebreide opmerkingen over dit recept.' });
	$("#notes").jqxInput({ theme: theme, width: 960, height: 200 });
	$("#type").jqxTooltip({ content: 'Het brouw type van dit recept.' });
	$("#type").jqxDropDownList({
		theme: theme,
		source: RecipeTypeAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true
	});
	$("#efficiency").jqxTooltip({ content: 'Het rendement van maischen en koken.' });
	$("#efficiency").jqxNumberInput( Perc1dec );
	$("#batch_size").jqxTooltip({ content: 'Het volume van het gekoelde wort na het koken.' });
	$("#batch_size").jqxNumberInput( Spin1dec );
	$("#batch_size").jqxNumberInput({ min: 4 });
	$("#boil_size").jqxTooltip({ content: 'Het volume van het wort voor het koken.' });
	$("#boil_size").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 2, readOnly: true });
	$("#boil_time").jqxTooltip({ content: 'De kooktijd in minuten.' });
	$("#boil_time").jqxNumberInput( PosInt );
	$("#boil_time").jqxNumberInput({ min: 4, max: 360 });

	$("#st_name").jqxTooltip({ content: 'De bierstijl naam voor dit recept.'});
	$("#st_name").jqxInput({ theme: theme, width: 250, height: 23 });
	$("#st_letter").jqxTooltip({ content: 'De bierstijl letter voor dit recept.'});
	$("#st_letter").jqxInput({ theme: theme, width: 100, height: 23 });
	$("#st_guide").jqxTooltip({ content: 'De bierstijl gids voor dit recept.'});
	$("#st_guide").jqxInput({ theme: theme, width: 250, height: 23 });
	$("#st_category").jqxTooltip({ content: 'De Amerikaanse bierstijl categorie.'});
	$("#st_category").jqxInput({ theme: theme, width: 250, height: 23 });
	$("#st_category_number").jqxTooltip({ content: 'De Amerikaanse bierstijl categorie sub nummer.'});
	$("#st_category_number").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
	$("#st_type").jqxTooltip({ content: 'Het bierstijl type.'});
	$("#st_type").jqxInput({ theme: theme, width: 250, height: 23 });

	$("#est_og").jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' });
	$("#est_og").jqxNumberInput( SGopts );
	$("#st_og_min").jqxTooltip({ content: 'Het minimum begin SG voor deze bierstijl.'});
	$("#st_og_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
	$("#st_og_max").jqxTooltip({ content: 'Het maximum begin SG voor deze bierstijl.'});
	$("#st_og_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });

	$("#est_fg").jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' });
	$("#est_fg").jqxNumberInput( Show3dec );
	$("#st_fg_min").jqxTooltip({ content: 'Het minimum eind SG voor deze bierstijl.'});
	$("#st_fg_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
	$("#st_fg_max").jqxTooltip({ content: 'Het maximum eind SG voor deze bierstijl.'});
	$("#st_fg_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });

	$("#est_abv").jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' });
	$("#est_abv").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
	$("#st_abv_min").jqxTooltip({ content: 'Het minimum alcohol volume % voor deze bierstijl.'});
	$("#st_abv_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
	$("#st_abv_max").jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'});
	$("#st_abv_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });

	$("#est_color").jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' });
	$("#est_color").jqxNumberInput( Show0dec );
	$("#st_color_min").jqxTooltip({ content: 'De minimum kleur voor deze bierstijl.'});
	$("#st_color_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
	$("#st_color_max").jqxTooltip({ content: 'De maximum kleur voor deze bierstijl.'});
	$("#st_color_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
	$("#color_method").jqxDropDownList({
		theme: theme,
		source: ColorMethodAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true
	});

	$("#est_ibu").jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' });
	$("#est_ibu").jqxNumberInput( Show0dec );
	$("#st_ibu_min").jqxTooltip({ content: 'De minimum bitterheid voor deze bierstijl.'});
	$("#st_ibu_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
	$("#st_ibu_max").jqxTooltip({ content: 'De maximum bitterheid voor deze bierstijl.'});
	$("#st_ibu_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
	$("#ibu_method").jqxDropDownList({
		theme: theme,
		source: IBUmethodAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true,
		dropDownVerticalAlignment: 'top'
	});

	$("#est_carb").jqxTooltip({ content: 'Koolzuur volume. Dit wordt automatisch berekend.' });
	$("#est_carb").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
	$("#st_carb_min").jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'});
	$("#st_carb_min").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
	$("#st_carb_max").jqxTooltip({ content: 'Het maximum koolzuur volume voor deze bierstijl.'});
	$("#st_carb_max").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });

	// Tab 2, Vergistbaar
	$("#est_color2").jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' });
	$("#est_color2").jqxNumberInput( Show0dec );
	$("#est_og2").jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' });
	$("#est_og2").jqxNumberInput( Show3dec );
	$("#perc_malts").jqxProgressBar({
		width: 300,
		height: 23,
		theme: theme,
		showText: true,
		animationDuration: 0,
		colorRanges: [
			{ stop:  90, color: '#008C00' },
			{ stop:  95, color: '#EB7331' },
			{ stop: 100, color: '#FF0000' }
		]
	});
	$("#perc_sugars").jqxProgressBar({
		width: 300,
		height: 23,
		theme: theme,
		showText: true,
		animationDuration: 0,
		colorRanges: [
			{ stop:  20, color: '#008C00' },
			{ stop: 100, color: '#FF0000' }
		]
	});
	$("#perc_cara").jqxProgressBar({
		width: 300,
		height: 23,
		theme: theme,
		showText: true,
		animationDuration: 0,
		colorRanges: [
			{ stop:  25, color: '#008C00' },
			{ stop: 100, color: '#FF0000' }
		]
	});
	$("#popupFermentable").jqxWindow({
		width: 800,
		height: 300,
		position: { x: 230, y: 100 },
		resizable: false,
		theme: theme,
		isModal: true,
		autoOpen: false,
		cancelButton: $("#FermentableReady"),
		modalOpacity: 0.40
	});
	$("#FermentableReady").jqxButton({ template: "success", width: '90px', theme: theme });
	$("#FermentableReady").click(function () {
		$("#fermentableGrid").jqxGrid('sortby', 'f_amount', 'desc');
		// Recalc percentages
		calcFermentables();
		calcIBUs();
		// Waters: yes there is impact.
	});
	$("#wf_name").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#wf_instock").jqxCheckBox({ theme: theme, height: 23 });
	$("#wf_instock").on('change', function (event) {
		fermentableinstock = event.args.checked;
		fermentablelist.dataBind();
	});
	$("#wf_select").jqxDropDownList({
		placeHolder: "Kies mout:",
		theme: theme,
		source: fermentablelist,
		displayMember: "name",
		width: 150,
		height: 23,
		dropDownWidth: 500,
		dropDownHeight: 500,
		renderer: function (index, label, value) {
			var datarecord = fermentablelist.records[index];
			return datarecord.supplier+ " / " + datarecord.name + " (" + datarecord.color + " EBC)";
		}
	});
	$("#wf_select").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = fermentablelist.records[index];
			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
			$("#wf_name").val(datarecord.name);
			rowdata.f_name = datarecord.name;
			rowdata.f_origin = datarecord.origin;
			rowdata.f_supplier = datarecord.supplier;
			rowdata.f_type = datarecord.type;
			rowdata.f_cost = datarecord.cost;
			rowdata.f_yield = datarecord.yield;
			rowdata.f_color = datarecord.color;
			rowdata.f_coarse_fine_diff = datarecord.coarse_fine_diff;
			rowdata.f_moisture = datarecord.moisture;
			rowdata.f_diastatic_power = datarecord.diastatic_power;
			rowdata.f_protein = datarecord.protein;
			rowdata.f_max_in_batch = datarecord.max_in_batch;
			rowdata.f_graintype = datarecord.graintype;
			rowdata.f_dissolved_protein = datarecord.dissolved_protein;
			rowdata.f_recommend_mash = datarecord.recommend_mash;
			rowdata.f_add_after_boil = datarecord.add_after_boil;
			rowdata.f_di_ph = datarecord.di_ph;
			rowdata.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
			rowdata.f_inventory = datarecord.inventory;
		}
	});
	$("#wf_amount").jqxNumberInput( Spin3dec );
	$('#wf_amount').on('change', function (event) {
		console.log("amount changed: "+event.args.value);
		$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', event.args.value);
		if (! to_100) {
			// Recalculate percentages
			console.log("adjust percentages");
			var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
			if (rowscount > 1) {
				var tw = 0;
				for (i = 0; i < rowscount; i++) {
					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
					tw += rowdata.f_amount;
				};
				for (i = 0; i < rowscount; i++) {
					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
					var percentage = Math.round(rowdata.f_amount / tw * 1000) / 10.0;
					$("#fermentableGrid").jqxGrid('setcellvalue', i, "f_percentage", percentage);
		//			if (i == fermentableRow) // Will crash the script.
		//				$("#wf_percentage").val(percentage);
				};
			} else {
				$("#fermentableGrid").jqxGrid('setcellvalue', 0, "f_percentage", 100);
			}
			calcFermentables();
		};
	});
	$("#wf_percentage").jqxNumberInput( Perc1dec );
	$("#wf_percentage").on('change', function (event) {
		var oldvalue = Math.round(fermentableData.f_percentage * 10) / 10.0;
		var newvalue = event.args.value;
		console.log("percentage changed: "+newvalue+" old: "+oldvalue);
		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
		if ((oldvalue != newvalue) && (rowscount > 1)) {
			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
			if (rowdata.f_adjust_to_total_100) {
				$("#wf_percentage").val(oldvalue);
			} else {
				var diff = newvalue - oldvalue;
				var tw = 0;     // total weight
				for (i = 0; i < rowscount; i++) {
					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
					tw += rowdata.f_amount;
				}
				if (to_100) {
					// Adjust this row and the 100% row.
					var damount = tw * diff / 100;
					var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
					var namount = rowdata.f_amount + damount;
					$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', namount);
					$("#wf_amount").val(namount);
					$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_percentage', rowdata.f_percentage + diff);
					for (i = 0; i < rowscount; i++) {
						var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
						if (rowdata.f_adjust_to_total_100) {
							namount = rowdata.f_amount - damount;
							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', rowdata.f_percentage - diff);
							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
						}
					}
					calcFermentables();
				} else {
					// Adjust all the rows.
					var nw = tw * diff / 100;
					for (i = 0; i < rowscount; i++) {
						var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', i);
						if (i == fermentableRow) {
							var namount = rowdata.f_amount + nw;
							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
		//					$("#wf_amount").val(namount); // Will crash the script.
							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newvalue);
						} else {
							var namount = rowdata.f_amount - (nw / (rowscount - 1));
							var newperc = Math.round((namount / tw) * 1000) / 10.0;
							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_amount', namount);
							$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_percentage', newperc);
						}
					}
					calcFermentables();
				}
			}
		}

	});
	$("#wf_adjust_to_total_100").jqxCheckBox({ theme: theme, width: 120, height: 23 });
	$("#wf_adjust_to_total_100").on('checked', function (event) {
		if (fermentableData.f_adjust_to_total_100 == 0) {
			if (to_100) {
				// Reset other flag first.
				var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
				for (var i = 0; i < rowscount; i++) {
					if (i != fermentableRow) {
						$("#fermentableGrid").jqxGrid('setcellvalue', i, 'f_adjust_to_total_100', 0);
					}
				}
			}
			$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_adjust_to_total_100', 1);
			calcFermentables();
		}
	});
	$("#wf_adjust_to_total_100").on('unchecked', function (event) {
		if (fermentableData.f_adjust_to_total_100 != 0) {
			$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_adjust_to_total_100', 0);
			calcFermentables();
		}
	});
	$("#wf_added").jqxDropDownList({
		theme: theme,
		source: AddedAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true,
		dropDownVerticalAlignment: 'top'
	});
	$("#wf_added").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_added', index);
			calcFermentables();
			calcIBUs();
		}
	});

	// Tab 3, Hoppen
	$("#est_ibu2").jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' });
	$("#est_ibu2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 0, readOnly: true });
	$("#hop_flavour").jqxProgressBar({
		width: 300,
		height: 23,
		theme: theme,
		showText: true,
		animationDuration: 0,
		colorRanges: [
			{ stop:  20, color: '#004D00' },
			{ stop:  40, color: '#008C00' },
			{ stop:  60, color: '#00BF00' },
			{ stop:  80, color: '#00FF00' },
			{ stop: 100, color: '#80FF80' }
		]
	});
	$("#hop_aroma").jqxProgressBar({
		width: 300,
		height: 23,
		theme: theme,
		showText: true,
		animationDuration: 0,
		colorRanges: [
			{ stop:  20, color: '#004D00' },
			{ stop:  40, color: '#008C00' },
			{ stop:  60, color: '#00BF00' },
			{ stop:  80, color: '#00FF00' },
			{ stop: 100, color: '#80FF80' }
		]
	});
	$("#popupHop").jqxWindow({
		width: 800,
		height: 300,
		position: { x: 230, y: 100 },
		resizable: false,
		theme: theme,
		isModal: true,
		autoOpen: false,
		cancelButton: $("#HopReady"),
		modalOpacity: 0.40
	});
	$("#HopReady").jqxButton({ template: "success", width: '90px', theme: theme });
	$("#HopReady").click(function () {
		$("#hopGrid").jqxGrid('sortby', 'h_amount', 'asc');
		calcIBUs();
	});
	$("#wh_name").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#wh_instock").jqxCheckBox({ theme: theme, height: 23 });
	$("#wh_instock").on('change', function (event) {
		hopinstock = event.args.checked;
		hoplist.dataBind();
	});
	$("#wh_select").jqxDropDownList({
		placeHolder: "Kies hop:",
		theme: theme,
		source: hoplist,
		displayMember: "name",
		width: 150,
		height: 23,
		dropDownWidth: 500,
		dropDownHeight: 500,
		renderer: function (index, label, value) {
			var datarecord = hoplist.records[index];
			return datarecord.origin+ " / " + datarecord.name + " (" + datarecord.alpha + " % &alpha;)";
		}
	});
	$("#wh_select").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = hoplist.records[index];
			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
			$("#wh_name").val(datarecord.name);
			rowdata.h_name = datarecord.name;
			rowdata.h_origin = datarecord.origin;
			rowdata.h_cost = datarecord.cost;
			rowdata.h_type = datarecord.type;
			rowdata.h_form = datarecord.form;
			rowdata.h_alpha = datarecord.alpha;
			rowdata.h_beta = datarecord.beta;
			rowdata.h_hsi = datarecord.hsi;
			rowdata.h_humulene = datarecord.humulene;
			rowdata.h_caryophyllene = datarecord.caryophyllene;
			rowdata.h_cohumulone = datarecord.cohumulone;
			rowdata.h_myrcene = datarecord.myrcene;
			rowdata.h_total_oil = datarecord.total_oil;
			rowdata.h_inventory = datarecord.inventory;
		}
	});
	$("#wh_amount").jqxNumberInput( Spin1dec );
	$('#wh_amount').on('change', function (event) {
		console.log("amount changed: "+event.args.value);
		var amount = parseFloat(event.args.value) / 1000;
		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);

		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg,
			parseFloat($("#batch_size").jqxNumberInput('decimal')),
			amount, parseFloat(rowdata.h_time),
			parseFloat(rowdata.h_alpha), $("#ibu_method").val()
		);
		rowdata.h_amount = amount;
		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
				parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
		$("#wh_ibu").val(ibu);
		calcIBUs();
	});
	$("#wh_ibu").jqxNumberInput( Show1dec );
	$("#wh_time").jqxNumberInput( PosInt );
	$("#wh_time").on('change', function (event) {
		console.log("time changed: "+event.args.value);
		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
		var newtime = parseFloat(event.args.value);
		// Check limits and correct
		if (rowdata.h_useat == 2) {	// Boil
			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
				$("#wh_time").val(newtime);
			}
			rowdata.h_time = newtime;
		} else if (rowdata.h_useat == 4) {	// Whirlpool
			if (newtime > 120) {
				newtime = 120;
				$("#wh_time").val(newtime);
			}
			rowdata.h_time = newtime;
		} else if (rowdata.h_useat == 5) {	// Dry hop
			if (newtime > 21) {
				newtime = 21;
				$("#wh_time").val(newtime);
			}
			rowdata.h_time = newtime * 1440;
		}
		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
			parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
		$("#wh_ibu").val(ibu);
		calcIBUs();
	});
	$("#wh_useat").jqxDropDownList({
		theme: theme,
		source: HopUseAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true,
		dropDownVerticalAlignment: 'top'
	});
	$("#wh_useat").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
			rowdata.h_useat = index;
			if ((index == 0) || (index == 1)) {	// Mashhop or First wort hop
				rowdata.h_time = parseFloat(dataRecord.boil_time);
				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
				$("#wh_time").val(rowdata.h_time);
			} else if (index == 3) {	// Aroma
				rowdata.h_time = 0;
				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
				$("#wh_time").val(0);
			} else {	// Boil, Whirlpool or Dry hop
				$("#wh_time").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
			}
			if (index == 5)	// Dry hop
				$("#wh_pmpt_time").html("Tijd in dagen");
			else
				$("#wh_pmpt_time").html("Tijd in minuten");
		}
	});

	// Tab 4, Diversen
	$("#popupMisc").jqxWindow({
		width: 800,
		height: 275,
		position: { x: 230, y: 100 },
		resizable: false,
		theme: theme,
		isModal: true,
		autoOpen: false,
		cancelButton: $("#MiscReady"),
		modalOpacity: 0.40
	});
	$("#MiscReady").jqxButton({ template: "success", width: '90px', theme: theme });
	$("#MiscReady").click(function () {
		$("#miscGrid").jqxGrid('sortby', 'm_use_use', 'asc');
	});
	$("#wm_name").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#wm_instock").jqxCheckBox({ theme: theme, height: 23 });
	$("#wm_instock").on('change', function (event) {
		miscinstock = event.args.checked;
		misclist.dataBind();
	});
	$("#wm_select").jqxDropDownList({
		placeHolder: "Kies ingredi&euml;nt:",
		theme: theme,
		source: misclist,
		displayMember: "name",
		width: 150,
		height: 23,
		dropDownWidth: 500,
		dropDownHeight: 500
	});
	$("#wm_select").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = misclist.records[index];
			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
			$("#wm_name").val(datarecord.name);
			rowdata.m_name = datarecord.name;
			rowdata.m_cost = datarecord.cost;
			rowdata.m_type = datarecord.type;
			rowdata.m_use_use = datarecord.use_use;
			rowdata.m_amount_is_weight = datarecord.amount_is_weight;
			rowdata.m_inventory = datarecord.inventory;
		}
	});
	$("#wm_amount").jqxNumberInput( Spin1dec );
	$('#wm_amount').on('change', function (event) {
		console.log("amount changed: "+event.args.value);
		var amount = parseFloat(event.args.value) / 1000;
		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
		rowdata.m_amount = amount;
	});
	$("#wm_time").jqxNumberInput( PosInt );
	$("#wm_time").on('change', function (event) {
		console.log("time changed: "+event.args.value);
		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
		var newtime = parseFloat(event.args.value);

		if (rowdata.m_use_use == 2) {	// Boil
			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
				$("#wm_time").val(newtime);
			}
		        rowdata.m_time = newtime;
		} else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) {	// Primary or Secondary
			if (newtime > 21) {
				newtime = 21;
				$("#wm_time").val(newtime);
			}
			rowdata.m_time = newtime * 1440;
		}
	});
	$("#wm_use_use").jqxDropDownList({
		theme: theme,
		source: MiscUseAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true,
		dropDownVerticalAlignment: 'top'
	});
	$("#wm_use_use").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
			rowdata.m_use_use = index;
			if ((index == 2) || (index == 3) || (index == 4)) {	// Boil, Primary or Secondary
				$("#wm_time").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
			} else {
				rowdata.m_time = 0;
				$("#wm_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
				$("#wm_time").val(0);
			}
		}
	});

	// Tab 5, Gist
	$("#est_fg2").jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' });
	$("#est_fg2").jqxNumberInput( Show3dec );
	$("#est_abv2").jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' });
	$("#est_abv2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
	$("#popupYeast").jqxWindow({
		width: 800,
		height: 300,
		position: { x: 230, y: 100 },
		resizable: false,
		theme: theme,
		isModal: true,
		autoOpen: false,
		cancelButton: $("#YeastReady"),
		modalOpacity: 0.40
	});
	$("#YeastReady").jqxButton({ template: "success", width: '90px', theme: theme });
	$("#YeastReady").click(function () {
		calcFermentables();
		$("#yeastGrid").jqxGrid('sortby', 'y_use', 'asc');
	});
	$("#wy_name").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#wy_laboratory").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#wy_product_id").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#wy_instock").jqxCheckBox({ theme: theme, height: 23 });
	$("#wy_instock").on('change', function (event) {
		yeastinstock = event.args.checked;
		yeastlist.dataBind();
	});
	$("#wy_select").jqxDropDownList({
		placeHolder: "Kies gist:",
		theme: theme,
		source: yeastlist,
		displayMember: "name",
		width: 150,
		height: 23,
		dropDownWidth: 500,
		dropDownHeight: 500,
		renderer: function (index, label, value) {
			var datarecord = yeastlist.records[index];
			return datarecord.laboratory+" "+datarecord.product_id+" "+datarecord.name;
		}
	});
	$("#wy_select").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = yeastlist.records[index];
			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
			$("#wy_name").val(datarecord.name);
			$("#wy_laboratory").val(datarecord.laboratory);
			$("#wy_product_id").val(datarecord.product_id);
			rowdata.y_name = datarecord.name;
			rowdata.y_cost = datarecord.cost;
			rowdata.y_type = datarecord.type;
			rowdata.y_form = datarecord.form;
			rowdata.y_laboratory = datarecord.laboratory;
			rowdata.y_product_id = datarecord.product_id;
			rowdata.y_min_temperature = datarecord.min_temperature;
			rowdata.y_max_temperature = datarecord.max_temperature;
			rowdata.y_flocculation = datarecord.flocculation;
			rowdata.y_attenuation = datarecord.attenuation;
			rowdata.y_cells = datarecord.cells;
			rowdata.y_inventory = datarecord.inventory;
			if (rowdata.y_form == 0) {
				$("#wy_pmpt_amount").html("Pak(ken):");
			} else if (rowdata.y_form == 1) {
				$("#wy_pmpt_amount").html("Gewicht gram:");
			} else {
				$("#wy_pmpt_amount").html("Volume ml:");
			}
			calcFermentables();
		}
	});
	$("#wy_amount").jqxNumberInput( Spin1dec );
	$('#wy_amount').on('change', function (event) {
		console.log("amount changed: "+event.args.value);
		var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
		if (rowdata.y_form == 0)	// Liquid
			var amount = parseFloat(event.args.value);
		else
			var amount = parseFloat(event.args.value) / 1000;
		rowdata.y_amount = amount;
		calcFermentables();
	});
	$("#wy_use").jqxDropDownList({
		theme: theme,
		source: YeastUseAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true,
		dropDownVerticalAlignment: 'top'
	});
	$("#wy_use").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
			rowdata.y_use = index;
			calcFermentabes();
		}
	});

	// Tab 6, Maischen
	$("#mash_name").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#mash_select").jqxDropDownList({
		placeHolder: "Kies schema:",
		theme: theme,
		source: mashlist,
		displayMember: "name",
		width: 250,
		height: 23,
		dropDownWidth: 500,
		dropDownHeight: 500,
		dropDownHorizontalAlignment: 'right'
	});
	$("#mash_select").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			// First delete all current steps
			var rowIDs = new Array();
			var rows = $("#mashGrid").jqxGrid('getdisplayrows');
			for (var i = 0; i < rows.length; i++) {
				var row = rows[i];
				rowIDs.push(row.uid);
			}
			$("#mashGrid").jqxGrid('deleterow', rowIDs);
			// Then add the new steps
			var datarecord = mashlist.records[index];
			$("#mash_name").val(datarecord.name);
			for (var i = 0; i < datarecord.steps.length; i++) {
				var data = datarecord.steps[i];
				var row = {};
				row["step_name"] = data.step_name;
				row["step_type"] = data.step_type;
				// For now, but this must be smarter.
				if (mash_infuse == 0 && dataRecord.w1_amount > 0)
					mash_infuse = dataRecord.w1_amount;
				if (i == 0)
					row["step_infuse_amount"] = mash_infuse;
				else
					row["step_infuse_amount"] = 0;
				row["step_temp"] = data.step_temp;
				row["end_temp"] = data.end_temp;
				row["step_time"] = data.step_time;
				row["ramp_time"] = data.ramp_time;
				var commit = $("#mashGrid").jqxGrid('addrow', null, row);
			}
		}
	});
	$("#popupMash").jqxWindow({
		width: 800,
		height: 350,
		position: { x: 230, y: 100 },
		resizable: false,
		theme: theme,
		isModal: true,
		autoOpen: false,
		cancelButton: $("#MashReady"),
		modalOpacity: 0.40
	});
	$("#MashReady").jqxButton({ template: "success", width: '90px', theme: theme });
	$("#MashReady").click(function () {
		$("#mashGrid").jqxGrid('sortby', 'step_temp', 'asc');
	});
	$("#wstep_name").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#wstep_type").jqxDropDownList({
		theme: theme,
		source: MashStepTypeAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true
	});
	$("#wstep_type").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
			rowdata.step_type = index;
			if (index == 0) {
				$("#wstep_infuse_amount").show();
				$("#wstep_pmpt").show();
			} else {
				rowdata.step_infuse_amount = 0;
				$("#wstep_infuse_amount").hide();
				$("#wstep_pmpt").hide();
			}
			mash_infuse = 0;
			var rows = $('#mashGrid').jqxGrid('getrows');
			for (var i = 0; i < rows.length; i++) {
				var row = rows[i];
				if (row.step_type == 0) // Infusion
					mash_infuse += parseFloat(row.step_infuse_amount);
			}
		}
	});
	$("#wstep_temp").jqxNumberInput( Spin1dec );
	$('#wstep_temp').on('change', function (event) {
		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
		rowdata.step_temp = parseFloat(event.args.value);
	});
	$("#wend_temp").jqxNumberInput( Spin1dec );
	$('#wend_temp').on('change', function (event) {
		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
		rowdata.end_temp = parseFloat(event.args.value);
	});
	$("#wstep_time").jqxNumberInput( PosInt );
	$('#wstep_time').on('change', function (event) {
		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
		rowdata.step_time = parseFloat(event.args.value);
	});
	$("#wramp_time").jqxNumberInput( PosInt );
	$('#wramp_time').on('change', function (event) {
		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
		rowdata.ramp_time = parseFloat(event.args.value);
	});
	$("#wstep_infuse_amount").jqxNumberInput( Spin1dec );
	$('#wstep_infuse_amount').on('change', function (event) {
		var rowdata = $("#mashGrid").jqxGrid('getrowdata', mashRow);
		rowdata.step_infuse_amount = parseFloat(event.args.value);
		mash_infuse = 0;
		var rows = $('#mashGrid').jqxGrid('getrows');
		for (var i = 0; i < rows.length; i++) {
			var row = rows[i];
			if (row.step_type == 0) // Infusion
				mash_infuse += parseFloat(row.step_infuse_amount);
		}
		if (dataRecord.w2_amount == 0) {
			dataRecord.w1_amount = mash_infuse;
			$("#w1_amount").val(mash_infuse);
		} else {
			dataRecord.w1_amount = (dataRecord.w1_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse;
			dataRecord.w2_amount = (dataRecord.w2_amount / (dataRecord.w1_amount + dataRecord.w2_amount)) * mash_infuse;
			$("#w1_amount").val(dataRecord.w1_amount);
			$("#w2_amount").val(dataRecord.w2_amount);
		}
		$('#wg_amount').val(mash_infuse);
	});

	// Tab 7, Water
	$("#tgt_bu").jqxNumberInput( Show2wat );
	$("#tgt_cl_so4").jqxNumberInput( Show1wat );

	// Water source 1
	$("#w1_name").jqxDropDownList({
		placeHolder: "Kies hoofd water:",
		theme: theme,
		source: waterlist,
		displayMember: "name",
		width: 250,
		height: 27,
		dropDownWidth: 400,
		dropDownHeight: 400
	});
	$("#w1_name").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = waterlist.records[index];
			dataRecord.w1_name = datarecord.name;
			$("#w1_calcium").val(datarecord.calcium);
			dataRecord.w1_calcium = datarecord.calcium;
			$("#w1_sulfate").val(datarecord.sulfate);
			dataRecord.w1_sulfate = datarecord.sulfate;
			$("#w1_chloride").val(datarecord.chloride);
			dataRecord.w1_chloride = datarecord.chloride;
			$("#w1_sodium").val(datarecord.sodium);
			dataRecord.w1_sodium = datarecord.sodium;
			$("#w1_magnesium").val(datarecord.magnesium);
			dataRecord.w1_magnesium = datarecord.magnesium;
			$("#w1_total_alkalinity").val(datarecord.total_alkalinity);
			dataRecord.w1_total_alkalinity = datarecord.total_alkalinity;
			$("#w1_ph").val(datarecord.ph);
			dataRecord.w1_ph = datarecord.ph;
			$("#w1_cost").val(datarecord.cost);
			dataRecord.w1_cost = datarecord.cost;
			calcWater();
		}
	});
	$("#w1_amount").jqxNumberInput( Show1wat );
	$("#w1_calcium").jqxNumberInput( Show1wat );
	$("#w1_magnesium").jqxNumberInput( Show1wat );
	$("#w1_sodium").jqxNumberInput( Show1wat );
	$("#w1_total_alkalinity").jqxNumberInput( Show1wat );
	$("#w1_chloride").jqxNumberInput( Show1wat );
	$("#w1_sulfate").jqxNumberInput( Show1wat );
	$("#w1_ph").jqxNumberInput( Show1wat );
	// Water source 2
	$("#w2_name").jqxDropDownList({
		placeHolder: "Kies meng water:",
		theme: theme,
		source: waterlist,
		displayMember: "name",
		width: 250,
		height: 27,
		dropDownWidth: 400,
		dropDownHeight: 400
	});
	$("#w2_name").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = waterlist.records[index];
			dataRecord.w2_name = datarecord.name;
			$("#w2_calcium").val(datarecord.calcium);
			dataRecord.w2_calcium = datarecord.calcium;
			$("#w2_sulfate").val(datarecord.sulfate);
			dataRecord.w2_sulfate = datarecord.sulfate;
			$("#w2_chloride").val(datarecord.chloride);
			dataRecord.w2_chloride = datarecord.chloride;
			$("#w2_sodium").val(datarecord.sodium);
			dataRecord.w2_sodium = datarecord.sodium;
			$("#w2_magnesium").val(datarecord.magnesium);
			dataRecord.w2_magnesium = datarecord.magnesium;
			$("#w2_total_alkalinity").val(datarecord.total_alkalinity);
			dataRecord.w2_total_alkalinity = datarecord.total_alkalinity;
			$("#w2_ph").val(datarecord.ph);
			dataRecord.w2_ph = datarecord.ph;
			$("#w2_cost").val(datarecord.cost);
			dataRecord.w2_cost = datarecord.cost;
			$("#w2_amount").jqxNumberInput({ max: 100000, readOnly: false }); // Set high max to enable the spinbuttons.
			calcWater();
		}
	});
	$("#w2_amount").jqxTooltip({ content: 'De verdeling van het hoofd en meng water. Het totale maisch water volume blijft gelijk.'});
	$("#w2_amount").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 94, height: 23, min: 0, max: 0, decimalDigits: 1, spinButtons: true, readOnly: true });
	$("#w2_calcium").jqxNumberInput( Show1wat );
	$("#w2_magnesium").jqxNumberInput( Show1wat );
	$("#w2_sodium").jqxNumberInput( Show1wat );
	$("#w2_total_alkalinity").jqxNumberInput( Show1wat );
	$("#w2_chloride").jqxNumberInput( Show1wat );
	$("#w2_sulfate").jqxNumberInput( Show1wat );
	$("#w2_ph").jqxNumberInput( Show1wat );
	// Water mixed
	$("#wg_amount").jqxNumberInput( Show1wat );
	$("#wg_calcium").jqxNumberInput( Show1wat );
	$("#wg_magnesium").jqxNumberInput( Show1wat );
	$("#wg_sodium").jqxNumberInput( Show1wat );
	$("#wg_total_alkalinity").jqxNumberInput( Show1wat );
	$("#wg_chloride").jqxNumberInput( Show1wat );
	$("#wg_sulfate").jqxNumberInput( Show1wat );
	$("#wg_ph").jqxNumberInput( Show1wat );
	// Water treated
	$("#wb_calcium").jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'});
	$("#wb_calcium").jqxNumberInput( Show1wat );
	$("#wb_magnesium").jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is lager dan 30.'});
	$("#wb_magnesium").jqxNumberInput( Show1wat );
	$("#wb_sodium").jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'});
	$("#wb_sodium").jqxNumberInput( Show1wat );
	$("#wb_chloride").jqxTooltip({ content: 'De ideale hoeveelheid Chloride is lager dan 100.'});
	$("#wb_chloride").jqxNumberInput( Show1wat );
	$("#wb_sulfate").jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is lager dan 350.'});
	$("#wb_sulfate").jqxNumberInput( Show1wat );
	$("#wb_total_alkalinity").jqxNumberInput( Show1wat );
	$("#wb_ph").jqxNumberInput( Show1wat );
	// Water target profile
	$("#pr_name").jqxDropDownList({
		placeHolder: "Kies doel profiel:",
		theme: theme,
		source: waterprofiles,
		displayMember: "name",
		width: 250,
		height: 27,
		dropDownWidth: 400,
		dropDownHeight: 300
	});
	$("#pr_name").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = waterprofiles.records[index];
			$("#pr_calcium").val(datarecord.calcium);
			$("#pr_sulfate").val(datarecord.sulfate);
			$("#pr_chloride").val(datarecord.chloride);
			$("#pr_sodium").val(datarecord.sodium);
			$("#pr_magnesium").val(datarecord.magnesium);
			$("#pr_total_alkalinity").val(datarecord.total_alkalinity);
		}
        });
	$("#pr_calcium").jqxNumberInput( Show1wat );
	$("#pr_magnesium").jqxNumberInput( Show1wat );
	$("#pr_sodium").jqxNumberInput( Show1wat );
	$("#pr_total_alkalinity").jqxNumberInput( Show1wat );
	$("#pr_chloride").jqxNumberInput( Show1wat );
	$("#pr_sulfate").jqxNumberInput( Show1wat );

	// Water agents
	$("#wa_cacl2").jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.'});
	$("#wa_cacl2").jqxNumberInput( Spin1dec );
	$("#wa_caso4").jqxTooltip({ content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.'});
	$("#wa_caso4").jqxNumberInput( Spin1dec );
	$("#wa_mgso4").jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!'});
	$("#wa_mgso4").jqxNumberInput( Spin1dec );
	$("#wa_nacl").jqxTooltip({ content: 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.'});
	$("#wa_nacl").jqxNumberInput( Spin1dec );
	$("#mash_ph").jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'});
	$("#mash_ph").jqxNumberInput( SpinpH );
	$("#calc_acid").jqxCheckBox({ theme: theme, width: 120, height: 23 });
	$("#wa_base_name").jqxDropDownList({
		theme: theme,
		source: BaseTypeAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 170,
		height: 23,
		autoDropDownHeight: true
	});
	$("#wa_base").jqxNumberInput( Spin2dec );
	$("#wa_base").jqxNumberInput({ symbol: ' gr', symbolPosition: 'right' });
	$("#wa_acid_name").jqxDropDownList({
		theme: theme,
		source: AcidTypeAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 170,
		height: 23,
		autoDropDownHeight: true
	});
	$("#wa_acid").jqxNumberInput( Spin2dec );
	$("#wa_acid").jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' });
	$("#wa_acid_perc").jqxNumberInput( Perc0 );
	$("#wa_acid_perc").jqxNumberInput({ width: 70, symbol: '%', symbolPosition: 'right' });
	// Sparge water
	$("#sparge_temp").jqxNumberInput( Spin1dec );
	$("#sparge_volume").jqxNumberInput( Spin1dec );
	$("#sparge_ph").jqxNumberInput( SpinpH );
	$("#sparge_source").jqxDropDownList({
		theme: theme,
		source: SpargeSourceAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 110,
		height: 23,
		autoDropDownHeight: true
	});
	$("#sparge_acid_amount").jqxNumberInput( Spin2dec );
	$("#sparge_acid_amount").jqxNumberInput({ spinButtons: false, readOnly: true, symbol: ' ml', symbolPosition: 'right' });
	$("#sparge_acid_type").jqxDropDownList({
		theme: theme,
		source: AcidTypeAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 110,
		height: 23,
		autoDropDownHeight: true
	});
	$("#sparge_acid_perc").jqxNumberInput( Perc0 );
	$("#sparge_acid_perc").jqxNumberInput({ symbol: '%', symbolPosition: 'right' });

	// Tabs inside the popup window.
	$('#jqxTabs').jqxTabs({
		theme: theme,
		width: 1280,
		height: 660,
		autoHeight: false,
		position: 'top'
	});

	$("#Print").jqxButton({ template: "info", width: '80px', theme: theme });
	$("#Print").click(function () {
		saveRecord();
		// Open print in a new tab.
		var url="rec_print.php?record=" + my_record;
		window.open(url);
	});

	$("#Export").jqxButton({ template: "info", width: '80px', theme: theme });
	$("#Export").click(function () {
		saveRecord();
		var url="rec_export.php?record=" + my_record + "&return=" + my_return + "&name=" + dataRecord.name;
		window.location.href = url;
	});

	$("#Delete").jqxButton({ template: "danger", width: '80px', theme: theme });
	$("#Delete").click(function () {
		// Open a popup to confirm this action.
		$('#eventWindow').jqxWindow('open');
		$("#delOk").click(function () {
			var data = "delete=true&" + $.param({ record: my_record });
			$.ajax({
				dataType: 'json',
				url: url,
				cache: false,
				data: data,
				type: "POST",
				success: function (data, status, xhr) {
					// delete command is executed.
					window.location.href = my_return;
				},
				error: function (jqXHR, textStatus, errorThrown) {
				}
			});
		});
	});

	$("#Cancel").jqxButton({ template: "primary", width: '80px', theme: theme });
	$("#Cancel").click(function () {
		window.location.href = my_return;
	});

	$("#Save").jqxButton({ template: "success", width: '80px', theme: theme });
	$("#Save").click(function () {
		saveRecord();
		window.location.href = my_return;
	});
	createDelElements();
});

mercurial