function AssistedSearchCategory(
                        category_switch_link_id,
                        container_id,
                        advanced_search_fields,
                        product_db) {
    this.category_switch_link = $(category_switch_link_id);
    this.container = $(container_id);
    this.product_db = product_db;
    this.results_link = this.container.getElement("div[class='advanced_search_results_link']");
    this.results_link_visible = false;
	this.progress_indicator = this.container.getElement("div[class='progress_indicator']");
	this.num_selected_fields = 0;
	var _this = this;
	
	// Get a reference to this category's form inputs
	this.inputs = this.container.getElements("select");
	
	// Hide our form container so that the "compare selected" button doesn't appear
    this.product_db.container.setStyle("display", "none");
	
	// Setup fade effect for this page's container
	this.fx_container_opacity = new Fx.Tween(
	    _this.container, {
		property: "opacity",
		duration: page_fade_duration,
		onStart: function() {
		    _this.container.setStyles({
	            display: "block"
	        });
		},
		onComplete: function() {
		    if (_this.container.getStyle("opacity") == 0 || _this.container.getSize().y <= 0) {
		        _this.container.setStyles({
		            display: "none"
		        });
		    }
		}
	}).set("0.0");
	
	// Setup slide effect for this page's search results link
	this.fx_results_link_slide = new Fx.Slide(this.results_link, {
		duration: 500
	}).hide();
	this.results_link.setStyle("display", "block");
	
	// Setup fade effect for this page's progress indicator
	this.fx_progress_indicator_opacity = new Fx.Tween(
	    _this.progress_indicator, {
		property: "opacity",
		duration: progress_indicator_fade_duration
	}).set("0.0");
	
	// Determine the database index values corresponding to our inputs
    this.field_keys = new Array();
    this.default_options = new Array();
    for (var i=0; i<this.inputs.length; i++) {
        var input = this.inputs[i];
        
        // Find db index for our key
        var key = input.id.substr(input.id.indexOf("_", 7) + 1);    // Strip "search_xxx_ from field id
        var key_index = this.product_db.GetDatabaseMapIndexForField(key);
        
        // This shouldn't happen
//        if (key_index == -1)
//            return;
        
        // Add value to our array
        this.field_keys.push(key_index);
        
        // Setup seletion change events on all inputs
	    input.addEvent("change", function(the_event) {
	        _this.RefreshSelectContentsAndAvailability();
	    });
	    
	    // Cache the default options for this input so that we can quickly reset the interface when necessary
	    var options = new Array();
	    for (var j=0; j<input.options.length; j++)
    	    options.push(new Array(input.options[j].value, input.options[j].text));
    	
    	this.default_options.push(options);
	    
	    // Clear all field selections on load (FireFox maintains them, which we may not want)
	    input.selectedIndex = 0;
	    input.disabled = options.length <= 2;
    }
    
    // Setup field reset button
    $$("#" + container_id + " .reset_button input").addEvent("click", function(the_event) {
    	// Deselect all inputs
        for (var i=0; i<_this.inputs.length; i++)
            _this.inputs[i].selectedIndex = 0;
        
        // Refresh product list
        _this.RefreshSelectContentsAndAvailability();
    });
	
	// Setup category/page switch actions to refresh the product list
    this.category_switch_link.addEvent("click", function(the_event) {
    	// Stop if this is the category we're already on
	    if (current_page == _this)
	        return;
	    
	    // Stop if we're already in the middle of a page transition
    	if (transitioning_pages)
    		return;
    	transitioning_pages = true;
	    
	    // Remove current page indicator from all subnav buttons
		$$("#pageSubMenu li").removeClass("selected");
		
		// Set this subnav button's current page indicator
		_this.category_switch_link.addClass("selected");
	    
	    // Crossfade search fields
	    current_page.fx_container_opacity.start(0.0).chain(function() {
	        // Change dimensions of the search fields and results list to match the page we're transitioning to
	        _this.container.setStyle("display", "block");
            advanced_search_fields.setStyle("height", _this.container.getSize().y + "px");
	        _this.fx_container_opacity.start(1.0).chain(function() {
	            // Update current_page variable once all of our transitions have completed
                current_page = _this;
                
                // Update page transition flag
                setTimeout(function() {
	                transitioning_pages = false;
	            }, 200);
	        });
	    });
	    
	    // Crossfade results list
	    if (current_page.num_selected_fields > 0) {
	        current_page.product_db.fx_list_opacity.start(0.0).chain(function() {
	            if (_this.num_selected_fields > 0)
    	            _this.product_db.fx_list_opacity.start(1.0);
	        });
	    } else {
	        if (_this.num_selected_fields > 0)
    	        _this.product_db.fx_list_opacity.start(1.0);
	    }
	});
	
	this.GetCurrentFieldValues = function() {
	    // Load all selected values and determine their related indexes within our database
        var field_values = new Array();
        for (var i=0; i<this.inputs.length; i++) {
            var input = this.inputs[i];
	        
            // Find db index for the selected value
            var value = input.options[input.selectedIndex].value;
            
            // Add value to our array
            if (value == "")
                field_values.push(null);
            else
                field_values.push(parseInt(value, 10));
        }
        
        return field_values;
	};
	
	this.RefreshSelectContentsAndAvailability = function() {
	    // Make sure that the progress indicator has been displayed before doing any further processing
	    var _this = this;
        this.fx_progress_indicator_opacity.start(1.0).chain(function() {
	        // Load all selected values and determine their related indexes within our database
            var field_values = _this.GetCurrentFieldValues();
            _this.num_selected_fields = 0;
            for (var i=0; i<field_values.length; i++) {
                if (field_values[i] != null)
                    _this.num_selected_fields++;
            }
            
            if (_this.num_selected_fields == 0) {
                // Nothing was selected - Reload the cached default options
                for (var i=0; i<_this.inputs.length; i++) {
                    var input = _this.inputs[i];
                    
                    // Hide the list container & associated comparison button
                    _this.product_db.container.setStyle("display", "none");
                    
                    // Empty this input
                    $(input).empty();
                    
                    for (var j=0; j<_this.default_options[i].length; j++)
                        _this.AppendOption(input, _this.default_options[i][j][0], _this.default_options[i][j][1], j == 0);
                    
                    input.disabled = _this.default_options[i].length <= 2;
                }
            } else {
                // Show the list container & associated comparison button
                _this.product_db.container.setStyle("display", "block");
                _this.product_db.fx_list_opacity.start(1.0);
                
                // Some combination of fields were selected -
                // Reload all of our fields with the unique data referenced by our matched products
                for (var i=0; i<_this.inputs.length; i++) {
                    var input = _this.inputs[i];
                    var unique_values = new Array();
                    
                    // If we couldn't map this field to the database, skip it
	                if (_this.field_keys[i] == -1)
	                    continue;
                    
                    var selected_value = input.options[input.selectedIndex].value;
                    if (selected_value == "")
                        selected_value = null;
                    else
                        selected_value = parseInt(selected_value, 10);
        	        
                    // Load all unique matches, ignoring this field so that all valid options will be listed
                    var matches = _this.product_db.FindMatches(_this.field_keys, field_values, _this.field_keys[i]);
                    
                    for (var j=0; j<matches.length; j++) {
                        var product_value = _this.product_db.db.map[matches[j]][_this.field_keys[i]];
                        var found = false;
                        
                        // "-1" values are used for fields that could not be mapped to a
                        // database item or custom span - don't add these to our unique value array
                        if (product_value == -1)
                            continue;
        	            
                        // Locate this value in our unique value array
                        for (var k=0; k<unique_values.length; k++) {
                            if (unique_values[k] == product_value) {
                                found = true;
                                break;
                            }
                        }
        	            
                        // Add to array if not already present
                        if (!found)
	                        unique_values.push(product_value);
                    }
        	        
                    // Sort the unique value array
                    unique_values.sort(function(a, b) {
                        return a - b;
                    });
        	        
                    // Empty this input
                    $(input).empty();
        	        
                    // Append default "Any" option
                    _this.AppendOption(input, "", "Any", selected_value == null);
        	        
                    for (var j=0; j<unique_values.length; j++) {
                        var text = _this.product_db.db.db[_this.field_keys[i]][unique_values[j]];
                        _this.AppendOption(input, unique_values[j], text, selected_value == unique_values[j]);
                    }
                    
                    input.disabled = unique_values.length <= 1;
                }
            }
            
	        // Fade out product list
            _this.product_db.HideList(function() {
	            // Don't display anything if no fields have been selected
                if (_this.num_selected_fields > 0) {
                    _this.product_db.RecreateListContents(_this.field_keys, field_values);
                    
                    // Show results link if it's not visible
                    if (!_this.results_link_visible) {
                    	_this.results_link_visible = true;
                    	advanced_search_fields.setStyle("height", (advanced_search_fields.getSize().y + _this.results_link.getSize().y) + "px");
                    	_this.fx_results_link_slide.slideIn();
                    }
                } else {
                    _this.product_db.list.empty();
                    
                    // Hide results link if it's visible
                    if (_this.results_link_visible) {
                    	_this.results_link_visible = false;
                    	advanced_search_fields.setStyle("height", (advanced_search_fields.getSize().y - _this.results_link.getSize().y) + "px");
                    	_this.fx_results_link_slide.slideOut();
                    }
                }
                
                // Fade list back in now that it's been repopulated with data
                _this.product_db.ShowList(function() {
                	// Hide progress indicator
			        if (parseFloat(_this.progress_indicator.style.opacity) > 0)
		                _this.fx_progress_indicator_opacity.start(0.0);
                });
	        });
	    });
	};
	
	this.AppendOption = function(input, value, text, selected) {
        var option = document.createElement("option");
        option.value = value;
        option.appendChild(document.createTextNode(text));
        if (selected)
            option.selected = true;
        input.appendChild(option);
	};
}

window.addEvent('domready', function() {
    var container = $("product_table_container");
    
    var advanced_search_fields = $("advanced_search_fields");
	advanced_search_fields.setStyle("height", "0px");
    
    // Show items that are hidden by default for users who don't have JavaScript enabled
    $$(".hideIfJavaScriptDisabled").setStyle("display", "block");
    
	// Setup all of our product search pages
	var product_db = new ProductDatabase(
		pumps,
		"list_container_pumps",
		false,
        new Array(
	        new Array("Part Number", "carow_part_number"),
	        new Array("Product Name", "category_name"),
	        new Array("Color", "color"),
	        new Array("Output cc", "output_cc"),
	        new Array("Output oz", "output_oz"),
	        new Array("Cap Diameter", "cap_diameter"),
	        new Array("Cap Height", "cap_h"),
	        new Array("Minimum", "minimum")),
	    new Array(
	        new Array("Note", "note"),
	        new Array("Typical Lead Time", "typical_lead_time"),
	        new Array("Minimum for Color and Typical Lead Time", "minimum_for_color_and_typi"),
	        new Array("Texture", "cap_texture"),
	        new Array("Location", "location"))
	);
	var category_pumps = new AssistedSearchCategory(
	    "category_button_pumps",
	    "search_container_pumps",
	    advanced_search_fields,
	    product_db
	);
	
	var product_db = new ProductDatabase(
		caps,
		"list_container_caps",
		false,
	    new Array(
	        new Array("Part Number", "carow_part_number"),
	        new Array("Product Name", "category_name"),
	        new Array("Color", "color"),
	        new Array("Cap Diameter", "cap_diameter"),
	        new Array("Cap Height", "cap_h"),
	        new Array("Texture", "cap_texture"),
	        new Array("Minimum", "minimum"),
	        new Array("Location", "location")),
	    new Array(
	        new Array("Note", "note"),
	        new Array("Typical Lead Time", "typical_lead_time"),
	        new Array("Minimum for Color and Typical Lead Time", "minimum_for_color_and_typic"),
	        new Array("Primary Market", "primary_market"))
	);
	var category_caps = new AssistedSearchCategory(
	    "category_button_caps",
	    "search_container_caps",
	    advanced_search_fields,
	    product_db
	);
	
	var product_db = new ProductDatabase(
		containers,
		"list_container_containers",
		false,
	    new Array(
	        new Array("Part Number", "carow_part_number"),
	        new Array("Product Name", "category_name"),
	        new Array("Color", "color"),
	        new Array("Capacity cc", "capacity_cc"),
	        new Array("Capacity oz", "capacity_oz"),
	        new Array("Neck Diameter", "neck_diameter"),
	        new Array("Neck Height", "neck_h"),
	        new Array("Minimum", "minimum")),
	    new Array(
	        new Array("Note", "note"),
	        new Array("Typical Lead Time", "typical_lead_time"),
	        new Array("Minimum for Color and Typical Lead Time", "minimum_for_color_and"),
	        new Array("Material", "material"),
	        new Array("Height (mm)", "height_mm"),
	        new Array("Diameter (mm)", "diameter_mm"),
	        new Array("Location", "location"))
	);
	var category_containers = new AssistedSearchCategory(
	    "category_button_containers",
	    "search_container_containers",
	    advanced_search_fields,
	    product_db
	);
	
	var product_db = new ProductDatabase(
		dispensers,
		"list_container_dispensers",
		false,
	    new Array(
	        new Array("Part Number", "carow_part_number"),
	        new Array("Product Name", "category_name"),
	        new Array("Color", "color"),
	        new Array("Output cc", "output_cc"),
	        new Array("Output oz", "output_oz"),
	        new Array("Minimum", "minimum"),
	        new Array("Location", "location")),
	    new Array(
	        new Array("Note", "note"),
	        new Array("Typical Lead Time", "typical_lead_time"),
	        new Array("Minimum for Color and Typical Lead Time", "minimum_for_color_and"),
	        new Array("Height (mm)", "height_mm"),
	        new Array("Diameter (mm)", "diameter_mm"))
	);
	var category_dispensers = new AssistedSearchCategory(
	    "category_button_dispensers",
	    "search_container_dispensers",
	    advanced_search_fields,
	    product_db
	);
	
	// Show default page (pumps)
	current_page = category_pumps;
	current_page.container.setStyle("display", "block");
	current_page.fx_container_opacity.set(1.0);
	current_page.category_switch_link.addClass("selected");
	advanced_search_fields.setStyle("height", current_page.container.getSize().y + "px");
});
