/**
 * Controller class for AnalysisRequestAddView
 */
function AnalysisRequestAddView() {

	var that = this;

	that.load = function () {

		ar_rename_elements();
		ar_referencewidget_lookups();
		ar_set_tabindexes();

		$("input[type=text]").prop("autocomplete", "off")

		$(".copyButton").live("click", copyButton);

		$("th[class^='analysiscategory']").click(clickAnalysisCategory);
		expand_default_categories();

		$("input[name^='Price']").live("change", recalc_prices);

		$("input[id*='_ReportDryMatter']").change(changeReportDryMatter);

		$(".spec_bit").live("change", function () {
			validate_spec_field_entry(this);
		});

		// AR Add/Edit ajax form submits
		loadAjaxSubmitHandler();

		// these go here so that popup windows can access them in our context
		window.recalc_prices = recalc_prices;
		window.calculate_parts = calculate_parts;
		window.toggleCat = toggleCat;

		// Filter data by the selected client
		filterByClient();

		// the copy_to_new button passes a copy_from request parameter
		// which is a UID or comma separated list oif UIDs.
		var copy_from = window.location.href.split("copy_from=");
		if (copy_from.length > 1) {
			copy_from = copy_from[1].split("&")[0];
			copy_from = copy_from.split(",");
			for (var column = 0; column < copy_from.length; column++) {
				// use this to pass column nr to the fill_column callback
				window.bika.ar_copy_from_col = column;
				// XXX async.
				$.ajaxSetup({async: false});
				window.bika.lims.jsonapi_read({
												  catalog_name: "uid_catalog",
												  UID: copy_from[column]
											  }, fill_column);
				$.ajaxSetup({async: true});
			}
		}
	}


    /**
     *  AR Add/Edit ajax form submits
     */
    function loadAjaxSubmitHandler() {
        var ar_edit_form = $("#analysisrequest_edit_form");
        var options = {
            url: window.location.href.split("/portal_factory")[0] + "/analysisrequest_submit",
            dataType: "json",
            data: {"_authenticator": $("input[name='_authenticator']").val()},
            beforeSubmit: function() {
                $("input[class~='context']").prop("disabled",true);
            },
            success: function(responseText) {
                var destination;
                if(responseText.success !== undefined){
                    if(responseText.labels !== undefined){
                        destination = window.location.href
                            .split("/portal_factory")[0];
                        var ars = responseText.labels;
                        var labelsize = responseText.labelsize;
                        var q = "/sticker?size="+labelsize+"&items=";
                        q = q + ars.join(",");
                        window.location.replace(destination+q);
                    } else {
                        destination = window.location.href
                            .split("/portal_factory")[0];
                        window.location.replace(destination);
                    }
                } else {
                    var msg = "";
                    for(var error in responseText.errors){
                        var x = error.split(".");
                        var e;
                        if (x.length == 2){
                            e = x[1] + ", Column " + (+x[0]) + ": ";
                        } else {
                            e = "";
                        }
                        msg = msg + e + responseText.errors[error] + "<br/>";
                    }
                    window.bika.lims.portalMessage(msg);
                    window.scroll(0,0);
                    $("input[class~='context']").prop("disabled", false);
                }
            },
            error: function(XMLHttpRequest, statusText) {
                window.bika.lims.portalMessage(statusText);
                window.scroll(0,0);
                $("input[class~='context']").prop("disabled", false);
            }
        };
        $("#analysisrequest_edit_form").ajaxForm(options);
    }

    /**
     * Show only the data (contacts, templates, etc.) for the selected
     * client.   This is the initial filter, but the filters are re-applied
	 * each time a Client field is modified.
     */
    function filterByClient() {
        // Iterate all the columns to filtrate by client
        for (var col = 0; col < parseInt($("#col_count").val(), 10); col++) {
            var element = $("#ar_" + col + "_Contact");
            var clientuid = $("#ar_" + col + "_Client_uid").val();
            // Initial value of contact list, set by the page's hidden ClientUID.
            applyComboFilter(element, "getParentUID", clientuid);
            element = $("#ar_" + col + "_CCContact");
            applyComboFilter(element, "getParentUID", clientuid);
            // Filter sample points by client
            element = $("#ar_" + col + "_SamplePoint");
            applyComboFilter(element, "getClientUID",
                             [clientuid, $("#bika_setup").attr("bika_samplepoints_uid")]);
            // Filter template by client
            element = $("#ar_" + col + "_Template");
            applyComboFilter(element, "getClientUID",
                             [clientuid, $("#bika_setup").attr("bika_artemplates_uid")]);
            // Filter Analysis Profile by client
            element = $("#ar_" + col + "_Profile");
            applyComboFilter(element, "getClientUID",
                             [clientuid, $("#bika_setup").attr("bika_analysisprofiles_uid")]);
            // Filter Analysis Spec by client
            element = $("#ar_" + col + "_Specification");
            applyComboFilter(element, "getClientUID",
                             [clientuid, $("#bika_setup").attr("bika_analysisspecs_uid")]);
        }
    }

    function destroy(arr, val) {
        for (var i = 0; i < arr.length; i++) if (arr[i] === val) arr.splice(i, 1);
        return arr;
    }

	function set_specs(column){
		// Get the spec for this column, and check if the hidden #spec input must be updated
		var spec_uid = $("#ar_" + column + "_Specification_uid").val();
		if (spec_uid == "" || spec_uid == undefined || spec_uid == null) {
			return;
		}
		var request_data = {
			catalog_name: 'bika_setup_catalog',
			UID: spec_uid
		};
		window.bika.lims.jsonapi_read(request_data, function (data) {
			if (data.success && data.objects.length > 0) {
				// Update the #specs value.
				var element = $("#specs");
				var form_rr = $.parseJSON($(element).val());
				form_rr[column] = data.objects[0]['ResultsRange'];
				$(element).val($.toJSON(form_rr));

				/* Specs are taken from the Specification element values (#specs).
				   If a spec is defined in copy_to_new_specs, it is used instead, and the
				   values in #specs have no effect. */
				var copy_to_new_specs = $.parseJSON($("#copy_to_new_specs").val());
				var specs = $.parseJSON($("#specs").val());
				var rr = copy_to_new_specs[column];
				if (rr == undefined || rr.length < 1) {
					rr = specs[column];
				}
				// Set values for selected analyses
				if (rr != undefined && rr.length > 0) {
					for (var i = 0; i < rr.length; i++) {
						var this_min = "[name='ar." + column + ".min." + rr[i].uid + "']";
						var this_max = "[name='ar." + column + ".max." + rr[i].uid + "']";
						var this_error = "[name='ar." + column + ".error." + rr[i].uid + "']";
						if ($(this_min).length > 0) {
							if ($(this_min).val() == "") {
								$(this_min).val(rr[i].min);
							}
							if ($(this_max).val() == "") {
								$(this_max).val(rr[i].max);
							}
							if ($(this_error).val() == "") {
								$(this_error).val(rr[i].error);
							}
						}
					}
				}


			}
		});
	}

	function reset_spec_fields(arnum) {
		$("[name^='ar." + arnum + ".min']").val("");
		$("[name^='ar." + arnum + ".max']").val("");
		$("[name^='ar." + arnum + ".error']").val("");
	}

	function toggle_spec_fields(element) {
		// This flag disables spec inputs
		if (!$("#bika_setup").attr("EnableARSpecs")) {
			return;
		}
		// Specifications not allowed if ResultOptions used for service
		if (element.attr("has_resultoptions") == "True") {
			return;
		}

		var column = $(element).attr("column");
		var service_uid = $(element).attr("value");
		var min_name = "ar." + column + ".min." + service_uid;
		var max_name = "ar." + column + ".max." + service_uid;
		var error_name = "ar." + column + ".error." + service_uid;

		if ($(element).prop("checked") &&
				$(element).siblings().filter("[name='" + min_name + "']").length == 0) {
			var min = $("<input class='spec_bit min' type='text' size='3' uid='" + service_uid + "' value='' name='" + min_name + "' keyword='" + $(element).attr("keyword") + "' autocomplete='off' placeholder='&gt;'/>");
			var max = $("<input class='spec_bit max' type='text' size='3' uid='" + service_uid + "' value='' name='" + max_name + "' keyword='" + $(element).attr("keyword") + "' autocomplete='off' placeholder='&lt;'/>");
			var error = $("<input class='spec_bit error' type='text' size='3' uid='" + service_uid + "' value='' name='" + error_name + "' keyword='" + $(element).attr("keyword") + "' autocomplete='off' placeholder='%'/>");
			$(element).after(error).after(max).after(min);
		} else {
			$("input[name='" + min_name + "']").remove();
			$("input[name='" + max_name + "']").remove();
			$("input[name='" + error_name + "']").remove();
		}
		set_specs(column);
	}

    function validate_spec_field_entry(element) {
        var column = $(element).attr("name").split(".")[1];
        var uid = $(element).attr("uid");
        $("[name^='ar\\."+column+"\\.Specification']").val("");
        $("[name^='ar\\."+column+"\\.Specification_uid']").val("");
        var min_element = $("[name='ar."+column+".min."+uid+"']");
        var max_element = $("[name='ar."+column+".max."+uid+"']");
        var error_element = $("[name='ar."+column+".error."+uid+"']");
        var min = parseFloat($(min_element).val(), 10);
        var max = parseFloat($(max_element).val(), 10);
        var error = parseFloat($(error_element).val(), 10);
        if($(element).hasClass("min")){
            if(isNaN(min)) {
                $(min_element).val("");
            } else if ((!isNaN(max)) && min > max) {
                $(max_element).val("");
            }
        } else if($(element).hasClass("max")){
            if(isNaN(max)) {
                $(max_element).val("");
            } else if ((!isNaN(min)) && max < min) {
                $(min_element).val("");
            }
        } else if($(element).hasClass("error")){
            if(isNaN(error) || error < 0 || error > 100){
                $(error_element).val("");
            }
        }
    }

    function set_cc_contacts(column) {
        var contact_uid = $("#ar_"+column+"_Contact_uid").val();
        var fieldName = "ar."+column+".CCContact";
        // clear the CC widget
        $("input[name='"+fieldName+":record']").val("");
        $("input[name='"+fieldName+":record']").attr("uid", "");
        $("input[name='"+fieldName+"_uid']").val("");
        $("#ar_"+column+"_CCContact-listing").empty();
        if(contact_uid !== ""){
            var request_data = {
                portal_type: "Contact",
                UID: contact_uid
            };
            window.bika.lims.jsonapi_read(request_data, function(data) {
                if(data.objects && data.objects.length < 1) {
                    return;
                }
                var ob = data.objects[0];
                var cc_titles = ob.CCContact;
                var cc_uids = ob.CCContact_uid;
                if(!cc_uids) {
                    return;
                }
                $("input[name='"+fieldName+"_uid']").val(cc_uids.join(","));
                for (var i = 0; i < cc_uids.length; i++) {
                    var title = cc_titles[i];
                    var uid = cc_uids[i];
                    var del_btn_src = window.portal_url+"/++resource++bika.lims.images/delete.png";
                    var del_btn = "<img class='ar_deletebtn' src='"+del_btn_src+"' fieldName='"+fieldName+"' uid='"+uid+"'/>";
                    var new_item = "<div class='reference_multi_item' uid='"+uid+"'>"+del_btn+title+"</div>";
                    $("#ar_"+column+"_CCContact-listing").append($(new_item));
                }
            });
        }
    }

    function modify_Specification_field_filter(column) {
        // when a SampleType is selected I will allow only specs to be selected
        // which 1- (have the same Sample Types)
        // 2- (have no sample type at all)
        var sampletype_title = $("#ar_"+column+"_SampleType").val();
        var e = $("#ar_"+column+"_Specification");
        var query_str = $(e).attr("search_query");
        var query_obj = $.parseJSON(query_str);
        if (    query_obj.hasOwnProperty("getSampleTypeTitle") ){
            delete query_obj.getSampleTypeTitle;
        }
        query_obj.getSampleTypeTitle = [encodeURIComponent(sampletype_title), ""];
        query_str = $.toJSON(query_obj);
        $(e).attr("search_query", query_str);
    }

	function set_Specification_from_SampleType(column) {
		st_title = $("#ar_" + column + "_SampleType").val();
		st_uid = $("#ar_" + column + "_SampleType_uid").val();
		if (st_uid == undefined || st_uid == null || st_uid == "") {
			return;
		}
		spec_element = $("#ar_" + column + "_Specification");
		spec_uid_element = $("#ar_" + column + "_Specification_uid");
		var request_data = {
			catalog_name: "bika_setup_catalog",
			portal_type: "AnalysisSpec",
			getSampleTypeTitle: st_title,
			include_fields: ["Title", "UID"]
		};
		window.bika.lims.jsonapi_read(request_data, function (data) {
			if (data.objects.length > 0) {
				var spec = data.objects[0];
				// set spec values for this column
				$(spec_element).val(spec.Title);
				$(spec_uid_element).val(spec.UID);
				reset_spec_fields(column);
				set_specs(column);
			}
		});
	}

    function ar_set_tabindexes() {
        // Sets the tab index to the elements. Tab flow top to bottom instead of left
        // to right.
        // Keyboard tab flow top to bottom instead of left to right
        var index = 10;
        var count = $("input[id='col_count']").val();
        for (var i=0; i<count; i++) {
            var elements = $("td[column="+i+"]").find("input[type!=hidden]").not("[disabled]");
            for (var j=0; j<elements.length; j++) {
                $(elements[j]).attr("tabindex",index);
                index++;
            }
        }
    }

    // Configure the widgets that archetypes built:
    // set id and name to ar-col-fieldName formats
    // un-set the readonly attribute on the fields (so that we can search).
    function ar_rename_elements(){
        var i, e, elements, column;
        elements = $("td[ar_add_column_widget]").find("input[type!='hidden']").not("[disabled]");
        for (i = elements.length - 1; i >= 0; i--) {
            e = elements[i];
            column = $($(e).parents("td")).attr("column");
            // not :ignore_empty, widgets each get submitted to their own form handlers
            $(e).attr("name", "ar."+column+"."+$(e).attr("name")+":record");
            $(e).attr("id", "ar_"+column+"_"+e.id);
            $(e).removeAttr("required");
        }
        elements = $("td[ar_add_column_widget]").find("input[type='hidden']");
        for (i = elements.length - 1; i >= 0; i--) {
            e = elements[i];
            column = $($(e).parents("td")).attr("column");
            $(e).attr("id", "ar_"+column+"_"+e.id);
            // not :ignore_empty, widgets each get submitted to their own form handlers
            $(e).attr("name", "ar."+column+"."+$(e).attr("name")+":record");
        }
        elements = $(".multiValued-listing");
        for (i = elements.length - 1; i >= 0; i--) {
            e = elements[i];
            var eid = e.id.split("-listing")[0];
            column = $($(e).parents("td")).attr("column");
            $(e).attr("id", "ar_"+column+"_"+eid+"-listing");
            // not :ignore_empty, widgets each get submitted to their own form handlers
            $(e).attr("name", "ar."+column+"."+eid+"-listing");
            $(e).attr("fieldName", "ar."+column+"."+eid);
        }
    }

    // The columnar referencewidgets that we reconfigure use this as their
    // select handler.
    function ar_referencewidget_select_handler(event, ui){
        /*jshint validthis:true */
        event.preventDefault();

        // Set form values in activated element (must exist in colModel!)
        var column = $(this).attr("id").split("_")[1];
        var fieldName = $(this).attr("name").split(".")[2].split(":")[0];
        var skip;

        var uid_element = $("#ar_"+column+"_"+fieldName+"_uid");
        var listing_div = $("#ar_"+column+"_"+fieldName+"-listing");
        if(listing_div.length > 0) {
          // Add selection to textfield value
          var existing_uids = $(uid_element).val().split(",");
          destroy(existing_uids,"");
          destroy(existing_uids,"[]");
          var selected_value = ui.item[$(this).attr("ui_item")];
          var selected_uid = ui.item.UID;
          if (existing_uids.indexOf(selected_uid) == -1) {
              existing_uids.push(selected_uid);
              $(this).val("");
              $(this).attr("uid", existing_uids.join(","));
              $(uid_element).val(existing_uids.join(","));
                        // insert item to listing
                        var del_btn_src = portal_url+"/++resource++bika.lims.images/delete.png";
                        var del_btn = "<img class='deletebtn' src='"+del_btn_src+"' fieldName='ar."+column+"."+fieldName+"' uid='"+selected_uid+"'/>";
                        var new_item = "<div class='reference_multi_item' uid='"+selected_uid+"'>"+del_btn+selected_value+"</div>";
                        $(listing_div).append($(new_item));
          }
          skip = $(uid_element).attr("skip_referencewidget_lookup");
          if (skip !== true){
              $(this).trigger("selected", ui.item.UID);
          }
          $(uid_element).removeAttr("skip_referencewidget_lookup");
          $(this).next("input").focus();
        } else {
            // Set value in activated element (must exist in colModel!)
            $(this).val(ui.item[$(this).attr("ui_item")]);
            $(this).attr("uid", ui.item.UID);
            $(uid_element).val(ui.item.UID);
            skip = $(uid_element).attr("skip_referencewidget_lookup");
            if (skip !== true){
                $(this).trigger("selected", ui.item.UID);
            }
            $(uid_element).removeAttr("skip_referencewidget_lookup");
            $(this).next("input").focus();
        }

		if (fieldName == "Client") {
			var element = $("#ar_" + column + "_Contact");
			var clientuid = $(this).attr("uid");
			applyComboFilter(element, "getParentUID", clientuid);
			element = $("#ar_" + column + "_CCContact");
			applyComboFilter(element, "getParentUID", clientuid);
			// Filter sample points by client
			element = $("#ar_" + column + "_SamplePoint");
			applyComboFilter(element, "getClientUID",
							 [clientuid,
							  $("#bika_setup").attr("bika_samplepoints_uid")]);
			// Filter template by client
			element = $("#ar_" + column + "_Template");
			applyComboFilter(element, "getClientUID",
							 [clientuid,
							  $("#bika_setup").attr("bika_artemplates_uid")]);
			// Filter Analysis Profile by client
			element = $("#ar_" + column + "_Profile");
			applyComboFilter(element, "getClientUID",
							 [clientuid,
							  $("#bika_setup").attr("bika_analysisprofiles_uid")]);
			// Filter Analysis Spec by client
			element = $("#ar_" + column + "_Specification");
			applyComboFilter(element, "getClientUID",
							 [clientuid,
							  $("#bika_setup").attr("bika_analysisspecs_uid")]);
		}
        if(fieldName == "Contact"){
          set_cc_contacts(column);
        }
        if(fieldName == "SampleType"){
            //// selecting a Sampletype - jiggle the SamplePoint element.
            //var sp_element = $("#ar_"+column+"_SamplePoint");
            //sp_element
            //    .removeClass( "cg-autocomplete-input" )
            //    .removeAttr( "autocomplete" )
            //    .removeAttr( "role" )
            //    .removeAttr( "aria-autocomplete" )
            //    .removeAttr( "aria-haspopup" );
            //var new_sp_element = $(sp_element[0]).clone();
            //var sp_parent_node = $(sp_element).parent();
            //$(sp_element).remove();
            //$(sp_parent_node).append(new_sp_element);
            //var sp_search_query = {"getSampleTypeTitle": [encodeURIComponent(ui.item[$(this).attr("ui_item")]), ""]};
            //sp_search_query = $.toJSON(sp_search_query);
            //sp_element.attr("search_query", sp_search_query);
            //ar_referencewidget_lookups(sp_element);
            // Template gets removed, as it no longer matches the SampleType.
			unsetTemplate(column);
			// Discover if we have a Specification linked to the SampleType
			set_Specification_from_SampleType(column);
			// Fix filter for Specs to exclude Spec with non matching sample type
			modify_Specification_field_filter(column);
			// Fix the spec values to reflect the new specification ranges
			set_specs(column);
			calculate_parts(column);
		}
        if(fieldName == "SamplePoint"){
            // selecting a Samplepoint - jiggle the SampleType element.
            var st_element = $("#ar_"+column+"_SampleType");
            st_element
                .removeClass( "cg-autocomplete-input" )
                .removeAttr( "autocomplete" )
                .removeAttr( "role" )
                .removeAttr( "aria-autocomplete" )
                .removeAttr( "aria-haspopup" );
            var new_st_element = $(st_element[0]).clone();
            var st_parent_node = $(st_element).parent();
            $(st_element).remove();
            $(st_parent_node).append(new_st_element);
            st_element = $("#ar_"+column+"_SampleType");
            // cut kwargs into the base_query
//            var st_base_query = $(st_element).attr("base_query");
//            st_base_query = $.parseJSON(st_base_query);
//            st_base_query = $.toJSON(st_base_query);
            var st_search_query = {"getRawSamplePoints": $(this).attr("uid")};
            st_search_query = $.toJSON(st_search_query);
            st_element.attr("search_query", st_search_query);
            ar_referencewidget_lookups(st_element);
        }

        // Selected a Profile
        if(fieldName == "Profile"){
            unsetTemplate(column);
            setAnalysisProfile(column, $(this).val());
            calculate_parts(column);
			reset_spec_fields(column);
			set_specs()
		}

        // Selected a Template
        if(fieldName == "Template"){
            setTemplate(column, $(this).val());
			reset_spec_fields(column);
			set_specs(column);
		}

        // Selected a sample to create a secondary AR.
        if(fieldName == "Sample"){
            // var e = $("input[name^='ar\\."+column+"\\."+fieldName+"']");
            // var Sample = $("input[name^='ar\\."+column+"\\."+fieldName+"']").val();
            // var Sample_uid = $("input[name^='ar\\."+column+"\\."+fieldName+"_uid']").val();
            // Install the handler which will undo the changes I am about to make
            $(this).blur(function(){
                if($(this).val() === ""){
                    // clear and un-disable everything
                    var disabled_elements = $("[ar_add_column_widget] [id*='ar_"+column+"']:disabled");
                    $.each(disabled_elements, function(x,disabled_element){
                        $(disabled_element).prop("disabled", false);
                        if($(disabled_element).attr("type") == "checkbox"){
                            $(disabled_element).prop("checked", false);
                        } else {
                            $(disabled_element).val("");
                        }
                    });
                }
            });
            // Then populate and disable sample fields
            $.getJSON(window.location.href.replace("/ar_add","") + "/secondary_ar_sample_info",
                {
                    "Sample_uid": $(this).attr("uid"),
                    "_authenticator": $("input[name='_authenticator']").val()},
                function(data){
                    for (var x = data.length - 1; x >= 0; x--) {
                        var fieldname = data[x][0];
                        var fieldvalue = data[x][1];
                        var uid_element = $("#ar_"+column+"_"+fieldname+"_uid");
                        $(uid_element).val("");
                        var sample_element = $("#ar_"+column+"_"+fieldname);
                        $(sample_element).val("").prop("disabled", true);
                        if($(sample_element).attr("type") == "checkbox" && fieldvalue){
                            $(sample_element).prop("checked", true);
                        } else {
                            $(sample_element).val(fieldvalue);
                        }
                    }
                }
            );
        }

        // Selected a Specification
        if(fieldName == "Specification"){
			reset_spec_fields(column);
			set_specs(column);
		}

        // Triggers 'selected' event (as reference widget)
        $(this).trigger("selected", ui.item.UID);
    }

    function add_path_filter_to_spec_lookups(){
        for (var col=0; col<parseInt($("#col_count").val(), 10); col++) {
            var element = $("#ar_"+col+"_Specification");
            var bq = $.parseJSON($(element).attr("base_query"));
            bq.path = [$("#bika_setup").attr("bika_analysisspecs_path"),
                       $("#PhysicalPath").attr("here")];
            $(element).attr("base_query", $.toJSON(bq));
        }
    }

    // we do the referencewidget_lookups differently to the widget default.
    // We also include a bunch of ar_add specific on-change stuff, since the
    // popup widget takes over the .change event completely.
    function ar_referencewidget_lookups(elements){
        add_path_filter_to_spec_lookups();
        var inputs;
        if(elements === undefined){
            inputs = $("input.referencewidget").not(".has_combogrid_widget");
        } else {
            inputs = elements;
        }
        for (var i = inputs.length - 1; i >= 0; i--) {
            var element = inputs[i];
            var options = $.parseJSON($(element).attr("combogrid_options"));
            if(options === "" || options === undefined){
                continue;
            }
            options.select = ar_referencewidget_select_handler;

            if(window.location.href.search("ar_add") > -1){
                options.url = window.location.href.split("/ar_add")[0] + "/" + options.url;
            }
            options.url = options.url + "?_authenticator=" + $("input[name='_authenticator']").val();
            options.url = options.url + "&catalog_name=" + $(element).attr("catalog_name");
            options.url = options.url + "&base_query=" + $(element).attr("base_query");
            options.url = options.url + "&search_query=" + $(element).attr("search_query");
            options.url = options.url + "&colModel=" + $.toJSON( $.parseJSON($(element).attr("combogrid_options")).colModel);
            options.url = options.url + "&search_fields=" + $.toJSON($.parseJSON($(element).attr("combogrid_options")).search_fields);
            options.url = options.url + "&discard_empty=" + $.toJSON($.parseJSON($(element).attr("combogrid_options")).discard_empty);
            $(element).combogrid(options);
            $(element).addClass("has_combogrid_widget");
            $(element).attr("search_query", "{}");
        }
    }

    function recalc_prices(column){
        if(column){
            // recalculate just this column
            var subtotal = 0.00;
            var discount_amount = 0.00;
            var vat = 0.00;
            var total = 0.00;
            var discount = parseFloat($("#member_discount").val());
            $.each($("input[name='ar."+column+".Analyses:list:ignore_empty:record']"), function(){
                var disabled = $(this).prop("disabled");
                // For some browsers, `attr` is undefined; for others, its false.  Check for both.
                if (typeof disabled !== "undefined" && disabled !== false) {
                    disabled = true;
                } else {
                    disabled = false;
                }
                if(!(disabled) && $(this).prop("checked")){
                    var serviceUID = this.id;
                    var form_price = parseFloat($("#"+serviceUID+"_price").val());
                    var vat_amount = parseFloat($("#"+serviceUID+"_price").attr("vat_amount"));
                    var price;
                    if(discount){
                        price = form_price - ((form_price / 100) * discount);
                    } else {
                        price = form_price;
                    }
                    subtotal += price;
                    discount_amount += ((form_price / 100) * discount);
                    vat += ((price / 100) * vat_amount);
                    total += price + ((price / 100) * vat_amount);
                }
            });
            $("#ar_"+column+"_subtotal").val(subtotal.toFixed(2));
            $("#ar_"+column+"_subtotal_display").val(subtotal.toFixed(2));
            $("#ar_"+column+"_discount").val(discount_amount.toFixed(2));
            $("#ar_"+column+"_vat").val(vat.toFixed(2));
            $("#ar_"+column+"_vat_display").val(vat.toFixed(2));
            $("#ar_"+column+"_total").val(total.toFixed(2));
            $("#ar_"+column+"_total_display").val(total.toFixed(2));
        } else {
            // recalculate the entire form
            for (var col=0; col<parseInt($("#col_count").val(), 10); col++) {
                recalc_prices(String(col));
            }
        }
    }

    function changeReportDryMatter(){
        /*jshint validthis:true */
        var dm = $("#getDryMatterService");
        var uid = $(dm).val();
        var cat = $(dm).attr("cat");
        var poc = $(dm).attr("poc");
        var column = $(this).parents("td").attr("column");
        if ($(this).prop("checked")){
            // only play with service checkboxes when enabling dry matter
            unsetAnalysisProfile(column);
            $.ajaxSetup({async:false});
            toggleCat(poc, cat, column, [uid], true);
            $.ajaxSetup({async:true});
            var dryservice_cb = $("input[column='"+column+"']:checkbox").filter("#"+uid);
            $(dryservice_cb).prop("checked",true);
            calcdependencies([$(dryservice_cb)], true);
            calculate_parts(column);
        }
        recalc_prices();
    }

    function copy_service(copybutton){
        var e = $("input[column='0']").filter("#" + copybutton.id);
        var kw = $(e).attr("keyword");
        var service_uid = $(e).prop("value");
        // get column 0 values
        var first_val = $(e).prop("checked");
        var first_min = $("[name='ar.0.min." + service_uid + "']").prop("value");
        var first_max = $("[name='ar.0.max." + service_uid + "']").prop("value");
        var first_error = $("[name='ar.0.error." + service_uid + "']").prop("value");

        var col_count = parseInt($("#col_count").val(), 10);
        var affected_elements = [];
        // 0 is the first column; we only want to change cols 1 onward.
        for (var column = 1; column < col_count; column++) {
            unsetTemplate(column);
            unsetAnalysisProfile(column);
            var other_elem = $("input[column='" + column + "']").filter("#" + copybutton.id);
            if ((!other_elem.prop("disabled")) && (other_elem.prop("checked") != first_val)) {
                other_elem.prop("checked", first_val ? true : false);
                toggle_spec_fields(other_elem);
                affected_elements.push(other_elem);
            }
            if (first_val) {
                $(".spec_bit.min[column='" + column + "']").filter("[keyword='" + kw + "']")
                    .prop("value", first_min);
                $(".spec_bit.max[column='" + column + "']").filter("[keyword='" + kw + "']")
                    .prop("value", first_max);
                $(".spec_bit.error[column='" + column + "']").filter("[keyword='" + kw + "']")
                    .prop("value", first_error);
            }
            calculate_parts(column);
        }
        calcdependencies(affected_elements, true);
        recalc_prices();
    }

    function copy_checkbox(copybutton){
        var fieldName = $(copybutton).attr("name");
        var first_val = $("input[name^='ar\\.0\\."+fieldName+"']").prop("checked");
      var col_count = parseInt($("#col_count").val(), 10);
        // col starts at 1 here; we don't copy into the the first row
        for (var col=1; col<col_count; col++) {
            var other_elem = $("#ar_" + col + "_" + fieldName);
            if ((other_elem.prop("checked")!=first_val)) {
                other_elem.prop("checked",first_val?true:false);
                other_elem.trigger("change");
            }
        }
        $("[id*='_" + fieldName + "']").change();
    }

    function copyButton(){
        /*jshint validthis:true */
        var fieldName = $(this).attr("name");
      var col_count = parseInt($("#col_count").val(), 10);

        if ($(this).parent().attr("class") == "service"){
            copy_service(this);
        }

        else if ($("input[name^='ar\\.0\\."+fieldName+"']").attr("type") == "checkbox") {
            copy_checkbox(this);
        }

        // Anything else

        else{
            var first_val = $("input[name^='ar\\.0\\."+fieldName+"']").filter("[type=text]").val();
            // Reference fields have a hidden *_uid field
            var first_uid = $("input[name^='ar\\.0\\."+fieldName+"_uid']").val();
            // multi-valued fields: selection is in {fieldname}-listing
            var first_multi_html = $("div[name^='ar\\.0\\."+fieldName+"-listing']").html();
            // col starts at 1 here; we don't copy into the the first row
            for (var col=1; col<col_count; col++) {
                var other_uid_elem = $("#ar_" + col + "_" + fieldName + "_uid");
                if (first_uid !== undefined && first_uid !== null){
                    other_uid_elem.val(first_uid);
                }
                var other_multi_div = $("div[name^='ar\\."+col+"\\."+fieldName+"-listing']");
                if (first_multi_html !== undefined && first_multi_html !== null){
                    other_multi_div.html(first_multi_html.replace(".0.", "."+col+"."));
                }
                // Actual field value
                var other_elem = $("#ar_" + col + "_" + fieldName);
                if (!(other_elem.prop("disabled"))) {
                    $(other_elem).attr("skip_referencewidget_lookup", true);
                    other_elem.val(first_val);
                    other_elem.trigger("change");

                    if(fieldName == "Contact") {
                        set_cc_contacts(col);
                    }

                    if(fieldName == "Profile"){
                        unsetTemplate(col);
                        setAnalysisProfile(col, first_val);
                        calculate_parts(col);
                    }

                    if(fieldName == "Template"){
                        setTemplate(col, first_val);
                    }

                    if(fieldName == "SampleType"){
                        unsetTemplate(col);
                        calculate_parts(col);
						set_specs(col);
					}

                    if(fieldName == "Specification"){
						set_specs(col);
						reset_spec_fields(column);
					}

                }
            }
            //$('[id*=_' + fieldName + "]").change();
        }
    }



    function toggleCat(poc, category_uid, column, selectedservices, force_expand, disable) {
        // selectedservices and column are optional.
        // disable is used for field analyses - secondary ARs should not be able
        // to select these
        force_expand = force_expand || false;
        disable = disable || -1;
        if(!column && column !== 0) { column = ""; }

        var th = $("th[poc='"+poc+"']").filter("[cat='"+category_uid+"']");
        var tbody = $("#"+poc+"_"+category_uid);

        if($(tbody).hasClass("expanded")){
            // displaying an already expanded category:
            if(selectedservices){
                var rows = tbody.children();
                for(var i = 0; i < rows.length; i++){
                    var service = rows[i];
                    var service_uid = $(service).attr("id");
                    if(selectedservices.indexOf(service_uid) > -1){
                        var cb = $("input[value="+service_uid+"]").filter("[column='"+column+"']");
                        $(cb).prop("checked",true);
                        toggle_spec_fields(cb);
					}
                }
                recalc_prices(column);
            } else {
                if (force_expand){ $(tbody).toggle(true); }
                else { $(tbody).toggle(); }
            }
        } else {
            if(!selectedservices) selectedservices = [];
            $(tbody).removeClass("collapsed").addClass("expanded");
            var options = {
                "selectedservices": selectedservices.join(","),
                "categoryUID": category_uid,
                "column": column,
                "disable": disable > -1 ? column : -1,
                "col_count": $("#col_count").attr("value"),
                "poc": poc
            };
            // possibly remove the fake ar context
            var url = window.location.href.split("/ar_add")[0] + "/analysisrequest_analysisservices";
            $(tbody).load(url, options, function(){
                // analysis service checkboxes
                $("input[name*='Analyses']").unbind();
                $("input[name*='Analyses']").bind("change", service_checkbox_change);
                if(selectedservices!=[]){
                    recalc_prices(column);
                    for(i=0;i<selectedservices.length;i++){
                        var service_uid = selectedservices[i];
                        var e = $("input[value=" + service_uid + "]").filter("[column='" + column + "']");
                        toggle_spec_fields(e);
					}
                }
            });
        }
    }

    function calc_parts_handler(column, data){
        // Set new part numbers in hidden form field
        var formparts = $.parseJSON($("#parts").val());
        var parts = data.parts;
        formparts[column] = parts;
        $("#parts").val($.toJSON(formparts));
        // write new part numbers next to checkboxes
        for(var p in parts) { if(!parts.hasOwnProperty(p)){ continue; }
            for (var s in parts[p].services) {
                if (!parts[p].services.hasOwnProperty(s)) { continue; }
                $(".partnr_"+parts[p].services[s]).filter("[column='"+column+"']").empty().append(p+1);
            }
        }
    }

    function calculate_parts(column) {
        // Template columns are not calculated
        if ($("#ar_"+column+"_Template").val() !== ""){
            return;
        }
        var st_uid = $("#ar_"+column+"_SampleType_uid").val();
        var checked = $("[name^='ar\\."+column+"\\.Analyses']").filter(":checked");
        var service_uids = [];
        for(var i=0;i<checked.length;i++){
            var uid = $(checked[i]).attr("value");
            service_uids.push(uid);
        }
        // if no sampletype or no selected analyses:  remove partition markers
        if (st_uid === "" || service_uids.length === 0) {
            $("[class*='partnr_']").filter("[column='"+column+"']").empty();
            return;
        }
        var request_data = {
                services: service_uids.join(","),
                sampletype: st_uid,
                _authenticator: $("input[name='_authenticator']").val()
        };
        window.jsonapi_cache = window.jsonapi_cache || {};
        var cacheKey = $.param(request_data);
        if (typeof window.jsonapi_cache[cacheKey] === "undefined") {
            $.ajax({
                type: "POST",
                dataType: "json",
                url: window.portal_url + "/@@API/calculate_partitions",
                data: request_data,
                success: function(data) {
                    // Check if calculation succeeded
                    if (data.success == false) {
                        alert('Error while calculating partitions: ' + data.message);
                    } else {
                        window.jsonapi_cache[cacheKey] = data;
                        calc_parts_handler(column, data);
                    }
                }
            });
        } else {
            var data = window.jsonapi_cache[cacheKey];
            calc_parts_handler(column, data);
        }
    }

    function add_Yes(dlg, element, dep_services){
        /*jshint validthis:true */
        var column = $(element).attr("column");
        var key, json_key, dep, i;
        var keyed_deps = {};
        for(i = 0; i<dep_services.length; i++){
            dep = dep_services[i];
            key = {
                col: column,
                poc: dep.PointOfCapture,
                cat_uid: dep.Category_uid
            };
            json_key = $.toJSON(key);
            if(!keyed_deps[json_key]){
                keyed_deps[json_key] = [];
            }
            keyed_deps[json_key].push(dep.Service_uid);
        }

        var modified_cols = [];
        for(json_key in keyed_deps){
            if (!keyed_deps.hasOwnProperty(json_key)){ continue; }
            key = $.parseJSON(json_key);
            if(!modified_cols[key.col]){
                modified_cols.push(key.col);
            }
            var service_uids = keyed_deps[json_key];
            var tbody = $("#"+key.poc+"_"+key.cat_uid);
            if($(tbody).hasClass("expanded")) {
                // if cat is already expanded, manually select service checkboxes
                $(tbody).toggle(true);
                for(i=0; i<service_uids.length; i++){
                    var service_uid = service_uids[i];
                    var e = $("input[column='"+key.col+"']").filter("#"+service_uid);
                    $(e).prop("checked",true);
                    toggle_spec_fields(e);
				}
            } else {
                // otherwise, toggleCat will take care of everything for us
                $.ajaxSetup({async:false});
                toggleCat(key.poc, key.cat_uid, key.col, service_uids);
                $.ajaxSetup({async:true});
            }
        }
        recalc_prices();
        for(i=0; i<modified_cols.length; i+=1){
            calculate_parts(modified_cols[i]);
        }
        $(dlg).dialog("close");
        $("#messagebox").remove();


    }

    function add_No(dlg, element){
        /*jshint validthis:true */
        $(element).prop("checked",false);
        $(dlg).dialog("close");
        $("#messagebox").remove();
    }

    function calcdependencies(elements, auto_yes) {
        /*jshint validthis:true */
        auto_yes = auto_yes || false;
        jarn.i18n.loadCatalog('bika');
        var _ = window.jarn.i18n.MessageFactory("bika");

        var dep;
        var dep_i, cb;

        var lims = window.bika.lims;

        for(var elements_i = 0; elements_i < elements.length; elements_i++){
            var dep_services = [];  // actionable services
            var dep_titles = [];
            var element = elements[elements_i];
            var column = $(element).attr("column");
            var service_uid = $(element).attr("id");
            var modified_cols = [];
            // selecting a service; discover dependencies
            if ($(element).prop("checked")){
                var Dependencies = lims.AnalysisService.Dependencies(service_uid);
                for(dep_i = 0; dep_i<Dependencies.length; dep_i++) {
                    dep = Dependencies[dep_i];
                    if ($("input[column='"+column+"']").filter("#"+dep.Service_uid).prop("checked")){
                        continue; // skip if checked already
                    }
                    dep_services.push(dep);
                    dep_titles.push(dep.Service);
                }

                if (dep_services.length > 0) {
                    if(!modified_cols[column]){
                        modified_cols.push(column);
                    }
                    if (auto_yes) {
                        add_Yes(this, element, dep_services);
                    } else {
                        var html = "<div id='messagebox' style='display:none' title='" + _("Service dependencies") + "'>";
                        html = html + _("<p>${service} requires the following services to be selected:</p>"+
                                                        "<br/><p>${deps}</p><br/><p>Do you want to apply these selections now?</p>",
                                                        {
                                                            service: $(element).attr("title"),
                                                            deps: dep_titles.join("<br/>")
                                                        });
                        html = html + "</div>";
                        $("body").append(html);
                        $("#messagebox").dialog({
                            width:450,
                            resizable:false,
                            closeOnEscape: false,
                            buttons:{
                                yes: function(){
                                    add_Yes(this, element, dep_services);
                                },
                                no: function(){
                                    add_No(this, element);
                                }
                            }
                        });
                    }
                }
            }
            // unselecting a service; discover back dependencies
            else {
                var Dependants = lims.AnalysisService.Dependants(service_uid);
                if (Dependants.length > 0){
                    for (i=0; i<Dependants.length; i++){
                        dep = Dependants[i];
                        cb = $("input[column='"+column+"']").filter("#"+dep.Service_uid);
                        if (cb.prop("checked")){
                            dep_titles.push(dep.Service);
                            dep_services.push(dep);
                        }
                    }
                    if(dep_services.length > 0){
                        if (auto_yes) {
                            for(dep_i=0; dep_i<dep_services.length; dep_i+=1) {
                                dep = dep_services[dep_i];
                                service_uid = dep.Service_uid;
                                cb = $("input[column='"+column+"']").filter("#"+service_uid);
                                $(cb).prop("checked", false);
                                toggle_spec_fields($(cb));
								$(".partnr_"+service_uid).filter("[column='"+column+"']").empty();
                                if ($(cb).val() == $("#getDryMatterService").val()) {
                                    $("#ar_"+column+"_ReportDryMatter").prop("checked",false);
                                }
                            }
                        } else {
                            $("body").append(
                                "<div id='messagebox' style='display:none' title='" + _("Service dependencies") + "'>"+
                                _("<p>The following services depend on ${service}, and will be unselected if you continue:</p><br/><p>${deps}</p><br/><p>Do you want to remove these selections now?</p>",
                                    {service:$(element).attr("title"),
                                    deps: dep_titles.join("<br/>")})+"</div>");
                            $("#messagebox").dialog({
                                width:450,
                                resizable:false,
                                closeOnEscape: false,
                                buttons:{
                                    Yes: function(){
                                        for(dep_i=0; dep_i<dep_services.length; dep_i+=1) {
                                            dep = dep_services[dep_i];
                                            service_uid = dep.Service_uid;
                                            cb = $("input[column='"+column+"']").filter("#"+service_uid);
                                            $(cb).prop("checked", false);
                                            toggle_spec_fields($(cb));
											$(".partnr_"+service_uid).filter("[column='"+column+"']").empty();
                                            if ($(cb).val() == $("#getDryMatterService").val()) {
                                                $("#ar_"+column+"_ReportDryMatter").prop("checked",false);
                                            }
                                        }
                                        $(this).dialog("close");
                                        $("#messagebox").remove();
                                    },
                                    No:function(){
                                        $(element).prop("checked",true);
                                        toggle_spec_fields($(element));
										$(this).dialog("close");
                                        $("#messagebox").remove();
                                    }
                                }
                            });
                        }
                    }
                }
            }
            recalc_prices();
            for(var i=0; i<modified_cols.length; i+=1){
                calculate_parts(modified_cols[i]);
            }
        }
    }

    function unsetAnalyses(column){
        $.each($("input[name^='ar."+column+".Analyses']"), function(){
            if($(this).prop("checked")) {
                $(this).prop("checked",false);
                toggle_spec_fields($(this));
            }
            $(".partnr_"+this.id).filter("[column='"+column+"']").empty();
        });
    }
    // function uncheck_partnrs(column){
    //  // all unchecked services have their part numbers removed
    //  var ep = $("[class^='partnr_']").filter("[column='"+column+"']").not(":empty");
    //  for(var i=0;i<ep.length;i++){
    //      var em = ep[i];
    //      var uid = $(ep[0]).attr("class").split("_")[1];
    //      var cb = $("#"+uid);
    //      if ( ! $(cb).prop("checked") ){
    //          $(em).empty();
    //      }
    //  }
    // }

    function unsetAnalysisProfile(column){
        if($("#ar_"+column+"_Profile").val() !== ""){
            $("#ar_"+column+"_Profile").val("");
        }
    }


    function unsetTemplate(column){
        if($("#ar_"+column+"_Template").val() !== ""){
            $("#ar_"+column+"_Template_uid").val("");
        }
    }


    function setTemplate(column, template_title){
        unsetAnalyses(column);
        var request_data = {
            portal_type: "ARTemplate",
            title: template_title,
            include_fields: [
                "SampleType",
                "SampleTypeUID",
                "SamplePoint",
                "SamplePointUID",
                "ReportDryMatter",
                "AnalysisProfile",
                "Partitions",
                "Analyses"]
        };
        window.bika.lims.jsonapi_read(request_data, function(data){
            var template = data.objects[0];
            var request_data, x, i;
            // set our template fields
            $("#ar_"+column+"_SampleType").val(template.SampleType)
            $("#ar_"+column+"_SampleType_uid").val(template.SampleTypeUID)
			set_Specification_from_SampleType(column)
            $("#ar_"+column+"_SamplePoint").val(template.SamplePoint)
            $("#ar_"+column+"_SamplePoint_uid").val(template.SamplePointUID)
            $("#ar_"+column+"_reportdrymatter").prop("checked", template.reportdrymatter)

            // lookup AnalysisProfile
            if(template.AnalysisProfile) {
                request_data = {
                    portal_type: "AnalysisProfile",
                    title: template.AnalysisProfile,
                    include_fields: ["UID"]
                };
                window.bika.lims.jsonapi_read(request_data, function(data){
                    $("#ar_"+column+"_Profile").val(template.AnalysisProfile);
                    $("#ar_"+column+"_Profile_uid").val(data.objects[0].UID);
                });
            } else {
                    $("#ar_"+column+"_Profile").val("");
                    $("#ar_"+column+"_Profile_uid").val("");
            }

            // scurrel the parts into hashes for easier lookup
            var parts_by_part_id = {};
            var parts_by_service_uid = {};
            for (x in template.Partitions) {
                if (!template.Partitions.hasOwnProperty(x)){ continue; }
                var P = template.Partitions[x];
                P.part_nr = parseInt(P.part_id.split("-")[1], 10);
                P.services = [];
                parts_by_part_id[P.part_id] = P;
            }
            for (x in template.Analyses) {
                if(!template.Analyses.hasOwnProperty(x)){ continue; }
                i = template.Analyses[x];
                parts_by_part_id[i.partition].services.push(i.service_uid);
                parts_by_service_uid[i.service_uid] = parts_by_part_id[i.partition];
            }
            // this one goes through with the form submit
            var parts = [];
            for(x in parts_by_part_id){
                if(!parts_by_part_id.hasOwnProperty(x)){ continue; }
                parts.push(parts_by_part_id[x]);
            }
            var formparts = $.parseJSON($("#parts").val());
            formparts[column] = parts;
            $("#parts").val($.toJSON(formparts));

            // lookup the services specified in the template
            request_data = {
                portal_type: "AnalysisService",
                UID: [],
                include_fields: ["PointOfCapture", "CategoryUID", "UID"]
            };
            for (x in template.Analyses) {
                if (!template.Analyses.hasOwnProperty(x)){ continue; }
                request_data.UID.push(template.Analyses[x].service_uid);
            }
            // save services in hash for easier lookup this
            window.bika.lims.jsonapi_read(request_data, function(data) {
                var e;
                var poc_cat_services = {};
                for(var x in data.objects) {
                    if(!data.objects.hasOwnProperty(x)){ continue; }
                    var service = data.objects[x];
                    var poc_title = service.PointOfCapture;
                    if (!(poc_title in poc_cat_services)) {
                        poc_cat_services[poc_title] = {};
                    }
                    if (!(service.CategoryUID in poc_cat_services[poc_title])) {
                        poc_cat_services[poc_title][service.CategoryUID] = [];
                    }
                    poc_cat_services[poc_title][service.CategoryUID].push(service.UID);
                }
                // expand categories, select, and enable controls for template services
                for (var p in poc_cat_services) {
                    if (!poc_cat_services.hasOwnProperty(p)){ continue; }
                    var poc = poc_cat_services[p];
                    for (var cat_uid in poc) {
                        if (!poc.hasOwnProperty(cat_uid)) {continue; }
                        var service_uids = poc[cat_uid];
                        var tbody = $("tbody[id='"+p+"_"+cat_uid+"']");
                        var service_uid;
                        // expand category
                        if(!($(tbody).hasClass("expanded"))) {
                            $.ajaxSetup({async:false});
                            toggleCat(p, cat_uid, 0);
                            $.ajaxSetup({async:true});
                        }
                        $(tbody).toggle(true);
                        // select checkboxes
                        for(i=0;i<service_uids.length;i++){
                            service_uid = service_uids[i];
                            e = $("input[column='"+column+"']").filter("#"+service_uid);
                            $(e).prop("checked", true);
                            toggle_spec_fields(e);
                        }
                        // set part number indicators
                        for(i=0;i<service_uids.length;i++){
                            service_uid = service_uids[i];
                            var partnr = parseInt(parts_by_service_uid[service_uid].part_nr, 10);
                            e = $(".partnr_"+service_uid).filter("[column='"+column+"']");
                            $(e).empty().append(partnr);
                        }
                        recalc_prices(column);
                    }
                }
            });
        });

        recalc_prices(column);

    }

    function setAnalysisProfile(column, profile_title){
        var request_data = {
            portal_type: "AnalysisProfile",
            title: profile_title
        };
        window.bika.lims.jsonapi_read(request_data, function(data){
            var profile_objects = data.objects;
            var request_data = {
                portal_type: "AnalysisService",
                title: profile_objects[0].Service,
                include_fields: ["PointOfCapture", "Category", "UID", "title"]
            };
            window.bika.lims.jsonapi_read(request_data, function(data){
                var i;
                unsetAnalyses(column);
                $("#ar_"+column+"_ReportDryMatter").prop("checked",false);

                var service_objects = data.objects;
                if (service_objects.length === 0) return;
                var categorised_services = {};
                for (i in service_objects){
                    var key = service_objects[i].PointOfCapture + "_" +
                        service_objects[i].Category;
                    if(categorised_services[key] === undefined)
                        categorised_services[key] = [];
                    categorised_services[key].push(service_objects[i]);
                }

                for (var poc_cat in categorised_services) {
                    var services = categorised_services[poc_cat];
                    var th = $("th#cat_"+poc_cat);
                    if($(th).hasClass("expanded")){
                        for (i in services){
                            var service_uid = services[i].UID;
                            var e = $("input[column='"+column+"']").filter("#"+service_uid);
                            $(e).prop("checked", true);
                        }
                        recalc_prices(column);
                    } else {
                        var poc = poc_cat.split("_")[0];
                        var cat_uid = services[0].Category_uid;
                        var service_uids = [];
                        for(var x = 0; x<services.length;x++){
                            service_uids.push(services[x].UID);
                        }
                        $.ajaxSetup({async:false});
                        toggleCat(poc, cat_uid, column, service_uids);
                        $.ajaxSetup({async:true});
                    }
                    $(th).removeClass("collapsed").addClass("expanded");
                }
                calculate_parts(column);
            });
        });
    }

    function service_checkbox_change(){
        /*jshint validthis:true */
        var column = $(this).attr("column");
        var element = $(this);
        unsetAnalysisProfile(column);
        unsetTemplate(column);

        // Unselecting Dry Matter Service unsets 'Report Dry Matter'
        if ($(this).val() == $("#getDryMatterService").val() && !$(this).prop("checked")) {
            $("#ar_"+column+"_ReportDryMatter").prop("checked",false);
        }

        // unselecting service: remove part number.
        if (!$(this).prop("checked")){
            $(".partnr_"+this.id).filter("[column='"+column+"']").empty();
        }

        calcdependencies([element]);
        recalc_prices();
        calculate_parts(column);
		toggle_spec_fields(element);

    }

    function clickAnalysisCategory(){
        /*jshint validthis:true */
        // cat is a category uid, and no column is required here.
        toggleCat($(this).attr("poc"), $(this).attr("cat"));
        if($(this).hasClass("expanded")){
            $(this).addClass("collapsed");
            $(this).removeClass("expanded");
        } else {
            $(this).removeClass("collapsed");
            $(this).addClass("expanded");
        }
    }

    function applyComboFilter(element, filterkey, filtervalue) {
        // If the element is not visible it is probably not worth creating a dropdown query.
        if (!$(element).is(':visible')){
            return;
        }
        var base_query=$.parseJSON($(element).attr("base_query"));
        base_query[filterkey] = filtervalue;
        $(element).attr("base_query", $.toJSON(base_query));
        var options = $.parseJSON($(element).attr("combogrid_options"));
        options.url = window.location.href.split("/ar_add")[0] + "/" + options.url;
        options.url = options.url + "?_authenticator=" + $("input[name='_authenticator']").val();
        options.url = options.url + "&catalog_name=" + $(element).attr("catalog_name");
        options.url = options.url + "&base_query=" + $.toJSON(base_query);
        options.url = options.url + "&search_query=" + $(element).attr("search_query");
        options.url = options.url + "&colModel=" + $.toJSON( $.parseJSON($(element).attr("combogrid_options")).colModel);
        options.url = options.url + "&search_fields=" + $.toJSON($.parseJSON($(element).attr("combogrid_options")).search_fields);
        options.url = options.url + "&discard_empty=" + $.toJSON($.parseJSON($(element).attr("combogrid_options")).discard_empty);
        options.force_all="false";
        $(element).combogrid(options);
        $(element).addClass("has_combogrid_widget");
        $(element).attr("search_query", "{}");
    }

	function fill_column(data) {
		// fields which should not be completed from the source AR
		var skip_fields = ['Sample',
						   'Sample_uid',
						   'SamplingDate',
						   'DateSampled',
						   'Sampler']
		// if the jsonapi read data did not include any objects, abort
		// obviously, shouldn't happen
		if ((!data.success) || data.objects.length < 1) {
			return;
		}
		var obj = data.objects[0];
		// this is the column containing the elements we will write into
		var col = window.bika.ar_copy_from_col;
		// set field values from data into respective elements.  data does include
		// *_uid entries for reference field values, so the corrosponding *_uid
		// hidden elements are written here
		for (var fieldname in obj) {
			if (!obj.hasOwnProperty(fieldname)) { continue; }
			if (skip_fields.indexOf(fieldname) > -1) { continue; }
			var fieldvalue = obj[fieldname];
			var el = $("#ar_" + col + "_" + fieldname);
			if (el.length > 0) {
				$(el).val(fieldvalue);
			}
		}

		var services = {};
		var specs = {};
		var poc_name, cat_uid, service_uid, service_uids;
		var i, key;

		for (i = obj.Analyses.length - 1; i >= 0; i--) {
			var analysis = obj.Analyses[i];
			cat_uid = analysis.CategoryUID;
			service_uid = analysis.ServiceUID;
			key = analysis.PointOfCapture + "__" + analysis.CategoryUID;
			if (!(key in services)) {
				services[key] = [];
			}
			services[key].push(service_uid);
		}
		for (key in services) {
			if (!services.hasOwnProperty(key)) {
				continue;
			}
			poc_name = key.split("__")[0];
			cat_uid = key.split("__")[1];
			service_uids = services[key];
			window.toggleCat(poc_name, cat_uid, col, service_uids, true);
		}
	}

    function expand_default_categories() {
        $("th.prefill").click();
    }
}
