www/js/prod_edit.js

Sun, 10 Feb 2019 22:08:01 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 10 Feb 2019 22:08:01 +0100
changeset 262
36cf32fcd210
parent 260
042fc9b3717b
child 263
ed22ac46404b
permissions
-rw-r--r--

Swapped icons

/*****************************************************************************
 * 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	aboil_sg = 0;
	var	est_mash_sg = 0;
	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 = {};

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

	/*
	 * All calculations that depend on changes in the fermentables,
	 * volumes and equipments.
	 */
	function calcFermentables() {

		console.log("calcFermentables()");
		var sugarsf = 0;	// fermentable sugars mash + boil
		var 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 });
		}

		if (mvol > 0) {
			var v = s / sugardensity + mvol;
			s = 1000 * s / (v * 10); //deg. Plato
			est_mash_sg = Math.round(plato_to_sg(s) * 10000) / 10000;
			$('#est_mash_sg').val(est_mash_sg);
		}

		// 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 after boil
		aboil_sg = estimate_sg(sugarsf, parseFloat(dataRecord.batch_size));
		$('#est_og3').val(aboil_sg);

		// Estimate SG in kettle before boil
		preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size));
		$('#est_pre_sg').val(preboil_sg);

		// Recalculate volumes.
		var aboil_volume = parseFloat(dataRecord.batch_size);
		if (dataRecord.brew_aboil_volume > 0)
			aboil_volume = dataRecord.brew_aboil_volume / 1.04;	// volume @ 20 degrees
		dataRecord.brew_fermenter_volume = aboil_volume - dataRecord.brew_fermenter_tcloss + dataRecord.brew_fermenter_extrawater;
		$("#brew_fermenter_volume").val(dataRecord.brew_fermenter_volume);
		// Estimated needed sparge water corrected for the temperature.
		var spoelw = (dataRecord.boil_size - mash_infuse + (mashkg * my_grain_absorbtion) + dataRecord.eq_lauter_deadspace) * 1.03;
		$("#brew_sparge_est").val(spoelw);

		// Calculate SG in fermenter
		var ogx = dataRecord.brew_aboil_sg;
		if (ogx < 1.002)
			ogx = aboil_sg;
		var top = dataRecord.brew_fermenter_extrawater;

		if (dataRecord.brew_fermenter_volume > 0) {
			var sug = sg_to_plato(ogx) * dataRecord.brew_fermenter_volume * ogx / 100;  //kg of sugar in
			sug += addedS; //kg
			//console.log("Contents ferm_vol:"+dataRecord.brew_fermenter_volume+" top:"+top+" vol:"+vol+" addedS:"+addedS+" addedmass:"+addedmass);

			if ((dataRecord.brew_fermenter_volume * ogx + addedmass) > 0) {
				var pt = 100 * sug / (dataRecord.brew_fermenter_volume * ogx + addedmass + top);
				dataRecord.brew_fermenter_sg = Math.round(plato_to_sg(pt) * 10000) / 10000;
				$("#brew_fermenter_sg").val(dataRecord.brew_fermenter_sg);
				// color
				var cw = colort / (aboil_volume + top) * 8.34436;
				dataRecord.brew_fermenter_color = kw_to_ebc(dataRecord.color_method, cw);
				$("#brew_fermenter_color").val(dataRecord.brew_fermenter_color);
				var scolor = ebc_to_color(dataRecord.brew_fermenter_color);
				$("#bcolorf").show();
				document.getElementById("bcolorf").style.background= scolor;
				//console.log("OG in fermenter:"+dataRecord.brew_fermenter_sg+" color:"+dataRecord.brew_fermenter_color);
			}
		} else {
			// Negative volume
			dataRecord.brew_fermenter_sg = dataRecord.brew_fermenter_color = 0;
			$("#brew_fermenter_sg").val(0);
			$("#brew_fermenter_color").val(0);
			$("#bcolorf").hide();
		}

		// 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.eq_mash_max * 100;
		//console.log("mash kg: "+mashkg+" max: "+dataRecord.eq_mash_max+" perc: "+pmalts);
                $("#perc_malts").jqxProgressBar('val', pmalts);
                $("#perc_sugars").jqxProgressBar('val', psugar);
                $("#perc_cara").jqxProgressBar('val', pcara);
		calcStage();

		// 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);
		$('#est_fg3').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);

		// Calculate the final svg if available use the real value.
		if ((dataRecord.stage >= 6) && (dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) {
			svg = 100 * (dataRecord.brew_fermenter_sg - dataRecord.fg) / (dataRecord.brew_fermenter_sg - 1);
			//console.log("real svg:"+svg);
		}

	};

	/*
	 * 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 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
		}
		return (result * amount * 1000) / vol;
	}

	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
			result = 1.2;
		} else if (use == 4) {	// Whirlpool
			result = 1.2;
		} else if (use == 5) {	// Dry hop
			result = 1.33;
		}
		return (result * amount * 1000) / vol;
	}

	function calcIBUs() {
		var total_ibus = 0;
		var ferm_ibus = 0;
		var rows = {};
		hop_aroma = hop_flavour = 0;
		if (!(rows = $('#hopGrid').jqxGrid('getrows'))) {
			return;
		}
		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);
			ferm_ibus += toIBU(row.h_useat, row.h_form, preboil_sg,
					parseFloat(dataRecord.brew_fermenter_volume) + parseFloat(dataRecord.brew_fermenter_tcloss),
					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 * 10) / 10;
		ferm_ibus = Math.round(ferm_ibus * 10) / 10;
		hop_flavour = Math.round(hop_flavour * 100) / 10;
		hop_aroma = Math.round(hop_aroma * 100) / 10;
		if (hop_flavour > 100)
			hop_flavour = 100;
		if (hop_aroma > 100)
			hop_aroma = 100;
		console.log("calcIBUs(): " + total_ibus + "  flavour: " + hop_flavour + "  aroma: " + hop_aroma+"  fermenter:"+ferm_ibus);
		dataRecord.est_ibu = total_ibus;
		$('#est_ibu').val(total_ibus);
		$('#est_ibu2').val(total_ibus);
		$("#hop_flavour").jqxProgressBar('val', hop_flavour);
		$("#hop_aroma").jqxProgressBar('val', hop_aroma);
		$("#brew_fermenter_ibu").val(ferm_ibus);
		calcStage();
	};

	function calcMashEfficiency() {
//		console.log("calcMashEfficiency()");
		var c = sg_to_plato(est_mash_sg);
		var m = sg_to_plato(parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')));
//		console.log("c "+ c + "  m " + m + "  in " + parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')));
		if (c > 0.5)
			$("#brew_mash_efficiency").val(100 * m / c);
		else
			$("#brew_mash_efficiency").val(0);
	};

	function calcEfficiencyBeforeBoil() {
		var	m = 0;
		var	rows = {};
		if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
			return;	// grid not yet loaded.
		}
		for (var i = 0; i < rows.length; i++) {
			var row = rows[i];
			if (row.f_added == 0) { // Mash
				m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
			}
		}
		var tot = sg_to_plato(dataRecord.brew_preboil_sg) * (dataRecord.brew_preboil_volume / 1.04) * dataRecord.brew_preboil_sg * 10 / 1000;
		if (m > 0)
			var result = Math.round((tot / m * 100) * 10) / 10;
		else
			var result = 0;
		if (result < 0)
			result = 0;
		//console.log("calcEfficiencyBeforeBoil(): "+result);
		$("#brew_preboil_efficiency").val(result);
	}

	function calcEfficiencyAfterBoil() {
		var	m = 0;	// Sugars added at mash
		var	b = 0;	// Sugars added at boil
		var	rows = {};
		if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
			return; // grid not yet loaded.
		}
		for (var i = 0; i < rows.length; i++) {
			var row = rows[i];
			if (row.f_added == 0) { // Mash
				m += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
			} else if (row.f_added == 1) { // Boil
				b += row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
			}
		}
		var tot = sg_to_plato(dataRecord.brew_aboil_sg) * (dataRecord.brew_aboil_volume / 1.04) * dataRecord.brew_aboil_sg * 10 / 1000;
		tot -= b;	// total sugars in wort  minus added sugars.
		if (m > 0)
			var result = Math.round((tot / m * 100) * 10) / 10;
		else
			var result = 0;
		if (result < 0)
			result = 0;
		//console.log("calcEfficiencyAfterBoil(): "+result);
		dataRecord.brew_aboil_efficiency = result;
		$("#brew_aboil_efficiency").val(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)
				Result += x * row.f_amount;
			}
		}
		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
				};
		}
	}


	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 frac = 0;
		var TpH = 0;
		var protonDeficit = 0;

		if (dataRecord.w1_name == "") {
			return;
		}

		// 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);
		$('#est_mash_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 +
		     parseFloat($("#wa_base").jqxNumberInput('decimal')) * MMNa / MMNaHCO3;
		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;
		var BT = dataRecord.wa_base_name;

		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);
			$('#est_mash_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;
				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);
				$('#est_mash_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
		var 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);
	}

	function calcFermentation() {
		if (dataRecord.brew_fermenter_sg < 1.020)
			return;
		if ((dataRecord.primary_end_sg > 0.990) && (dataRecord.primary_end_sg < dataRecord.brew_fermenter_sg)) {
			var primary_svg = 100 * (dataRecord.brew_fermenter_sg - dataRecord.primary_end_sg) / (dataRecord.brew_fermenter_sg - 1);
			console.log("primary svg: "+primary_svg);
			$("#primary_svg").val(primary_svg);
			if ((dataRecord.fg > 0.990) && (dataRecord.fg < dataRecord.brew_fermenter_sg)) {
				var final_svg = 100 * (dataRecord.brew_fermenter_sg - dataRecord.fg) / (dataRecord.brew_fermenter_sg - 1);
				$("#final_svg").val(final_svg);
				var ABV = abvol(dataRecord.brew_fermenter_sg, dataRecord.fg);
				$("#final_abv").val(ABV);
			}
		}
	}

	function CarbCO2toS(CO2, T, SFactor) {
		// Calcuation of disolved CO2 in the beer.
		// Brewersfriend uses: 3.0378 - (0.050062 * temp) + (0.00026555 * temp^2)
		// Brouwhulp uses:     0.000849151 * T * T - 0.0587512 * T + 1.71137)
		var sugar = SFactor * (CO2 - (0.000849151 * T * T - 0.0587512 * T + 1.71137)) / 0.286;
		if (sugar < 0)
			sugar = 0;
		return sugar;
	}

	function CarbCO2ToPressure(CO2, T) {
		return (CO2 - (-0.000005594056 * Math.pow(T, 4) + 0.000144357886 * Math.pow(T, 3) +
				0.000362999168 * T * T - 0.064872987645 * T + 1.641145175049)) /
			        (0.00000498031 * Math.pow(T, 4) - 0.00024358267 * Math.pow(T, 3) +
				0.00385867329 * T * T - 0.05671206825 * T + 1.53801423376);
	}

	function calcCarbonation() {

		var TSec = dataRecord.secondary_temp;	// End fermentation temperature.
		if (TSec < 1)
			TSec = dataRecord.primary_end_temp;	// Fallback
		if (TSec < 1)
			TSec = 18;	// Fallback to room temperature.

		if (dataRecord.fg == 1.000)
			var ABV = abvol(dataRecord.brew_fermenter_sg, parseFloat($("#est_fg").jqxNumberInput('decimal')));
		else
			var ABV = abvol(dataRecord.brew_fermenter_sg, dataRecord.fg);

		// Bottles
		var SFactor = PrimingSugarData[dataRecord.bottle_priming_sugar].factor;
		var Amount = CarbCO2toS(dataRecord.bottle_carbonation, TSec, SFactor);
		dataRecord.bottle_priming_amount = Amount;
		$("#bottle_priming_amount").val(Math.round(dataRecord.bottle_priming_amount * 10) / 10);
		$("#bottle_priming_total").val(Math.round(dataRecord.bottle_amount * dataRecord.bottle_priming_amount * 10) / 10);
		$("#bottle_abv").val(Math.round((ABV + Amount * 0.47 / 7.907) * 10) / 10);

		// Kegs
		SFactor = PrimingSugarData[dataRecord.keg_priming_sugar].factor;
		Amount = CarbCO2toS(dataRecord.keg_carbonation, TSec, SFactor);
		var Pressure = CarbCO2ToPressure(dataRecord.keg_carbonation, dataRecord.keg_carbonation_temp);
		if (Pressure < 0)
			Pressure = 0;
		dataRecord.keg_pressure = Pressure;
		$("#keg_pressure").val(Math.round(Pressure * 10) / 10);

		if (dataRecord.keg_forced_carb) {
			Amount = 0;
			dataRecord.keg_priming_amount = 0;
			$("#keg_priming_amount").val(0);
			$("#keg_priming_total").val(0);
		} else {
			dataRecord.keg_priming_amount = Amount;
			$("#keg_priming_amount").val(Math.round(dataRecord.keg_priming_amount * 10) / 10);
			$("#keg_priming_total").val(Math.round(dataRecord.keg_amount * dataRecord.keg_priming_amount * 10) / 10);
		}

		$("#keg_abv").val(Math.round((ABV + Amount * 0.47 / 7.907) * 10) / 10);
	}

	function calcStage() {

		var	newstage = dataRecord.stage;
		/* parseFloat$("#brew_date_start").val()) returns the year if it is a valid mysql style date. */
		if (newstage == 0 && dataRecord.est_og > 1.005 && dataRecord.est_color > 3 && dataRecord.est_ibu > 3)
			newstage = 1;
		if (newstage == 1 && parseFloat($("#brew_date_start").val()) > 2000)
			newstage = 2;	// Brewday
		if (newstage == 2 && parseFloat($("#brew_date_end").val()) > 2000)
			newstage = 3;	// Primary
		if (newstage == 3 && parseFloat($("#primary_end_date").val()) > 2000)
			newstage = 4;	// Secondary
		if (newstage == 4 && parseFloat($("#secondary_end_date").val()) > 2000)
			newstage = 5;	// Tertiary
		if (newstage == 5 && parseFloat($("#package_date").val()) > 2000)
			newstage = 6;	// Package
		if (newstage >= 6 && newstage < 9) {
			var d = new Date();
			var date2 = $("#package_date").val();
			date2 = date2.split('-');
			// Now we convert the array to a Date object
			date1 = new Date(d.getFullYear(), d.getMonth(), d.getDate());
			date2 = new Date(date2[0], date2[1]-1, date2[2]);
			// We use the getTime() method and get the unixtime
			date1_unixtime = parseInt(date1.getTime() / 1000);
			date2_unixtime = parseInt(date2.getTime() / 1000);
			// This is the calculated difference in seconds
			var timeDifference = date1_unixtime - date2_unixtime;
			var timeDifferenceInDays = timeDifference / 60 / 60 / 24;
			//console.log(date1+'  '+date2+' days: '+timeDifferenceInDays);
			if (timeDifferenceInDays > 0) {			// At least one day
				if (timeDifferenceInDays >= 42)		// 6 weeks
					newstage = 9;			// Ready to taste
				else if (timeDifferenceInDays >= 14)	// 14 days
					newstage = 8;			// Mature
				else
					newstage = 7;			// Carbonation
			}
		}
		if (newstage == 9 && parseFloat($("#taste_date").val()) > 2000)
			newstage = 10;	// Ready

		if (newstage > dataRecord.stage) {
			console.log("calcStage() old: "+dataRecord.stage+" new: "+newstage);
			dataRecord.stage = newstage;
		}

		/*
		 * Set stage and enable or disable parts of the screens.
		 */
		$("#stage").val(StageData[dataRecord.stage].nl);
		if (dataRecord.stage >= 10) {
			$("#locked").jqxCheckBox({ disabled:false });
		}

		/*
		 * When the brew is in progress or done, block equipment select.
		 */
		if (dataRecord.stage > 1)
			$("#equipmentSelect").jqxDropDownList({ disabled: true });
		if (dataRecord.stage > 0) {
			$("#Delete").jqxButton({ disabled: true });
		}

		if (dataRecord.stage < 1) 	// Planning, no ingredients
			$('#jqxTabs').jqxTabs('disableAt', 8);	// Brewday tab
		else
			$('#jqxTabs').jqxTabs('enableAt', 8);

		if (dataRecord.stage < 3) {	// Primary
			$('#jqxTabs').jqxTabs('disableAt', 9);	// Fermentation tab
		} else {
			$('#jqxTabs').jqxTabs('enableAt', 9);
		}
		if (dataRecord.stage < 5) { // At least secondary
			$('#jqxTabs').jqxTabs('disableAt', 10);	// Packaging tab
		} else {
			$('#jqxTabs').jqxTabs('enableAt', 10);
		}
		if (dataRecord.stage < 6) {	// Not yet packaged
			$("#inventory_reduced").jqxCheckBox({ disabled : true });
		} else {
			if ($('#inventory_reduced').jqxCheckBox('checked'))
				$("#inventory_reduced").jqxCheckBox({ disabled : true });
		}
		if (dataRecord.stage < 8) { // Taste when at least Mature.
			$('#jqxTabs').jqxTabs('disableAt', 11);	// Tasting tab
		} else {
			$('#jqxTabs').jqxTabs('enableAt', 11);
		}
	}

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

		calcMashEfficiency();
		calcEfficiencyBeforeBoil();
		calcEfficiencyAfterBoil();

		$("#calc_acid").on('checked', function (event) {
			dataRecord.calc_acid = 1;
			calcWater();
		});
		$("#calc_acid").on('unchecked', function (event) {
			dataRecord.calc_acid = 0;
			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);
			$("#est_a_vol").val(event.args.value * 1.04);
			var new_boil = parseFloat(event.args.value) + dataRecord.boil_size - dataRecord.batch_size;
			dataRecord.boil_size = new_boil;
			$("#boil_size").val(Math.round(new_boil * 100) / 100);
			$("#est_pre_vol").val(Math.round(new_boil * 1.04 * 100) / 100);
			dataRecord.batch_size = parseFloat(event.args.value);
			calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal')));     // Keep the OG
			calcFermentables();
			// TODO: adjust the hops, miscs, yeast, water.
			calcIBUs();
		});
		$('#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;
			dataRecord.boil_time = parseFloat(event.args.value);
			dataRecord.boil_size = new_boil;
			$("#est_pre_vol").val(Math.round(new_boil * 1.04 * 100) / 100);
			$("#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);
			$('#est_og2').val(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();
		});

		calcFermentation();
		calcCarbonation();
		$('#bottle_amount').on('change', function (event) {
			dataRecord.bottle_amount = parseFloat(event.args.value);
			calcCarbonation();
		});
		$('#keg_amount').on('change', function (event) {
			dataRecord.keg_amount = parseFloat(event.args.value);
			calcCarbonation();
		});
		$('#bottle_carbonation').on('change', function (event) {
			dataRecord.bottle_carbonation = parseFloat(event.args.value);
			calcCarbonation();
		});
		$('#keg_carbonation').on('change', function (event) {
			dataRecord.keg_carbonation = parseFloat(event.args.value);
			calcCarbonation();
		});
		$('#bottle_priming_sugar').on('change', function (event) {
			dataRecord.bottle_priming_sugar = event.args.item.value;
			calcCarbonation();
		});
		$('#keg_priming_sugar').on('change', function (event) {
			dataRecord.keg_priming_sugar = event.args.item.value;
			calcCarbonation();
		});
		$("#keg_forced_carb").on('checked', function (event) {
			dataRecord.keg_forced_carb = 1;
			calcCarbonation();
		});
		$("#keg_forced_carb").on('unchecked', function (event) {
			dataRecord.keg_forced_carb = 0;
			calcCarbonation();
		});
		$('#keg_carbonation_temp').on('change', function (event) {
			dataRecord.keg_carbonation_temp = parseFloat(event.args.value);
			calcCarbonation();
		});

		$("#brew_fermenter_extrawater").on('change', function (event) {
			dataRecord.brew_fermenter_extrawater = parseFloat(event.args.value);
			calcFermentables();
			calcIBUs();
		});
		$("#brew_fermenter_tcloss").on('change', function (event) {
			dataRecord.brew_fermenter_tcloss = parseFloat(event.args.value);
			calcFermentables();
			calcIBUs();
		});

		$("#BLog").jqxButton({ disabled: (dataRecord.log_brew) ? false:true });
		$("#FLog").jqxButton({ disabled: (dataRecord.log_fermentation) ? false:true });
	};

	$("#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_min2").val(datarecord.carb_min);
			$("#st_carb_max").val(datarecord.carb_max);
			$("#st_carb_max2").val(datarecord.carb_max);
			$("#st_abv_min").val(datarecord.abv_min);
			$("#st_abv_max").val(datarecord.abv_max);
		}
	});

	// Equipemnt dropdown list
	$("#equipmentSelect").jqxDropDownList({
		placeHolder: "Kies apparatuur:",
		theme: theme,
		source: equipmentlist,
		displayMember: "name",
		width: 170,
		height: 23,
		dropDownWidth: 300,
		renderer: function (index, label, value) {
			var datarecord = equipmentlist.records[index];
			return datarecord.batch_size + " liter " + datarecord.name;
		}
	});
	$("#equipmentSelect").on('select', function (event) {
		if (event.args) {
			var index = event.args.index;
			var datarecord = equipmentlist.records[index];
			$("#eq_name").val(datarecord.name);
			$("#eq_boil_size").val(datarecord.boil_size);
			dataRecord.boil_size = datarecord.boil_size;
			$("#boil_size").val(datarecord.boil_size);
			$("#eq_batch_size").val(datarecord.batch_size);
			dataRecord.batch_size = datarecord.batch_size;
			$("#batch_size").val(datarecord.batch_size);
			$("#est_a_vol").val(datarecord.batch_size * 1.04);
			$("#eq_tun_volume").val(datarecord.tun_volume);
			dataRecord.eq_tun_weight = datarecord.tun_weight;
			dataRecord.eq_tun_specific_heat = datarecord.tun_specific_heat;
			dataRecord.eq_tun_material = datarecord.tun_material;
			dataRecord.eq_tun_height = datarecord.tun_height / 100.0;
			$("#eq_top_up_water").val(datarecord.top_up_water);
			$("#eq_trub_chiller_loss").val(datarecord.trub_chiller_loss);
			$("#eq_evap_rate").val(datarecord.evap_rate);
			$("#eq_boil_time").val(datarecord.boil_time);
			dataRecord.eq_calc_boil_volume = datarecord.calc_boil_volume;
			$("#eq_top_up_kettle").val(datarecord.top_up_kettle);
			$("#eq_hop_utilization").val(datarecord.hop_utilization);
			$("#eq_notes").val(datarecord.notes);
			$("#eq_lauter_volume").val(datarecord.lauter_volume);
			dataRecord.eq_lauter_height = datarecord.lauter_height / 100.0;
			$("#eq_lauter_deadspace").val(datarecord.lauter_deadspace);
			$("#eq_kettle_volume").val(datarecord.kettle_volume);
			dataRecord.eq_kettle_height = datarecord.kettle_height / 100.0;
			$("#eq_mash_volume").val(datarecord.mash_volume);
			$("#eq_mash_max").val(datarecord.mash_max);
			dataRecord.eq_mash_max = datarecord.mash_max;
			$("#mash_max").val(datarecord.mash_max);
			$("#eq_efficiency").val(datarecord.efficiency);
			dataRecord.efficiency = datarecord.efficiency;
			$("#efficiency").val(datarecord.efficiency);

			calcFermentablesFromOG(parseFloat($("#est_og").jqxNumberInput('decimal')));     // Keep the OG
			calcFermentables();
			// TODO: adjust the hops, miscs, yeast, water.
			calcIBUs();
		}
	});

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

	// Prepare the data
	var source = {
		datatype: "json",
		cache: false,
		datafields: [
			// From prod_main
			{ name: 'record', type: 'number' },
			{ name: 'uuid', type: 'string' },
			{ name: 'name', type: 'string' },
			{ name: 'code', type: 'string' },
			{ name: 'birth', type: 'string' },
			{ name: 'stage', type: 'int' },
			{ name: 'notes', type: 'string' },
			{ name: 'log_brew', type: 'int' },
			{ name: 'log_fermentation', type: 'int' },
			{ name: 'inventory_reduced', type: 'int' },
			{ name: 'locked', type: 'int' },
			{ name: 'eq_name', type: 'string' },
			{ name: 'eq_boil_size', type: 'float' },
			{ name: 'eq_batch_size', type: 'float' },
			{ name: 'eq_tun_volume', type: 'float' },
			{ name: 'eq_tun_weight', type: 'float' },
			{ name: 'eq_tun_specific_heat', type: 'float' },
			{ name: 'eq_tun_material', type: 'int' },
			{ name: 'eq_tun_height', type: 'float' },
			{ name: 'eq_top_up_water', type: 'float' },
			{ name: 'eq_trub_chiller_loss', type: 'float' },
			{ name: 'eq_evap_rate', type: 'float' },
			{ name: 'eq_boil_time', type: 'float' },
			{ name: 'eq_calc_boil_volume', type: 'int' },
			{ name: 'eq_top_up_kettle', type: 'float' },
			{ name: 'eq_hop_utilization', type: 'float' },
			{ name: 'eq_notes', type: 'string' },
			{ name: 'eq_lauter_volume', type: 'float' },
			{ name: 'eq_lauter_height', type: 'float' },
			{ name: 'eq_lauter_deadspace', type: 'float' },
			{ name: 'eq_kettle_volume', type: 'float' },
		        { name: 'eq_kettle_height', type: 'float' },
			{ name: 'eq_mash_volume', type: 'float' },
			{ name: 'eq_mash_max', type: 'float' },
			{ name: 'eq_efficiency', type: 'float' },
			{ name: 'brew_date_start', type: 'string' },
			{ name: 'brew_mash_ph', type: 'float' },
			{ name: 'brew_mash_sg', type: 'float' },
			{ name: 'brew_sparge_temperature', type: 'float' },
			{ name: 'brew_sparge_volume', type: 'float' },
			{ name: 'brew_sparge_ph', type: 'float' },
			{ name: 'brew_preboil_volume', type: 'float' },
			{ name: 'brew_preboil_sg', type: 'float' },
			{ name: 'brew_preboil_ph', type: 'float' },
			{ name: 'brew_aboil_volume', type: 'float' },
			{ name: 'brew_aboil_sg', type: 'float' },
			{ name: 'brew_aboil_ph', type: 'float' },
			{ name: 'brew_aboil_efficiency', type: 'float' },
			{ name: 'brew_cooling_method', type: 'int' },
			{ name: 'brew_cooling_time', type: 'float' },
			{ name: 'brew_cooling_to', type: 'float' },
			{ name: 'brew_whirlpool9', type: 'float' },
			{ name: 'brew_whirlpool7', type: 'float' },
			{ name: 'brew_whirlpool6', type: 'float' },
			{ name: 'brew_whirlpool2', type: 'float' },
			{ name: 'brew_fermenter_volume', type: 'float' },
			{ name: 'brew_fermenter_extrawater', type: 'float' },
			{ name: 'brew_fermenter_tcloss', type: 'float' },
			{ name: 'brew_aeration_time', type: 'float' },
			{ name: 'brew_aeration_speed', type: 'float' },
			{ name: 'brew_aeration_type', type: 'int' },
			{ name: 'brew_fermenter_sg', type: 'float' },
			{ name: 'brew_fermenter_ibu', type: 'float' },
			{ name: 'brew_fermenter_color', type: 'float' },
			{ name: 'brew_date_end', type: 'string' },
			{ name: 'og', type: 'float' },
			{ name: 'fg', type: 'float' },
			{ name: 'primary_start_temp', type: 'float' },
			{ name: 'primary_max_temp', type: 'float' },
			{ name: 'primary_end_temp', type: 'float' },
			{ name: 'primary_end_sg', type: 'float' },
			{ name: 'primary_end_date', type: 'string' },
			{ name: 'secondary_temp', type: 'float' },
			{ name: 'secondary_end_date', type: 'string' },
			{ name: 'tertiary_temp', type: 'float' },
			{ name: 'package_date', type: 'string' },
			{ name: 'bottle_amount', type: 'float' },
			{ name: 'bottle_carbonation', type: 'float' },
			{ name: 'bottle_priming_sugar', type: 'int' },
			{ name: 'bottle_priming_amount', type: 'float' },
			{ name: 'bottle_carbonation_temp', type: 'float' },
			{ name: 'keg_amount', type: 'float' },
			{ name: 'keg_carbonation', type: 'float' },
			{ name: 'keg_priming_sugar', type: 'int' },
			{ name: 'keg_priming_amount', type: 'float' },
			{ name: 'keg_carbonation_temp', type: 'float' },
			{ name: 'keg_forced_carb', type: 'int' },
			{ name: 'keg_pressure', type: 'float' },
			{ name: 'taste_notes', type: 'string' },
			{ name: 'taste_rate', type: 'float' },
			{ name: 'taste_date', type: 'string' },
			{ name: 'taste_color', type: 'string' },
			{ name: 'taste_transparency', type: 'string' },
			{ name: 'taste_head', type: 'string' },
			{ name: 'taste_aroma', type: 'string' },
			{ name: 'taste_taste', type: 'string' },
			{ name: 'taste_mouthfeel', type: 'string' },
			{ name: 'taste_aftertaste', type: 'string' },
			{ name: 'st_name', type: 'string' },
			{ name: 'st_letter', type: 'string' },
			{ name: 'st_guide', type: 'string' },
			{ name: 'st_category', type: 'string' },
			{ name: 'st_category_number', type: 'float' },
			{ name: 'st_type', type: 'int' },
			{ 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: '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: 'int' },
			{ 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);
			$("#code").val(dataRecord.code);
			$("#birth").val(dataRecord.birth);
			$("#stage").val(StageData[dataRecord.stage].nl);
			$("#notes").val(dataRecord.notes);
			$("#inventory_reduced").val(dataRecord.inventory_reduced);
			$("#locked").val(dataRecord.locked);
			$("#eq_name").val(dataRecord.eq_name);
			$("#eq_notes").val(dataRecord.eq_notes);
			$("#eq_boil_size").val(dataRecord.eq_boil_size);
			$("#eq_batch_size").val(dataRecord.eq_batch_size);
			$("#eq_tun_volume").val(dataRecord.eq_tun_volume);
			$("#eq_top_up_water").val(dataRecord.eq_top_up_water);
			$("#eq_trub_chiller_loss").val(dataRecord.eq_trub_chiller_loss);
			$("#eq_evap_rate").val(dataRecord.eq_evap_rate);
			$("#eq_boil_time").val(dataRecord.eq_boil_time);
			$("#eq_top_up_kettle").val(dataRecord.eq_top_up_kettle);
			$("#eq_hop_utilization").val(dataRecord.eq_hop_utilization);
			$("#eq_lauter_volume").val(dataRecord.eq_lauter_volume);
			$("#eq_lauter_deadspace").val(dataRecord.eq_lauter_deadspace);
			$("#eq_kettle_volume").val(dataRecord.eq_kettle_volume);
			$("#eq_mash_volume").val(dataRecord.eq_mash_volume);
			$("#eq_mash_max").val(dataRecord.eq_mash_max);
			$("#eq_efficiency").val(dataRecord.eq_efficiency);
			// Brewdate
			$("#brew_date_start").val(dataRecord.brew_date_start);
			$("#brew_mash_ph").val(dataRecord.brew_mash_ph);
			$("#brew_mash_sg").val(dataRecord.brew_mash_sg);
			// brew_mash_efficiency to calculate on th fly.
			// Header Spoelen en filteren
			$("#brew_sparge_temperature").val(dataRecord.brew_sparge_temperature);
			$("#brew_sparge_volume").val(dataRecord.brew_sparge_volume);
			$("#brew_sparge_ph").val(dataRecord.brew_sparge_ph);
			// Header Beluchten
			$("#brew_aeration_type").val(dataRecord.brew_aeration_type);
			$("#brew_aeration_time").val(dataRecord.brew_aeration_time);
			$("#brew_aeration_speed").val(dataRecord.brew_aeration_speed);

			$("#brew_preboil_ph").val(dataRecord.brew_preboil_ph);
			$("#brew_preboil_sg").val(dataRecord.brew_preboil_sg);
			$("#brew_preboil_volume").val(dataRecord.brew_preboil_volume);
			//$("#brew_preboil_efficiency").val(dataRecord.brew_preboil_efficiency);
			// Header Koelen en whirlpoolen
			$("#brew_whirlpool9").val(dataRecord.brew_whirlpool9);
			$("#brew_whirlpool7").val(dataRecord.brew_whirlpool7);
			$("#brew_whirlpool6").val(dataRecord.brew_whirlpool6);
			$("#brew_whirlpool2").val(dataRecord.brew_whirlpool2);
			// Header Naar gistvat
			$("#brew_fermenter_volume").val(dataRecord.brew_fermenter_volume);
			$("#brew_fermenter_sg").val(dataRecord.brew_fermenter_sg);
			$("#brew_fermenter_sg2").val(dataRecord.brew_fermenter_sg);
			$("#brew_fermenter_ibu").val(dataRecord.brew_fermenter_ibu);
			$("#brew_fermenter_color").val(dataRecord.brew_fermenter_color);
			$("#brew_fermenter_extrawater").val(dataRecord.brew_fermenter_extrawater);
			$("#brew_fermenter_tcloss").val(dataRecord.brew_fermenter_tcloss);

			$("#brew_aboil_ph").val(dataRecord.brew_aboil_ph);
			$("#brew_aboil_sg").val(dataRecord.brew_aboil_sg);
			$("#brew_aboil_volume").val(dataRecord.brew_aboil_volume);
			$("#brew_aboil_efficiency").val(dataRecord.brew_aboil_efficiency);
			// Header Koelen en whirlpoolen
			$("#brew_cooling_to").val(dataRecord.brew_cooling_to);
			$("#brew_cooling_method").val(dataRecord.brew_cooling_method);
			$("#brew_cooling_time").val(dataRecord.brew_cooling_time);
			// Niks
			$("#brew_date_end").val(dataRecord.brew_date_end);
			$("#og").val(dataRecord.og);
			$("#fg").val(dataRecord.fg);
			$("#primary_start_temp").val(dataRecord.primary_start_temp);
			$("#primary_max_temp").val(dataRecord.primary_max_temp);
			$("#primary_end_temp").val(dataRecord.primary_end_temp);
			$("#primary_end_sg").val(dataRecord.primary_end_sg);
			$("#primary_end_date").val(dataRecord.primary_end_date);
			$("#secondary_temp").val(dataRecord.secondary_temp);
			$("#secondary_end_date").val(dataRecord.secondary_end_date);
			$("#tertiary_temp").val(dataRecord.tertiary_temp);
			$("#package_date").val(dataRecord.package_date);
			$("#bottle_amount").val(dataRecord.bottle_amount);
			$("#bottle_carbonation").val(dataRecord.bottle_carbonation);
			$("#bottle_priming_sugar").val(dataRecord.bottle_priming_sugar);
			$("#bottle_priming_amount").val(dataRecord.bottle_priming_amount);
			$("#bottle_carbonation_temp").val(dataRecord.bottle_carbonation_temp);
			$("#keg_amount").val(dataRecord.keg_amount);
			$("#keg_carbonation").val(dataRecord.keg_carbonation);
			$("#keg_priming_sugar").val(dataRecord.keg_priming_sugar);
			$("#keg_priming_amount").val(dataRecord.keg_priming_amount);
			$("#keg_carbonation_temp").val(dataRecord.keg_carbonation_temp);
			$("#keg_forced_carb").val(dataRecord.keg_forced_carb);
			$("#keg_pressure").val(dataRecord.keg_pressure);
			$("#taste_notes").val(dataRecord.taste_notes);
			$("#taste_rate").val(dataRecord.taste_rate);
			$("#taste_date").val(dataRecord.taste_date);
			$("#taste_color").val(dataRecord.taste_color);
			$("#taste_transparency").val(dataRecord.taste_transparency);
			$("#taste_head").val(dataRecord.taste_head);
			$("#taste_aroma").val(dataRecord.taste_aroma);
			$("#taste_taste").val(dataRecord.taste_taste);
			$("#taste_mouthfeel").val(dataRecord.taste_mouthfeel);
			$("#taste_aftertaste").val(dataRecord.taste_aftertaste);

			// Recipe
			$("#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);
			$("#st_og_min").val(dataRecord.st_og_min);
			$("#st_og_max").val(dataRecord.st_og_max);
			$("#st_fg_min").val(dataRecord.st_fg_min);
			$("#st_fg_max").val(dataRecord.st_fg_max);
			$("#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);
			$("#st_ibu_min").val(dataRecord.st_ibu_min);
			$("#st_ibu_max").val(dataRecord.st_ibu_max);
			$("#st_carb_min").val(dataRecord.st_carb_min);
			$("#st_carb_min2").val(dataRecord.st_carb_min);
			$("#st_carb_max").val(dataRecord.st_carb_max);
			$("#st_carb_max2").val(dataRecord.st_carb_max);
			$("#type").val(dataRecord.type);
			$("#batch_size").val(dataRecord.batch_size);
			$("#est_a_vol").val(dataRecord.batch_size * 1.04);
			$("#boil_size").val(dataRecord.boil_size);
			$("#est_pre_vol").val(dataRecord.boil_size * 1.04);
			$("#boil_time").val(dataRecord.boil_time);
			$("#efficiency").val(dataRecord.efficiency);
			$("#est_og").val(dataRecord.est_og);
			$("#est_og2").val(dataRecord.est_og);
			$("#est_og3").val(0);
			$("#est_fg").val(dataRecord.est_fg);
			$("#est_fg2").val(dataRecord.est_fg);
			$("#est_fg3").val(dataRecord.est_fg);
			$("#est_color").val(dataRecord.est_color);
			$("#est_color2").val(dataRecord.est_color);
			$("#est_abv").val(dataRecord.est_abv);
			$("#color_method").val(dataRecord.color_method);
			$("#est_ibu").val(dataRecord.est_ibu);
			$("#est_ibu2").val(dataRecord.est_ibu);
			$("#ibu_method").val(dataRecord.ibu_method);
			$("#est_carb").val(dataRecord.est_carb);
			$("#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);
			calcStage();
			$('#jqxTabs').jqxTabs('select', 2);
		},
		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: 450,
                        source: fermentableAdapter,
                        theme: theme,
                        selectionmode: 'singlerow',
                        localization: getLocalization(),
                        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 (row, columnfield, value, defaulthtml, columnproperties) {
                                        var rowData = $("#fermentableGrid").jqxGrid('getrowdata', row);
                                        return "<span style='margin: 3px; margin-top: 6px; float: "+
                                                columnproperties.cellsalign+"'>" +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 "<div style='margin: 4px;'>" + FermentableTypeData[value].nl + "</div>";
				  }
			       	},
                                { text: 'Moment', width: 110, datafield: 'f_added',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<div style='margin: 4px;'>" + AddedData[value].nl + "</div>";
                                  }
                                },
                                { text: 'Opbrengst', 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', cellsalign: 'right', cellsformat: 'f3' },
                                { text: 'Percent', 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: 'Wijzig', 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: 510,
                        source: hopAdapter,
                        theme: theme,
                        selectionmode: 'singlerow',
                        localization: getLocalization(),
                        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);
                                        }
                                });

                                $("#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 (row, columnfield, value, defaulthtml, columnproperties) {
                                        var rowData = $("#hopGrid").jqxGrid('getrowdata', row);
                                        return "<span style='margin: 3px; margin-top: 6px; float: "+
                                                columnproperties.cellsalign+"'>" +rowData.h_origin+" / "+rowData.h_name+"</span>";
                                  },
                                },
                                { text: 'Type', width: 90, datafield: 'h_type',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<div style='margin: 4px;'>" + HopTypeData[value].nl + "</div>";
				  }
			       	},
                                { text: 'Vorm', width: 90, datafield: 'h_form',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<div style='margin: 4px;'>" + HopFormData[value].nl + "</div>";
				  }
			       	},
                                { 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 "<div style='margin: 4px;'>" + HopUseData[value].nl + "</div>";
				  }
				},
				{ text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4))   // Boil, Whirlpool
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" min.</div>";
					if (rowdata.h_useat == 5)       // Dry hop
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value/1440, "f0")+" dagen</div>";
					else
						return "<div style='margin: 4px;'></div>";
				  }
				},
                                { 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 "<div style='margin: 4px;' class='jqx-right-align'>" + dataAdapter.formatNumber(ibu, "f1") + "</div>";
                                  }
                                },
				{ text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right', cellsalign: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					if (value < 1)
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value * 1000, "f1")+" gr</div>";
					else
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f1")+" kg</div>";
				  }
				},
				{ text: 'Voorraad', datafield: 'h_inventory', width: 110, align: 'right', cellsalign: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					if (value < 1)
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value * 1000, "f1")+" gr</div>";
					else
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f1")+" kg</div>";
				  }
				},
				{ text: 'Wijzig', 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: 525,
                        source: miscAdapter,
                        theme: theme,
                        selectionmode: 'singlerow',
                        localization: getLocalization(),
                        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 ingredient" />');
                                // 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 "<div style='margin: 4px;'>" + MiscTypeData[value].nl + "</div>";
				  }
			       	},
                                { text: 'Gebruik', width: 140, datafield: 'm_use_use',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					return "<div style='margin: 4px;'>" + MiscUseData[value].nl + "</div>";
                                  }
                               	},
                               	{ text: 'Tijd', datafield: 'm_time', width: 90, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					if (rowdata.m_use_use == 2) {   // Boil
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" min.</div>";
					} else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) {      // Primary or Secondary
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value/1440, "f0")+" dagen</div>";
					} else {
						var tijd = 0;
						return "<div style='margin: 4px;'> </div>";
					}
				  },
                                },
				{ 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 "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr+"</div>";
				  }
				},
				{ 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";
					return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value * 1000,"f2")+" "+vstr+"</div>";
				  }
				},
				{ text: 'Wijzig', 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: 400,
                        source: yeastAdapter,
                        theme: theme,
                        selectionmode: 'singlerow',
                        localization: getLocalization(),
                        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,
                                        source: yeastlist,
					template: "primary",
                                        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);
                                        }
                                });
                                $("#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 "<div style='margin: 4px;'>" + YeastFormData[value].nl + "</div>";
				  }
			       	},
                                { 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 "<div style='margin: 4px;'>" + YeastUseData[value].nl + "</div>";
                                  }
                                },
				{ text: 'Hoeveel', datafield: 'y_amount', width: 100, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					if (rowdata.y_form == 0) {      // Liquid
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" pk</div>";
					} else if (rowdata.y_form == 1) {       // Dry
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value*1000, "f1")+" gr</div>";
					} else {
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value*1000, "f0")+" ml</div>";
					}
				  }
				},
				{ text: 'Voorraad', datafield: 'y_inventory', width: 100, align: 'right',
				  cellsrenderer: function (index, datafield, value, defaultvalue, column, rowdata) {
					if (rowdata.y_form == 0) {      // Liquid
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value, "f0")+" pk</div>";
					} else if (rowdata.y_form == 1) {       // Dry
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value*1000, "f1")+" gr</div>";
					} else {
						return "<div style='margin: 4px;' class='jqx-right-align'>"+dataAdapter.formatNumber(value*1000, "f0")+" ml</div>";
					}
				  }
				},
				{ text: 'Wijzig', 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, spinButtonsStep: 1 });
						} else if (yeastData.y_form == 1) {
							$("#wy_pmpt_amount").html("Gewicht gram:");
							$("#wy_amount").val(yeastData.y_amount * 1000);
							$("#wy_amount").jqxNumberInput({ decimalDigits: 1, spinButtonsStep: 0.5 });
						} else {
							$("#wy_pmpt_amount").html("Volume ml:");
							$("#wy_amount").val(yeastData.y_amount * 1000);
							$("#wy_amount").jqxNumberInput({ decimalDigits: 0, spinButtonsStep: 1 });
						}
						$("#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"] = "Infusion";
                        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',
                        localization: getLocalization(),
                        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 step.
                                $("#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() {
                                calcInit();
                                $('#jqxLoader').jqxLoader('close');
                                $('#jqxTabs').jqxTabs('first');
                        },
                        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: 'Tijd', datafield: 'step_time', width: 90, align: 'right', cellsalign: 'right' },
                                { text: 'Stap', datafield: 'ramp_time', width: 90, align: 'right', cellsalign: 'right' },
                                { text: 'Infuse', datafield: 'step_infuse_amount', width: 90, align: 'right', cellsalign: 'right' },
				{ text: 'Wijzig', 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 product.' });
	$("#name").jqxInput({ theme: theme, width: 640, height: 23 });
	$("#code").jqxTooltip({ content: 'Product code nummer.' });
	$("#code").jqxInput({ theme: theme, width: 100, height: 23 });
	$("#birth").jqxTooltip({ content: 'De ontwerp datum van dit product.' });
	$("#birth").jqxInput({ theme: theme, width: 120, height: 23 });
	$("#stage").jqxTooltip({ content: 'De productie fase van dit product.' });
	$("#stage").jqxInput({ theme: theme, width: 100, height: 23 });
	$("#inventory_reduced").jqxCheckBox({ theme: theme, width: 120, height: 23 });
	$('#inventory_reduced').on('checked', function (event) {
		// Call a script to do the work and block this.
		// Note that this script must set this flag too, so if the user doesn't Save it is still set.
		// Call the script with the uuid.
		// set dataRecord.inventory_reduced to 1
		$("#inventory_reduced").jqxCheckBox({ disabled : true });
	});
	$("#locked").jqxCheckBox({ theme: theme, width: 120, height: 23, disabled : true });
	$('#locked').on('checked', function (event) {
		if (brewstage >= 10) {
			$("#stage").val('Closed');
			dataRecord.locked = 1;
			brewstage = 11;
		}
	});
	$('#locked').on('unchecked', function (event) {
		if (brewstage >= 10) {
			$("#stage").val('Ready');
			dataRecord.locked = 0;
			brewstage = 10;
		}
	});
	$("#notes").jqxTooltip({ content: 'De uitgebreide opmerkingen over dit product.' });
	$("#notes").jqxInput({ theme: theme, width: 960, height: 100 });
	$("#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_time").jqxTooltip({ content: 'De kooktijd in minuten.' });
	$("#boil_time").jqxNumberInput( PosInt );
	$("#boil_time").jqxNumberInput({ min: 4, max: 360 });
	$("#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 });

	$("#st_guide").jqxTooltip({ content: 'De bierstijl gids voor dit recept.'});
	$("#st_guide").jqxInput({ theme: theme, width: 250, height: 23 });
	$("#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_type").jqxTooltip({ content: 'Het bierstijl type.'});
	$("#st_type").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 });

	$("#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 verwachte 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, Equipment
	$("#eq_name").jqxTooltip({ content: 'De naam van deze brouw apparatuur.' });
	$("#eq_name").jqxInput({ theme: theme, width: 250, height: 23 });
	$("#eq_boil_size").jqxTooltip({ content: 'Normaal kook volume in liters' });
	$("#eq_boil_size").jqxNumberInput( Show1dec );
	$("#eq_batch_size").jqxTooltip({ content: 'Berekende batch grootte in liters aan het eind van de kook.' });
	$("#eq_batch_size").jqxNumberInput( Show1dec );
	$("#eq_tun_volume").jqxTooltip({ content: 'Maisch ketel volume.' });
	$("#eq_tun_volume").jqxNumberInput( Show1dec );
	$("#eq_top_up_water").jqxTooltip({ content: 'Extra water in het gistvat.' });
	$("#eq_top_up_water").jqxNumberInput( Show1dec );
	$("#eq_trub_chiller_loss").jqxTooltip({ content: 'Standaard verlies bij het overbrengen naar het gistvat.' });
	$("#eq_trub_chiller_loss").jqxNumberInput( Show1dec );
	$("#eq_evap_rate").jqxTooltip({ content: 'Verdamping in liters per uur.' });
	$("#eq_evap_rate").jqxNumberInput( Show2dec );
	$("#eq_boil_time").jqxTooltip({ content: 'Normale kooktijd in minuten.' });
	$("#eq_boil_time").jqxNumberInput( Show0dec );
	$("#eq_top_up_kettle").jqxTooltip({ content: 'Extra water toevoegen tijdens de kook.' });
	$("#eq_top_up_kettle").jqxNumberInput( Show1dec );
	$("#eq_hop_utilization").jqxTooltip({ content: '100% voor kleine installaties, hoger voor grote brouwerijen.' });
	$("#eq_hop_utilization").jqxNumberInput( Show0dec );
	$("#eq_notes").jqxTooltip({ content: 'Opmerkingen over deze apparatuur.' });
	$("#eq_notes").jqxInput({ theme: theme, width: 960, height: 200 });
	$("#eq_lauter_volume").jqxTooltip({ content: 'Filterkuip volume.' });
	$("#eq_lauter_volume").jqxNumberInput( Show1dec );
	$("#eq_lauter_deadspace").jqxTooltip({ content: 'Filterkuip verlies in liters.' });
	$("#eq_lauter_deadspace").jqxNumberInput( Show1dec );
	$("#eq_kettle_volume").jqxTooltip({ content: 'Kook ketel volume in liters.' });
	$("#eq_kettle_volume").jqxNumberInput( Show1dec );
	$("#eq_mash_volume").jqxTooltip({ content: 'Maisch water voor de eerste stap.' });
	$("#eq_mash_volume").jqxNumberInput( Show1dec );
	$("#eq_mash_max").jqxTooltip({ content: 'De maximale moutstort in Kg.' });
	$("#eq_mash_max").jqxNumberInput( Show1dec );
	$("#eq_efficiency").jqxTooltip({ content: 'Gemiddeld brouwzaal rendement.' });
	$("#eq_efficiency").jqxNumberInput( Show1dec );

	// Tab 3, Fermentables
	$("#est_color2").jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' });
	$("#est_color2").jqxNumberInput( Show0dec );
	$("#est_og2").jqxTooltip({ content: 'Het geschatte begin SG van dit product.' });
	$("#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();
			calcIBUs();
		};
	});
	$("#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();
					calcIBUs();
				} 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();
					calcIBUs();
				}
			}
		}
	});
	$("#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 4, Hops
	$("#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;
		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 5, Miscs
	$("#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 6, Yeasts
	$("#est_fg2").jqxTooltip({ content: 'Het verwachte 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;
			calcFermentables();
		}
	});

	// Tab 7, Mashing
	$("#mash_name").jqxTooltip({ content: 'De omschrijving van dit maisch profiel.' });
	$("#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);
		}
	});

	// Tab 8, 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', spinMode: 'simple', theme: theme, width: 94, height: 23, min: 0, max: 0, decimalDigits: 1, spinButtons: true, spinButtonsStep: 0.5, 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_total_alkalinity").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_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' });

	// Tab 9, Brewday
	$("#brew_date_start").jqxTooltip({ content: 'Brouw datum en tijd. Voor planning laat de tijd op 00:00:00 staan.' });
	$("#brew_date_start").jqxDateTimeInput( DateTimeopts );
	$('#brew_date_start').on('close', function (event) { calcStage(); });
	$("#brew_date_end").jqxTooltip({ content: 'End datum en tijd van de brouw. Leeg laten als er nog niet gebrouwen is.' });
	$("#brew_date_end").jqxDateTimeInput( DateTimeopts );
	$('#brew_date_end').on('close', function (event) { calcStage(); });
	$("#brew_mash_ph").jqxTooltip({ content: 'De gemeten pH tijdens het maischen eventueel na correctie.' });
	$("#brew_mash_ph").jqxNumberInput( SpinpH );
	$("#est_mash_ph").jqxTooltip({ content: 'De gewenste pH tijdens het maischen.' });
	$("#est_mash_ph").jqxNumberInput( Show1wat );
	$("#brew_preboil_ph").jqxTooltip({ content: 'De gemeten pH in de kookketel na het spoelen en voor de kook.' });
	$("#brew_preboil_ph").jqxNumberInput( SpinpH );
	// est_preboil_ph
	$("#brew_aboil_ph").jqxTooltip({ content: 'De gemeten pH na het koken.' });
	$("#brew_aboil_ph").jqxNumberInput( SpinpH );
	// est_aboil_ph
	$("#brew_mash_sg").jqxTooltip({ content: 'Het bereikte SG na het maischen.' });
	$("#brew_mash_sg").jqxNumberInput( SGopts );
	$("#brew_mash_sg").on('valueChanged', function () { calcMashEfficiency(); });
	$("#est_mash_sg").jqxTooltip({ content: 'Het berekende verwachte SG na het maischen.' });
	$("#est_mash_sg").jqxNumberInput( Show3wat );
	$("#brew_preboil_sg").jqxTooltip({ content: 'Het gemeten SG in de kookketel na het spoelen en voor het koken.' });
	$("#brew_preboil_sg").jqxNumberInput( SGopts );
	$("#brew_preboil_sg").on('valueChanged', function (event) {
		dataRecord.brew_preboil_sg = event.args.value;
		calcEfficiencyBeforeBoil();
	});
	$("#est_pre_sg").jqxTooltip({ content: 'Het berekende SG in de kookketel na het spoelen en voor het koken.' });
	$("#est_pre_sg").jqxNumberInput( Show3wat );
	$("#brew_aboil_sg").jqxTooltip({ content: 'Het gemeten SG in de kookketel na het koken.' });
	$("#brew_aboil_sg").jqxNumberInput( SGopts );
	$("#brew_aboil_sg").on('valueChanged', function (event) {
		dataRecord.brew_aboil_sg = event.args.value;
		calcEfficiencyAfterBoil();
		calcFermentables();
		calcIBUs();
	});
	$("#est_og3").jqxTooltip({ content: 'Het gewenste SG in de kookketel na het koken.' });
	$("#est_og3").jqxNumberInput( Show3wat );
	$("#brew_mash_efficiency").jqxTooltip({ content: 'Het behaalde maisch rendement.' });
	$("#brew_mash_efficiency").jqxNumberInput( Show1dec );
	$("#brew_preboil_volume").jqxTooltip({ content: 'Het gemeten volume van het wort voor het koken.' });
	$("#brew_preboil_volume").jqxNumberInput( Spin1dec );
	$("#brew_preboil_volume").on('valueChanged', function (event) {
		dataRecord.brew_preboil_volume = event.args.value;
		calcEfficiencyBeforeBoil();
	});
	$("#est_pre_vol").jqxTooltip({ content: 'Het berekende volume van het wort voor het koken.' });
	$("#est_pre_vol").jqxNumberInput( Show1wat );
	$("#brew_aboil_volume").jqxTooltip({ content: 'Het gemeten volume van het wort na het koken.' });
	$("#brew_aboil_volume").jqxNumberInput( Spin1dec );
	$("#brew_aboil_volume").on('valueChanged', function (event) {
		dataRecord.brew_aboil_volume = event.args.value;
		calcEfficiencyAfterBoil();
		calcFermentables();
		calcIBUs();
	});
	$("#est_a_vol").jqxTooltip({ content: 'Het gewenste volume na het koken.' });
	$("#est_a_vol").jqxNumberInput( Show1wat );
	$("#brew_preboil_efficiency").jqxTooltip({ content: 'Het berekende rendement voor het koken.' });
	$("#brew_preboil_efficiency").jqxNumberInput( Show1dec );
	$("#brew_aboil_efficiency").jqxTooltip({ content: 'Het bereikte rendement na het koken.' });
	$("#brew_aboil_efficiency").jqxNumberInput( Show1dec );
	$("#brew_sparge_temperature").jqxNumberInput( Spin1dec );
	$("#brew_sparge_volume").jqxNumberInput( Spin1dec );
	$("#brew_sparge_est").jqxNumberInput( Show1dec );
	$("#brew_whirlpool9").jqxNumberInput( PosInt );
	$("#brew_whirlpool9").jqxNumberInput({ max: 120 });
	$("#brew_cooling_to").jqxNumberInput( Spin1dec );
	$("#brew_sparge_ph").jqxNumberInput( SpinpH );
	$("#brew_whirlpool7").jqxNumberInput( PosInt );
	$("#brew_whirlpool7").jqxNumberInput({ max: 120 });
	$("#brew_cooling_method").jqxDropDownList({
		theme: theme,
		source: CoolingTypeAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true
	});
	$("#brew_whirlpool6").jqxNumberInput( PosInt );
	$("#brew_whirlpool6").jqxNumberInput({ max: 120 });
	$("#brew_cooling_time").jqxNumberInput( PosInt );
	$("#brew_cooling_time").jqxNumberInput({ max: 1440 });
	$("#brew_whirlpool2").jqxNumberInput( PosInt );
	$("#brew_whirlpool2").jqxNumberInput({ max: 120 });
	$("#brew_aeration_type").jqxDropDownList({
		theme: theme,
		source: AerationTypeAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true
	});
	$("#brew_aeration_time").jqxNumberInput( PosInt );
	$("#brew_aeration_time").jqxNumberInput({ max: 1440 });
	$("#brew_aeration_speed").jqxNumberInput( PosInt );
	$("#brew_aeration_speed").jqxNumberInput({ max: 1440 });
	$("#brew_fermenter_volume").jqxNumberInput( Show1dec );
	$("#brew_fermenter_extrawater").jqxNumberInput( Spin1dec );
	$("#brew_fermenter_sg").jqxNumberInput( Show3dec );
	$("#brew_fermenter_tcloss").jqxNumberInput( Spin1dec );
	$("#brew_fermenter_ibu").jqxNumberInput( Show0dec );
	$("#brew_fermenter_color").jqxNumberInput( Show0dec );
	$("#BLog").jqxButton({ template: "info", width: '150px', theme: theme });
	$("#BLog").click(function () {
		// Open log in a new tab.
		var url="log_brew.php?code=" + dataRecord.code;
		window.open(url);
	});

	// Tab 10, Fermentation
	// Note, fermentation temps changes must do calcCarbonation()
	$("#brew_fermenter_sg2").jqxNumberInput( Show3dec );
	$("#primary_start_temp").jqxNumberInput( YeastT );
	$("#primary_max_temp").jqxNumberInput( YeastT );
	$("#primary_end_temp").jqxNumberInput( YeastT );
	$("#primary_end_sg").jqxNumberInput( SGopts );
	$("#primary_svg").jqxNumberInput( Show1dec );
	$("#primary_end_date").jqxTooltip({ content: 'De eind datum van de hoofdvergisting en eventueel overhevelen.' });
	$("#primary_end_date").jqxDateTimeInput( Dateopts );
	$('#primary_end_date').on('close', function (event) { calcStage(); });
	$("#secondary_temp").jqxNumberInput( YeastT );
	$("#secondary_end_date").jqxTooltip({ content: 'De eind datum van de navergisting en het begin van het lageren.' });
	$("#secondary_end_date").jqxDateTimeInput( Dateopts );
	$('#secondary_end_date').on('close', function (event) { calcStage(); });
	$("#tertiary_temp").jqxNumberInput( YeastT );
	$("#fg").jqxNumberInput( Spin3dec );
	$("#est_fg3").jqxTooltip({ content: 'Het verwachte eind SG. Dit wordt automatisch berekend.' });
	$("#est_fg3").jqxNumberInput( Show3dec );
	$("#final_abv").jqxNumberInput( Show1dec );
	$("#final_svg").jqxNumberInput( Show1dec );
	$("#FLog").jqxButton({ template: "info", width: '150px', theme: theme });
	$("#FLog").click(function () {
		// Open log in a new tab.
		var url="log_fermentation.php?code=" + dataRecord.code + "&name=" + dataRecord.name;
		window.open(url);
	});

	// Tab 11, Packaging
	// TODO: high gravity packaging, extra water and recalc abv, color and ibu.
	$("#package_date").jqxTooltip({ content: 'De verpakkings datum van dit bier.' });
	$("#package_date").jqxDateTimeInput( Dateopts );
	$('#package_date').on('close', function (event) { calcStage(); });
	$("#st_carb_min2").jqxTooltip({ content: 'Het minimum aanbevolen koolzuur volume voor deze bierstijl.'});
	$("#st_carb_min2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
	$("#st_carb_max2").jqxTooltip({ content: 'Het maximum aamnevolen koolzuur volume voor deze bierstijl.'});
	$("#st_carb_max2").jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 1, readOnly: true });
	$("#bottle_amount").jqxTooltip({ content: 'De totale hoeveelheid te bottelen bier.' });
	$("#bottle_amount").jqxNumberInput( Spin1dec );
	$("#keg_amount").jqxTooltip({ content: 'De totale hoeveelheid op fust te zetten bier.' });
	$("#keg_amount").jqxNumberInput( Spin1dec );
	$("#bottle_carbonation").jqxTooltip({ content: 'Het gewenste CO2 volume in de flessen.' });
	$("#bottle_carbonation").jqxNumberInput( Spin2dec );
	$("#bottle_carbonation").jqxNumberInput({ max: 5 });
	$("#keg_carbonation").jqxTooltip({ content: 'Het gewenste CO2 volume door de suiker in de fusten.' });
	$("#keg_carbonation").jqxNumberInput( Spin2dec );
	$("#keg_carbonation").jqxNumberInput({ max: 5 });
	$("#bottle_priming_sugar").jqxDropDownList({
		theme: theme,
		source: PrimingSugarAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true
	});
	$("#keg_priming_sugar").jqxDropDownList({
		theme: theme,
		source: PrimingSugarAdapter,
		valueMember: 'id',
		displayMember: 'nl',
		width: 180,
		height: 23,
		autoDropDownHeight: true
	});
	$("#bottle_priming_amount").jqxNumberInput( Show1dec );
	$("#keg_priming_amount").jqxNumberInput( Show1dec );
	$("#bottle_priming_total").jqxNumberInput( Show1dec );
	$("#keg_priming_total").jqxNumberInput( Show1dec );
	$("#keg_forced_carb").jqxCheckBox({ theme: theme, width: 120, height: 23 });
	$("#keg_pressure").jqxNumberInput( Show1dec );
	$("#bottle_abv").jqxNumberInput( Show1dec );
	$("#keg_abv").jqxNumberInput( Show1dec );
	$("#bottle_carbonation_temp").jqxNumberInput( YeastT );
	$("#keg_carbonation_temp").jqxNumberInput( YeastT );

	// Tab 12, Tasting
	$("#taste_date").jqxTooltip({ content: 'De proef datum van dit bier.' });
        $("#taste_date").jqxDateTimeInput( Dateopts );
	$('#taste_date').on('close', function (event) { calcStage(); });
	$("#taste_rate").jqxTooltip({ content: 'Het cijfer voor dit bier van 1 tot 10.' });
	$("#taste_rate").jqxNumberInput( Spin1dec );
	$("#taste_rate").jqxNumberInput({ max: 10 });
	$("#taste_color").jqxTooltip({ content: 'De kleur van het bier.' });
	$("#taste_color").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#taste_transparency").jqxTooltip({ content: 'De helderheid van het bier.' });
	$("#taste_transparency").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#taste_head").jqxTooltip({ content: 'Het schuim op het bier.' });
	$("#taste_head").jqxInput({ theme: theme, width: 320, height: 23 });
	$("#taste_aroma").jqxTooltip({ content: 'Het aroma van het bier.' });
	$("#taste_aroma").jqxInput({ theme: theme, width: 960, height: 23 });
	$("#taste_taste").jqxTooltip({ content: 'De smaak van het bier.' });
	$("#taste_taste").jqxInput({ theme: theme, width: 960, height: 23 });
	$("#taste_aftertaste").jqxTooltip({ content: 'De nasmaak van het bier.' });
	$("#taste_aftertaste").jqxInput({ theme: theme, width: 960, height: 23 });
	$("#taste_mouthfeel").jqxTooltip({ content: 'Het mondgevoelvan het bier.' });
	$("#taste_mouthfeel").jqxInput({ theme: theme, width: 960, height: 23 });
	$("#taste_notes").jqxTooltip({ content: 'Het oordeel en opmerkingen over dit bier.' });
	$("#taste_notes").jqxInput({ theme: theme, width: 960, height: 100 });

	$('#jqxTabs').jqxTabs({
		theme: theme,
		width: 1280,
		height: 630,
		autoHeight: false,
		position: 'top'
	});

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

	$("#Export").jqxButton({ template: "info", width: '80px', theme: theme });
	$("#Export").click(function () {
		// Open print in a new tab.
		var url="prod_export.php?record=" + my_record;
		window.open(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({ uuid: dataRecord.uuid });
			$.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: '90px', theme: theme });
	$("#Save").click(function () {
		console.log(dataRecord.uuid);
		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(),
			code: $("#code").val(),
			birth: $("#birth").val(),
			stage: dataRecord.stage,
			notes: $("#notes").val(),
			log_brew: dataRecord.log_brew,
			log_fermentation: dataRecord.log_fermentation,
			inventory_reduced: dataRecord.inventory_reduced,
			locked: dataRecord.locked,
			eq_name: $("#eq_name").val(),
			eq_boil_size: parseFloat($("#eq_boil_size").jqxNumberInput('decimal')),
			eq_batch_size: parseFloat($("#eq_batch_size").jqxNumberInput('decimal')),
			eq_tun_volume: parseFloat($("#eq_tun_volume").jqxNumberInput('decimal')),
			eq_tun_weight: dataRecord.eq_tun_weight,
			eq_tun_specific_heat: dataRecord.eq_tun_specific_heat,
			eq_tun_material: dataRecord.eq_tun_material,
			eq_tun_height: dataRecord.eq_tun_height,
			eq_top_up_water: parseFloat($("#eq_top_up_water").jqxNumberInput('decimal')),
			eq_trub_chiller_loss: parseFloat($("#eq_trub_chiller_loss").jqxNumberInput('decimal')),
			eq_evap_rate: parseFloat($("#eq_evap_rate").jqxNumberInput('decimal')),
			eq_boil_time: parseFloat($("#eq_boil_time").jqxNumberInput('decimal')),
			eq_calc_boil_volume: dataRecord.eq_calc_boil_volume,
			eq_top_up_kettle: parseFloat($("#eq_top_up_kettle").jqxNumberInput('decimal')),
			eq_hop_utilization: parseFloat($("#eq_hop_utilization").jqxNumberInput('decimal')),
			eq_notes: $("#eq_notes").val(),
			eq_lauter_volume: parseFloat($("#eq_lauter_volume").jqxNumberInput('decimal')),
			eq_lauter_height: dataRecord.eq_lauter_height,
			eq_lauter_deadspace: parseFloat($("#eq_lauter_deadspace").jqxNumberInput('decimal')),
			eq_kettle_volume: parseFloat($("#eq_kettle_volume").jqxNumberInput('decimal')),
			eq_kettle_height: dataRecord.eq_kettle_height,
			eq_mash_volume: parseFloat($("#eq_mash_volume").jqxNumberInput('decimal')),
			eq_mash_max: parseFloat($("#eq_mash_max").jqxNumberInput('decimal')),
			eq_efficiency: parseFloat($("#eq_efficiency").jqxNumberInput('decimal')),
			brew_date_start: $("#brew_date_start").val(),
			brew_mash_ph: parseFloat($("#brew_mash_ph").jqxNumberInput('decimal')),
			brew_mash_sg: parseFloat($("#brew_mash_sg").jqxNumberInput('decimal')),
			brew_sparge_temperature: parseFloat($("#brew_sparge_temperature").jqxNumberInput('decimal')),
			brew_sparge_volume: parseFloat($("#brew_sparge_volume").jqxNumberInput('decimal')),
			brew_sparge_ph: parseFloat($("#brew_sparge_ph").jqxNumberInput('decimal')),
			brew_preboil_volume: parseFloat($("#brew_preboil_volume").jqxNumberInput('decimal')),
			brew_preboil_sg: parseFloat($("#brew_preboil_sg").jqxNumberInput('decimal')),
			brew_preboil_ph: parseFloat($("#brew_preboil_ph").jqxNumberInput('decimal')),
			brew_aboil_volume: parseFloat($("#brew_aboil_volume").jqxNumberInput('decimal')),
			brew_aboil_sg: parseFloat($("#brew_aboil_sg").jqxNumberInput('decimal')),
			brew_aboil_ph: parseFloat($("#brew_aboil_ph").jqxNumberInput('decimal')),
			brew_aboil_efficiency: parseFloat($("#brew_aboil_efficiency").jqxNumberInput('decimal')),
			brew_cooling_method: $("#brew_cooling_method").val(),
			brew_cooling_time: parseFloat($("#brew_cooling_time").jqxNumberInput('decimal')),
			brew_cooling_to: parseFloat($("#brew_cooling_to").jqxNumberInput('decimal')),
			brew_whirlpool9: parseFloat($("#brew_whirlpool9").jqxNumberInput('decimal')),
			brew_whirlpool7: parseFloat($("#brew_whirlpool7").jqxNumberInput('decimal')),
			brew_whirlpool6: parseFloat($("#brew_whirlpool6").jqxNumberInput('decimal')),
			brew_whirlpool2: parseFloat($("#brew_whirlpool2").jqxNumberInput('decimal')),
			brew_fermenter_volume: parseFloat($("#brew_fermenter_volume").jqxNumberInput('decimal')),
			brew_fermenter_extrawater: parseFloat($("#brew_fermenter_extrawater").jqxNumberInput('decimal')),
			brew_fermenter_tcloss: parseFloat($("#brew_fermenter_tcloss").jqxNumberInput('decimal')),
			brew_aeration_time: parseFloat($("#brew_aeration_time").jqxNumberInput('decimal')),
			brew_aeration_speed: parseFloat($("#brew_aeration_speed").jqxNumberInput('decimal')),
			brew_aeration_type: $("#brew_aeration_type").val(),
			brew_fermenter_sg: parseFloat($("#brew_fermenter_sg").jqxNumberInput('decimal')),
			brew_fermenter_ibu: parseFloat($("#brew_fermenter_ibu").jqxNumberInput('decimal')),
			brew_fermenter_color: parseFloat($("#brew_fermenter_color").jqxNumberInput('decimal')),
			brew_date_end: $("#brew_date_end").val(),
			og: dataRecord.og,
			fg: parseFloat($("#fg").jqxNumberInput('decimal')),
			primary_start_temp: parseFloat($("#primary_start_temp").jqxNumberInput('decimal')),
			primary_max_temp: parseFloat($("#primary_max_temp").jqxNumberInput('decimal')),
			primary_end_temp: parseFloat($("#primary_end_temp").jqxNumberInput('decimal')),
			primary_end_sg: parseFloat($("#primary_end_sg").jqxNumberInput('decimal')),
			primary_end_date: $("#primary_end_date").val(),
			secondary_temp: parseFloat($("#secondary_temp").jqxNumberInput('decimal')),
			secondary_end_date: $("#secondary_end_date").val(),
			tertiary_temp: parseFloat($("#tertiary_temp").jqxNumberInput('decimal')),
			package_date: $("#package_date").val(),
			bottle_amount: parseFloat($("#bottle_amount").jqxNumberInput('decimal')),
			bottle_carbonation: parseFloat($("#bottle_carbonation").jqxNumberInput('decimal')),
			bottle_priming_sugar: $("#bottle_priming_sugar").val(),
			bottle_priming_amount: parseFloat($("#bottle_priming_amount").jqxNumberInput('decimal')),
			bottle_carbonation_temp: parseFloat($("#bottle_carbonation_temp").jqxNumberInput('decimal')),
			keg_amount: parseFloat($("#keg_amount").jqxNumberInput('decimal')),
			keg_carbonation: parseFloat($("#keg_carbonation").jqxNumberInput('decimal')),
			keg_priming_sugar: $("#keg_priming_sugar").val(),
			keg_priming_amount: parseFloat($("#keg_priming_amount").jqxNumberInput('decimal')),
			keg_carbonation_temp: parseFloat($("#keg_carbonation_temp").jqxNumberInput('decimal')),
			keg_forced_carb: dataRecord.keg_forced_carb,
			keg_pressure: parseFloat($("#keg_pressure").jqxNumberInput('decimal')),
			taste_notes: $("#taste_notes").val(),
			taste_rate: parseFloat($("#taste_rate").jqxNumberInput('decimal')),
			taste_date: $("#taste_date").val(),
			taste_color: $("#taste_color").val(),
			taste_transparency: $("#taste_transparency").val(),
			taste_head: $("#taste_head").val(),
			taste_aroma: $("#taste_aroma").val(),
			taste_taste: $("#taste_taste").val(),
			taste_mouthfeel: $("#taste_mouthfeel").val(),
			taste_aftertaste: $("#taste_aftertaste").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: dataRecord.calc_acid,
			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) {
				// update command is executed.
				window.location.href = my_return;
			},
			error: function(jqXHR, textStatus, errorThrown) {
			}
		});
	});	
	createDelElements();
});

mercurial