//-- AJAX FUNCTIONS --//

/**
 * The AjaxRequest class is a wrapper for the XMLHttpRequest objects which
 * are available in most modern browsers. It simplifies the interfaces for
 * making Ajax requests, adds commonly-used convenience methods, and makes
 * the process of handling state changes more intuitive.
 * An object may be instantiated and used, or the Class methods may be used
 * which internally create an AjaxRequest object.
 * Code taken from {@link http://www.ajaxtoolbox.com/}
 */
function AjaxRequest() {
    var req = new Object();

    // -------------------
    // Instance properties
    // -------------------

    /**
     * Timeout period (in ms) until an async request will be aborted, and
     * the onTimeout function will be called
     */
    req.timeout = null;

    /**
     *	Since some browsers cache GET requests via XMLHttpRequest, an
     * additional parameter called AjaxRequestUniqueId will be added to
     * the request URI with a unique numeric value appended so that the requested
     * URL will not be cached.
     */
    req.generateUniqueUrl = true;

    /**
     * The url that the request will be made to, which defaults to the current
     * url of the window
     */
    req.url = window.location.href;

    /**
     * The method of the request, either GET (default), POST, or HEAD
     */
    req.method = "GET";

    /**
     * Whether or not the request will be asynchronous. In general, synchronous
     * requests should not be used so this should rarely be changed from true
     */
    req.async = true;

    /**
     * The username used to access the URL
     */
    req.username = null;

    /**
     * The password used to access the URL
     */
    req.password = null;

    /**
     * The parameters is an object holding name/value pairs which will be
     * added to the url for a GET request or the request content for a POST request
     */
    req.parameters = new Object();

    /**
     * The sequential index number of this request, updated internally
     */
    req.requestIndex = AjaxRequest.numAjaxRequests++;

    /**
     * Indicates whether a response has been received yet from the server
     */
    req.responseReceived = false;

    /**
     * The name of the group that this request belongs to, for activity
     * monitoring purposes
     */
    req.groupName = null;

    /**
     * The query string to be added to the end of a GET request, in proper
     * URIEncoded format
     */
    req.queryString = "";

    /**
     * After a response has been received, this will hold the text contents of
     * the response - even in case of error
     */
    req.responseText = null;

    /**
     * After a response has been received, this will hold the XML content
     */
    req.responseXML = null;

    /**
     * After a response has been received, this will hold the status code of
     * the response as returned by the server.
     */
    req.status = null;

    /**
     * After a response has been received, this will hold the text description
     * of the response code
     */
    req.statusText = null;

    /**
     * An internal flag to indicate whether the request has been aborted
     */
    req.aborted = false;

    /**
     * The XMLHttpRequest object used internally
     */
    req.xmlHttpRequest = null;

    // --------------
    // Event handlers
    // --------------

    /**
     * If a timeout period is set, and it is reached before a response is
     * received, a function reference assigned to onTimeout will be called
     */
    req.onTimeout = null;

    /**
     * A function reference assigned will be called when readyState=1
     */
    req.onLoading = null;

    /**
     * A function reference assigned will be called when readyState=2
     */
    req.onLoaded = null;

    /**
     * A function reference assigned will be called when readyState=3
     */
    req.onInteractive = null;

    /**
     * A function reference assigned will be called when readyState=4
     */
    req.onComplete = null;

    /**
     * A function reference assigned will be called after onComplete, if
     * the statusCode=200
     */
    req.onSuccess = null;

    /**
     * A function reference assigned will be called after onComplete, if
     * the statusCode != 200
     */
    req.onError = null;

    /**
     * If this request has a group name, this function reference will be called
     * and passed the group name if this is the first request in the group to
     * become active
     */
    req.onGroupBegin = null;

    /**
     * If this request has a group name, and this request is the last request
     * in the group to complete, this function reference will be called
     */
    req.onGroupEnd = null;

    // Get the XMLHttpRequest object itself
    req.xmlHttpRequest = AjaxRequest.getXmlHttpRequest();
    if (req.xmlHttpRequest==null) { return null; }

    // -------------------------------------------------------
    // Attach the event handlers for the XMLHttpRequest object
    // -------------------------------------------------------
    req.xmlHttpRequest.onreadystatechange =
	function() {
        if (req==null || req.xmlHttpRequest==null) { return; }
        if (req.xmlHttpRequest.readyState==1) { req.onLoadingInternal(req); }
        if (req.xmlHttpRequest.readyState==2) { req.onLoadedInternal(req); }
        if (req.xmlHttpRequest.readyState==3) { req.onInteractiveInternal(req); }
        if (req.xmlHttpRequest.readyState==4) { req.onCompleteInternal(req); }
    };

    // ---------------------------------------------------------------------------
    // Internal event handlers that fire, and in turn fire the user event handlers
    // ---------------------------------------------------------------------------
    // Flags to keep track if each event has been handled, in case of
    // multiple calls (some browsers may call the onreadystatechange
    // multiple times for the same state)
    req.onLoadingInternalHandled = false;
    req.onLoadedInternalHandled = false;
    req.onInteractiveInternalHandled = false;
    req.onCompleteInternalHandled = false;
    req.onLoadingInternal =
        function() {
        if (req.onLoadingInternalHandled) { return; }
        AjaxRequest.numActiveAjaxRequests++;
        if (AjaxRequest.numActiveAjaxRequests==1 && typeof(window['AjaxRequestBegin'])=="function") {
            AjaxRequestBegin();
        }
        if (req.groupName!=null) {
            if (typeof(AjaxRequest.numActiveAjaxGroupRequests[req.groupName])=="undefined") {
                AjaxRequest.numActiveAjaxGroupRequests[req.groupName] = 0;
            }
            AjaxRequest.numActiveAjaxGroupRequests[req.groupName]++;
            if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==1 && typeof(req.onGroupBegin)=="function") {
                req.onGroupBegin(req.groupName);
            }
        }
        if (typeof(req.onLoading)=="function") {
            req.onLoading(req);
        }
        req.onLoadingInternalHandled = true;
    };
    req.onLoadedInternal =
        function() {
        if (req.onLoadedInternalHandled) { return; }
        if (typeof(req.onLoaded)=="function") {
            req.onLoaded(req);
        }
        req.onLoadedInternalHandled = true;
    };
    req.onInteractiveInternal =
        function() {
        if (req.onInteractiveInternalHandled) { return; }
        if (typeof(req.onInteractive)=="function") {
            req.onInteractive(req);
        }
        req.onInteractiveInternalHandled = true;
    };
    req.onCompleteInternal =
        function() {
        if (req.onCompleteInternalHandled || req.aborted) { return; }
        req.onCompleteInternalHandled = true;
        AjaxRequest.numActiveAjaxRequests--;
        if (AjaxRequest.numActiveAjaxRequests==0 && typeof(window['AjaxRequestEnd'])=="function") {
            AjaxRequestEnd(req.groupName);
        }
        if (req.groupName!=null) {
            AjaxRequest.numActiveAjaxGroupRequests[req.groupName]--;
            if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==0 && typeof(req.onGroupEnd)=="function") {
                req.onGroupEnd(req.groupName);
            }
        }
        req.responseReceived = true;
        req.status = req.xmlHttpRequest.status;
        req.statusText = req.xmlHttpRequest.statusText;
        req.responseText = req.xmlHttpRequest.responseText;
        req.responseXML = req.xmlHttpRequest.responseXML;
        if (typeof(req.onComplete)=="function") {
            req.onComplete(req);
        }
        if (req.xmlHttpRequest.status==200 && typeof(req.onSuccess)=="function") {
            req.onSuccess(req);
        }
        else if (typeof(req.onError)=="function") {
            req.onError(req);
        }

        // Clean up so IE doesn't leak memory
        delete req.xmlHttpRequest['onreadystatechange'];
        req.xmlHttpRequest = null;
    };
    req.onTimeoutInternal =
        function() {
        if (req!=null && req.xmlHttpRequest!=null && !req.onCompleteInternalHandled) {
            req.aborted = true;
            req.xmlHttpRequest.abort();
            AjaxRequest.numActiveAjaxRequests--;
            if (AjaxRequest.numActiveAjaxRequests==0 && typeof(window['AjaxRequestEnd'])=="function") {
                AjaxRequestEnd(req.groupName);
            }
            if (req.groupName!=null) {
                AjaxRequest.numActiveAjaxGroupRequests[req.groupName]--;
                if (AjaxRequest.numActiveAjaxGroupRequests[req.groupName]==0 && typeof(req.onGroupEnd)=="function") {
                    req.onGroupEnd(req.groupName);
                }
            }
            if (typeof(req.onTimeout)=="function") {
                req.onTimeout(req);
            }
            // Opera won't fire onreadystatechange after abort, but other browsers do.
            // So we can't rely on the onreadystate function getting called. Clean up here!
            delete req.xmlHttpRequest['onreadystatechange'];
            req.xmlHttpRequest = null;
        }
    };

    // ----------------
    // Instance methods
    // ----------------
    /**
     * The process method is called to actually make the request. It builds the
     * querystring for GET requests (the content for POST requests), sets the
     * appropriate headers if necessary, and calls the
     * XMLHttpRequest.send() method
     */
    req.process =
        function() {
        if (req.xmlHttpRequest!=null) {
            // Some logic to get the real request URL
            if (req.generateUniqueUrl && req.method=="GET") {
                req.parameters["AjaxRequestUniqueId"] = new Date().getTime() + "" + req.requestIndex;
            }
            var content = null; // For POST requests, to hold query string
            for (var i in req.parameters) {
                if (req.queryString.length>0) { req.queryString += "&"; }
                req.queryString += encodeURIComponent(i) + "=" + encodeURIComponent(req.parameters[i]);
            }
            if (req.method=="GET") {
                if (req.queryString.length>0) {
                    req.url += ((req.url.indexOf("?")>-1)?"&":"?") + req.queryString;
                }
            }
            req.xmlHttpRequest.open(req.method,req.url,req.async,req.username,req.password);
            if (req.method=="POST") {
                if (typeof(req.xmlHttpRequest.setRequestHeader)!="undefined") {
                    req.xmlHttpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
                }
                content = req.queryString;
            }
            if (req.timeout>0) {
                setTimeout(req.onTimeoutInternal,req.timeout);
            }
            req.xmlHttpRequest.send(content);
        }
    };

    /**
     * An internal function to handle an Object argument, which may contain
     * either AjaxRequest field values or parameter name/values
     */
    req.handleArguments =
        function(args) {
        for (var i in args) {
            // If the AjaxRequest object doesn't have a property which was passed, treat it as a url parameter
            if (typeof(req[i])=="undefined") {
                req.parameters[i] = args[i];
            }
            else {
                req[i] = args[i];
            }
        }
    };

    /**
     * Returns the results of XMLHttpRequest.getAllResponseHeaders().
     * Only available after a response has been returned
     */
    req.getAllResponseHeaders =
        function() {
        if (req.xmlHttpRequest!=null) {
            if (req.responseReceived) {
                return req.xmlHttpRequest.getAllResponseHeaders();
            }
            alert("Cannot getAllResponseHeaders because a response has not yet been received");
        }
    };

    /**
     * Returns the the value of a response header as returned by
     * XMLHttpRequest,getResponseHeader().
     * Only available after a response has been returned
     */
    req.getResponseHeader =
        function(headerName) {
        if (req.xmlHttpRequest!=null) {
            if (req.responseReceived) {
                return req.xmlHttpRequest.getResponseHeader(headerName);
            }
            alert("Cannot getResponseHeader because a response has not yet been received");
        }
    };

    return req;
}

// ---------------------------------------
// Static methods of the AjaxRequest class
// ---------------------------------------

/**
 * Returns an XMLHttpRequest object, either as a core object or an ActiveX
 * implementation. If an object cannot be instantiated, it will return null;
 */
AjaxRequest.getXmlHttpRequest = function() {
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        // Based on http://jibbering.com/2002/4/httprequest.html
        /*@cc_on @*/
        /*@if (@_jscript_version >= 5)
		try {
			return new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				return new ActiveXObject("Microsoft.XMLHTTP");
			} catch (E) {
				return null;
			}
		}
		@end @*/
    } else {
        return null;
    }
};

/**
 * See if any request is active in the background
 */
AjaxRequest.isActive = function() {
    return (AjaxRequest.numActiveAjaxRequests>0);
};

/**
 * Make a GET request. Pass an object containing parameters and arguments as
 * the second argument.
 * These areguments may be either AjaxRequest properties to set on the request
 * object or name/values to set in the request querystring.
 */
AjaxRequest.get = function(args) {
    AjaxRequest.doRequest("GET",args);
};

/**
 * Make a POST request. Pass an object containing parameters and arguments as
 * the second argument.
 * These areguments may be either AjaxRequest properties to set on the request
 * object or name/values to set in the request querystring.
 */
AjaxRequest.post = function(args) {
    AjaxRequest.doRequest("POST",args);
};

/**
 * The internal method used by the .get() and .post() methods
 */
AjaxRequest.doRequest = function(method,args) {
    if (typeof(args)!="undefined" && args!=null) {
        var myRequest = new AjaxRequest();
        myRequest.method = method;
        myRequest.handleArguments(args);
        myRequest.process();
    }
}	;

/**
 * Submit a form. The requested URL will be the form's ACTION, and the request
 * method will be the form's METHOD.
 * Returns true if the submittal was handled successfully, else false so it
 * can easily be used with an onSubmit event for a form, and fallback to
 * submitting the form normally.
 */
AjaxRequest.submit = function(theform, args) {
    var myRequest = new AjaxRequest();
    if (myRequest==null) { return false; }
    var serializedForm = AjaxRequest.serializeForm(theform);
    myRequest.method = theform.method.toUpperCase();
    myRequest.url = theform.action;
    myRequest.handleArguments(args);
    myRequest.queryString = serializedForm;
    myRequest.process();
    return true;
};

/**
 * Serialize a form into a format which can be sent as a GET string or a POST
 * content.It correctly ignores disabled fields, maintains order of the fields
 * as in the elements[] array. The 'file' input type is not supported, as
 * its content is not available to javascript. This method is used internally
 * by the submit class method.
 */
AjaxRequest.serializeForm = function(theform) {
    var els = theform.elements;
    var len = els.length;
    var queryString = "";
    this.addField =
        function(name, value) {
        if (queryString.length>0) {
            queryString += "&";
        }
        queryString += encodeURIComponent(name) + "=" + encodeURIComponent(value);
    };
    for (var i=0; i<len; i++) {
        var el = els[i];
        if (!el.disabled) {
            switch(el.type) {
                case 'text': case 'password': case 'hidden': case 'textarea':
					this.addField(el.name, el.value);
					break;
				case 'select-one':
					if (el.selectedIndex >= 0) {
						this.addField(el.name, el.options[el.selectedIndex].value);
					}
					break;
				case 'select-multiple':
					for (var j = 0; j < el.options.length; j++) {
						if (el.options[j].selected) {
							this.addField(el.name, el.options[j].value);
						}
					}
					break;
				case 'checkbox': case 'radio':
						if (el.checked) {
							this.addField(el.name, el.value);
						}
						break;
		 	 }
		}
	}
	return queryString;
};

// -----------------------
// Static Class variables
// -----------------------

/**
 * The number of total AjaxRequest objects currently active and running
 */
AjaxRequest.numActiveAjaxRequests = 0;

/**
 * An object holding the number of active requests for each group
 */
AjaxRequest.numActiveAjaxGroupRequests = new Object();

/**
 * The total number of AjaxRequest objects instantiated
 */
AjaxRequest.numAjaxRequests = 0;

//-- DISTRIBUTOR SEARCH/MAP FUNCTIONS --//

/**
 * Function loads our Google maps script dynamically
 */
function load_maps_script() {
	var m_script = document.createElement("script");
	m_script.type = "text/javascript";
	m_script.src = "http://maps.google.com/maps?file=api&v=2.x&key=" + gkey + "&async=2&callback=load_distributor_map";
	document.body.appendChild(m_script);
}

/**
 * Function used to create a new GMarker object and set up the event window (click)
 * @param {object} point
 * @param {string} html
 * @returns {object} marker
 */
function create_marker(point, html) {
	var marker = new GMarker(point);
	GEvent.addListener(marker, "click", function() {
	  marker.openInfoWindowHtml(html, {maxWidth:150});
	});

	return marker;
}

/**
 * Function picks up the click event for a given marker and opens the
 * corresponding info window (for use with link other than GMarker)
 * @param {integer} m
 */
function get_marker(m) {
	gmarkers[m].openInfoWindowHtml(htmls[m],{maxWidth:150});
}

/**
 *  Load our distributor map based off search results written to our page as js code (json variables)
 */
function load_distributor_map() {
	if (GBrowserIsCompatible()) {
		var map = new GMap2($("map")), searched_address = json_decode(search_address), search_point = new GLatLng(searched_address.latitude, searched_address.longitude), locations_list = json_decode(locations);
		map.addControl(new GSmallZoomControl3D());
		map.addControl(new GScaleControl());
		map.setCenter(search_point, (searched_address.tolerance == 100 ? 6 : (searched_address.tolerance == 50 ? 7 : 9)));
		
		for (var i in locations_list) {
			if (trim(locations_list[i].name) != '') {
				var point = new GLatLng(locations_list[i].latitude, locations_list[i].longitude);
				
				var marker_html = '<div>' +
				                  '<h4>' + unescape(locations_list[i].name) + '</h4>' + 
								  '<p>' + unescape(locations_list[i].address) + '<br />' + 
								  unescape(locations_list[i].city) + ', ' + unescape(locations_list[i].state) + ' ' + locations_list[i].zip + '<br />' +
								  (locations_list[i].phone != '' ? 'Phone: ' + locations_list[i].phone + '<br />' : '') +
								  (locations_list[i].fax != '' ? 'Fax: ' + locations_list[i].fax + '<br />' : '') +
								  locations_list[i].distance + ' mile' + ((locations_list[i].distance > 1 || locations_list[i].distance == 0) ? 's' : '') + ' &bull; <a href="http://maps.google.com/maps?saddr=' + searched_address.address + '&daddr=' + locations_list[i].address + ',' + locations_list[i].city + ',' + locations_list[i].state + ' ' + locations_list[i].zip + '" target="_blank">Get Directions</a>' +
								  '</p></div>';

				//create our marker object, set up the click event, and add to our map
				var marker = create_marker(point, marker_html);					
				map.addOverlay(marker);			
				
				// save the info we need to use later for our location list links
				gmarkers[i] = marker;
				htmls[i] = marker_html;
			}
		}		
	}
}

//-- PRODUCT FUNCTIONS --//

/**
 * Function to clear out our right pane browse section's content, hide the element,
 * then show our right-pane section
 */
function hide_product() {
	$('content-browse').innerHTML = '';
	$('content-browse').style.display = 'none';
	$('content').style.display = '';
}

/**
 * Function returns the last div, used by product browse/attribute search
 * @param {string} prefix
 * @param {string} divid
 */
function last_div(prefix, divid) {
	return prefix + (divid.substring(prefix.length) - 0 - 1);
}

/**
 * Function returns the next div, used by product browse/attribute search
 * @param {string} prefix
 * @param {string} divid
 */
function next_div(prefix, divid) {
	return prefix + (divid.substring(prefix.length) - 0 + 1);
}

/**
 * Function used to return child items for given dattributeid
 * @param {Integer} did
 * @param {string} type
 * @return {array}
 */
function list_children(did, type) {
	return ((type == 'as') ? explode_array(ASplist[did], ',') : explode_array(PBplist[did], ','));
}

/**
 * Function used to show/hide additional product images
 * @param {string} image
 * @param {integer} total_images
 */
function show_image(image, total_images) {
	//hide all images
	for (var i = 1; i <= total_images; i++){
		$('prod' + i).style.display = 'none';
	}
	//show new main Image
	$(image).style.display = 'block';
}

/**
 * Function used to show our given div, also hides
 * other divs and sets active nav link (used by our 
 * download pages e.g. instruction sheets, photomotry, etc.)
 * @param {string} div
 */
function show_div(div) {
	var nav_array = $('products-nav').getElementsByTagName('a'), div_array = $('products-container').getElementsByTagName('div');
	
	//reset our other nav links
	for (var i = 0, nav_length = nav_array.length; i < nav_length; i++) {
		nav_array[i].className = '';
	}
	
	//hide all our other divs
	for (i = 0, div_length = div_array.length; i < div_length; i++) {
		if (div_array[i].id != '') {
			div_array[i].style.display = "none";
		}
	}
	
	//attempt to show our div and set our current link
	if ($(div)) {
		//set our active nav link
		$('nav-' + div).className = "current";
		
		//show our div
		$(div).style.display = "block";
	}
		
	return;	
}

/**
 * Function used to show our given div, also hides other divs
 * and resets our expand/collapse images (used by our
 * product pages activated by our tab navigation)
 * @param {string} div
 */
function show_content(div) {
	var div_array = child_elements('product-container');
	
	for (var i = 0, div_length = div_array.length; i < div_length; i++) {
		div_array[i].style.display = "none";
	}
	
	//reset our expand-collapse images
	reset_expand_collapse_images();

	//show our div
	if ($(div + '-content')) {
		$(div + '-content').style.display = 'block';
	}

	return;
}

/**
 * Function used to reset our expandable divs on our
 * product pages, we're not maintaining state across
 * tabs, instead we're resetting to default state
 */
function reset_expand_collapse_images() {
	var element_array = $('product-container').getElementsByTagName('li');
	
	for (var i = 0, element_array_length = element_array.length; i < element_array_length; i++) {
		if (element_array[i].id.indexOf('excol') != -1) {
			$(element_array[i]).className = "expand";
			
			//we need to get our child elements for this list item, and hide the div below it
			var children = child_elements(element_array[i].id);
			
			for (var j = 0, children_length = children.length; j < children_length; j++) {
				if (children[j].id != '') {
					children[j].style.display = "none";
				}
			}
		}
	}
}

/**
 * Function used to toggle our product browse/attribute search menu
 * @param {string} mode
 * @param {boolean} save Optional
 */
function toggle_menu(mode, save) {
	if (!save) {var save = false;}

	switch (mode) {
		case 'hide':
			if ($('side-pane')) {$('side-pane').style.display = 'none';}
			if ($('hide')) {$('hide').style.display = "none";}
			if ($('show')) {$('show').style.display = "";}	
			if ($('content')) {$('content').style.width = "100%";}
			break;
		case 'show':
			if ($('side-pane')) {$('side-pane').style.display = 'block';}
			if ($('hide')) {$('hide').style.display = "";}
			if ($('show')) {$('show').style.display = "none";}
			if ($('content')) {$('content').style.width = "600px";}
			break;			
	}

	//update our cookie if applicable
	if (save) {
		save_product_browse_cookie(mode);
	}
}

/**
 * Function used to set our active tab and the contents
 * for that tab, also deactives our other tabs
 * @param {string} tab
 */
function set_active_tab(tab) {
	//inactivate our previously active tab
	for (var i = 0, tab_count = $('tabNav').getElementsByTagName('li').length; i < tab_count; i++) {
		$('tabNav').getElementsByTagName('li')[i].className = "";
	}

	if ($(tab + 'Tab')) {
		//set our active tab
		$(tab + 'Tab').className = "current";

		//show our content for this tab
		show_content(tab);
	}
}

/**
 * Function used to save product browse preference cookie
 * @param {string} mode
 */
function save_product_browse_cookie(mode) {
	//let's create our cookie with their product browse menu preference
	create_cookie('product_browse_preference', mode, 365);
}

/**
 * Function to get product browse menu preference (reads from cookie)
 * and set's the style property of our product-menu element
 */
function get_product_browse_preference() {
	toggle_menu(read_cookie('product_browse_preference'));
}

/**
 * Function to initialize our attribute search functionality
 * @param {string} attribute_search_history Optional
 */
function attribute_search(attribute_search_history) {
	if (!attribute_search_history) {var attribute_search_history = '';}
	var siteurl = ''; 
	
	$('content-browse').style.display = 'none';
	$('content').style.display = 'block';
				   
	var ulstring = ' <ul>' +
				   '  <li class="selected"><a href="javascript: void(0);" onclick="attribute_search();"><span>Attribute Search</span></a></li>' +
				   '  <li><a href="javascript: void(0);" onclick="product_browse();"><span>Product Browse</span></a></li>' +
				   ' </ul>';
	
	$('pbrowse-tabs').innerHTML = ulstring;

	$('content-browse').innerHTML = '';
	$('attSearch1').innerHTML = ''; //clear existing att search
	
	$('content-browse').style.display = 'none';
	$('attSearch1').style.display = 'block';
	$("prod-browse").innerHTML = ''; //clear any existing product list
	$("prod-browse").style.display = 'none';

	if (attribute_search_history != '') {
		write_attribute_search_dd(asDid, 'attSearch1', siteurl, attribute_search_history, attribute_search_history);
	} else {
		write_attribute_search_dd(asDid, 'attSearch1', siteurl);
	}
}

/**
 * Function used to initialize our product browse functionality
 * @return string|int selected_did Optional
 */
function product_browse(selected_did) {
	if (!selected_did) {var selected_did = '';}	
	var siteurl = '' 

	$('content-browse').style.display = '';
	$('content').style.display = 'block';
					   
	var ulstring = ' <ul>' +
				   '  <li><a href="javascript: void(0);" onclick="attribute_search();"><span>Attribute Search</span></a></li>' +	
				   '  <li class="selected"><a href="javascript: void(0);" onclick="product_browse();"><span>Product Browse</span></a></li>' +				   
				   ' </ul>' +
				   ' <div class="clear"></div>';
		
	$('pbrowse-tabs').innerHTML = ulstring;	
	$('content-browse').innerHTML = '';
	$('bottomDiv').innerHTML = '';
	$('attSearch1').innerHTML = ''; 
	$('prod-browse').innerHTML = '';
	$('attSearch1').style.display = 'none';

	write_product_browse_dd(pbDid, 'prod-browse', siteurl, (selected_did != '' ? selected_did : ''));
	
	$('prod-browse').style.display = '';
}

/**
 * Function used to process our product browse/attribute search
 * list item rollover functionality
 * @param {object} select_ref
 * @param {string} divid
 * @param {string} type
 * @param {string} siteurl
 * @param {string} attribute_search_history Optional
 */
function search_choice(select_ref, divid, type, siteurl, attribute_search_history) {
	if (!attribute_search_history) {var attribute_search_history = '';}
	var selval = select_ref.options[select_ref.selectedIndex].value
	if (selval == select_ref.name) { //know this is attsearch since select name is a did
		var lastdiv = last_div('attribute-search', divid);
		//chose all option, must redraw dd to calculate matched products
		//must remove all attribute_search_history entries to the right of passed in did
		if (attribute_search_history != '') {
			var attribute_search_history = arguments[4].substring(0, arguments[4].indexOf(selval)+selval.length);
			write_attribute_search_dd(selval, lastdiv, siteurl, attribute_search_history);
		} else {
			write_attribute_search_dd(selval, lastdiv, siteurl, '');
		}
	} else if (type == 'as') {
		if (attribute_search_history != '') {
			//need to check if this is a selection above the current ahist and trim it accordingly
			//can achieve this by counting the number of ids in ahist and comparing it to the div id
			var splitAShist = explode_array(arguments[4], "_");
			var numAShist = splitAShist.length;
			var currentDD = divid.substring(9) - 0 - 1;
			if (numAShist >= currentDD) {//user selected up the asearch tree, trim attribute_search_history 
				for (i = 0; i < currentDD - 1; i++) {
					if (i == 0) {
						var attribute_search_history = splitAShist[i];
					} else {
						attribute_search_history += '_' + splitAShist[i];
					}
				}
				
				if (!defined(attribute_search_history)) {//need to make sure this isn't the top level and that the attribute_search_history will be undefined
					var attribute_search_history = selval;
				} else {
					attribute_search_history += '_' + selval;
				}
			} else {
				var attribute_search_history = arguments[4] + '_' + selval; 
			}
		} else {
			var attribute_search_history = selval;
		}
		write_attribute_search_dd(selval, divid, siteurl, attribute_search_history);
	} else if (type == 'pb') {
		//don't process if they selected the top select list item ('all')
		if (selval == pbDid) {
			$(divid).innerHTML = '';
		} else {
			//reset our div
			$(divid).innerHTML = '';

			//if this is a non-product link, open a new window with our url
			if (PBindex[selval][0] == "Non-Product Link") {
				//reset our select menu	
				select_ref.selectedIndex = 0;

				//open our window
				window.open(PBindex[selval][2]);					
				return;
			} else {
				var parameters = new Object();
					parameters._method = 'get_index_product_list';
					parameters.did = selval;
				
					AjaxRequest.post({
							'url': siteurl + 'includes/ajax.php',
							'parameters': parameters,
							'onLoading': toggle_element('loading'),
							'onSuccess': function(t) {write_product_browse_list(selval, divid, siteurl, t.responseText);toggle_element('loading');},
							'onError': function(t) {alert('Unable to retrieve product(s) for this product type');toggle_element('loading');}
					});
			}
		}
	}
}

/**
 * Function used to write out our attribute search drop down list
 * @param {int} did
 * @param {string} divid
 * @param {string} siteurl
 * @param {string} attribute_search_history Optional
 * @param {string} attribute_search_path Optional
 */
function write_attribute_search_dd(did, divid, siteurl, attribute_search_history, attribute_search_path) {
	if (did == '') {
		return false;
	}

	if (!attribute_search_history) {var attribute_search_history = '';}
	if (!attribute_search_path) {var attribute_search_path = '';}
	
	if (attribute_search_path != '') {
		if (attribute_search_path.indexOf('_') != -1) {
			var nextid = attribute_search_path.substring(0, attribute_search_path.indexOf('_')); //grab the first selection in aspath
			attribute_search_path = attribute_search_path.substring(attribute_search_path.indexOf('_')+1); //remove first selection from aspath
		} else {//only one selection
			var nextid = attribute_search_path;
			attribute_search_path = '';
		}
	}
		
	var matched = ASindex[did][2];
	var nextdiv = next_div('attSearch', divid);
	var category = list_children(did, 'as');
		
	//check if product returned
	if (ASindex[category[0]][0] == 'Product Name') {//product level
		if (arguments.length != 5) {
			//here we need to get our product list for this category
			var parameters = new Object();
				parameters._method = 'get_index_product_list';
				parameters.did = did;
			
				AjaxRequest.post({
					'url': siteurl + 'includes/ajax.php',
					'parameters': parameters,
					'onLoading': toggle_element('loading'),
					'onSuccess': function(t) {show_products(siteurl, t.responseText, attribute_search_history);toggle_element('loading');},
					'onError': function(t) {alert('Unable to retrieve product(s) for this product type');toggle_element('loading');}
				});
		}
		$(divid).innerHTML = '';
	} else {//category level
		if (did == asDid) {
			$('content-browse').innerHTML = '';
			$('content-browse').style.display = 'none';
			$('content').style.display = 'block';
		} else {				
			if (arguments.length != 5) {
				//here we need to get our product list for this category
				var parameters = new Object();
					parameters._method = 'get_index_product_list';
					parameters.did = did;
					
					AjaxRequest.post({
						'url': siteurl + 'includes/ajax.php',
						'parameters': parameters,
						'onLoading': toggle_element('loading'),
						'onSuccess': function(t) {show_products(siteurl, t.responseText, attribute_search_history);toggle_element('loading');},
						'onError': function(t) {alert('Unable to retrieve product(s) for this product type');toggle_element('loading');}
					});
			}
		}
		
		var	dd = '<h4 class="light">' + ASindex[category[0]][1] + '</h4>\n';		
		dd += '<select name="' + did + '" onChange="search_choice(this, \'' + nextdiv + '\', \'as\', \'' + siteurl + '\', \'' + attribute_search_history + '\');">\n';
		dd += '<option value="' + did + '">-- All --</option>\n';
		var choices = list_children(category[0], 'as');
		for (i=0; i < choices.length; i++) {
			if (choices[i] == nextid) {
				dd += '<option value="' + choices[i] + '" selected>' + ASindex[choices[i]][1] + '</option>\n';
			} else {
				dd += '<option value="' + choices[i] + '">' + ASindex[choices[i]][1] + '</option>\n';
			}
		}
		dd += '</select><div id="' + nextdiv + '"></div>\n'
		
		//write out bottom divs
		//num matching prods and reset button into bottomDiv
		if ($(divid)) {
			$(divid).innerHTML = dd;
		}
		
		$('bottomDiv').innerHTML = '';
	}

	//only show reset and found matches after first selection
	if (did != asDid) {
		var bottomDivs = '<p class="light">Found Matches: ' + matched + '</p>';
		bottomDivs += '<p id="reset"><input type="button" onClick="attribute_search();" value="Reset" /></p>\n';
		$('bottomDiv').innerHTML = bottomDivs;
	}

	if (trim(attribute_search_path) != '') {//have more path to display
		write_attribute_search_dd(nextid, nextdiv, siteurl, attribute_search_history, attribute_search_path);
	}
}

/**
 * Function used to write out our product browse drop down list
 * @param {int} did
 * @param {string} divid
 * @param {string} siteurl
 * @param {string} selected_did Optional
 */
function write_product_browse_dd(did, divid, siteurl, selected_did) {
	if (!selected_did) {var selected_did = '';}		
	var nextdiv = next_div('prod-browse', divid);
	var dd = '<form id="productBrowseForm"><h4 class="light">Browse Product Type</h4>' +
	         '<select onChange="search_choice(this, \'' + nextdiv + '\', \'pb\',\'' + siteurl + '\');" />\n' +
			 '<option value="' + did + '">-- All --</option>\n';

	var choices = list_children(did, 'pb');
			
	for (var i = 0, c_count = choices.length; i < c_count; i++) {
		dd += '<option value="' + choices[i] + '"' + ((selected_did != '' && [i] == selected_did) ? ' selected' : '') + '>' + PBindex[choices[i]][1] + '</option>\n';
	}
	
	dd += '</select>\n<div id="' + nextdiv + '"></div></form>\n';
	$(divid).innerHTML = dd;
	
	if (selected_did != '') {
		//here we need to get our product list for this category
		var parameters = new Object();
			parameters._method = 'get_index_product_list';
			parameters.did = selected_did;
		
			AjaxRequest.post({
				'url': siteurl + 'includes/ajax.php',
				'parameters': parameters,
				'onLoading': toggle_element('loading'),
				'onSuccess': function(t) {write_product_browse_list(selected_did, nextdiv, siteurl, t.responseText);toggle_element('loading');},
				'onError': function(t) {alert('Unable to retrieve product(s) for this product type');toggle_element('loading');}
			});
	}
}

/**
 * Function used to write out our product browse list
 * @param {int} did
 * @param {string} divid
 * @param {string} siteurl
 * @param {object} product_data
 */
function write_product_browse_list(did, divid, siteurl, product_data) {
	var filename_array = window.location.pathname.split('/');	
	var filename = filename_array[filename_array.length-2];

	var prod_list = "<ul class=\"side-nav\" style=\"width:180px\">\n";
    
	if (product_data == "") {
		alert("No data available for the selected category. Please try your request again.");
		product_browse('');
		return;
	}
		
	//parse our json string
	product_data = json_decode(product_data);
	var products = product_data.products;
		
	for (var i = 0, product_count = products.length; i < product_count; i++) {
		if (filename == products[i].filename) {//on this product page, don't link and no mouseover event
			prod_list += '<li><a class=\"current\">' + products[i].productName + '</a></li>\n';
		} else {//not on product page, include mouseover and link
			prod_list += "<li onmouseover=\"show_product(" + products[i].did + ",'" + siteurl + "','" + escape(json_encode(products[i])) + "');\" onmouseout=\"this.className='';hide_product();\"><a href=\"" + siteurl + "products/" + products[i].filename + "/?pbid=" + did + "\">" + products[i].productName + "</a></li>\n";
		}
	}
	
	prod_list += "</ul>\n";

	$(divid).innerHTML = prod_list;
}

/**
 * Function used to display list of products based
 * off of user selected attribute search criteria
 * @param {string} siteurl
 * @param {object} product_data
 * @param {string} attribute_search_history
 */
function show_products(siteurl, product_data, attribute_search_history) {
	if (product_data == "") {
		alert("No data available for the selected category. Please try your request again.");
		attribute_search();
		return;
	}

	//set our prodData (parsing our JSON string)
	var products = json_decode(unescape(product_data));
	 	products = products.products;

	var prod_count = products.length;

	//begin our product listing
	var prod_div = 	'<div id="content-header"><h4>Attribute Search</h4></div>';
	prod_div += '<div class="section">';
		
	for (var i = 0; i < prod_count; i++) {
		//ensure this is a valid product
		if (defined(products[i])) {			
			prod_div += '<div class="box">';
			
			//ensure we have a product image
			if (products[i].productImage != '') {
				prod_div += ' <img class="thumbnail float-left" src="' + siteurl + 'content/products/images/thumb/' + products[i].productImage + '" alt="' + products[i].productName + '" />';				
			}
			
			//product name	
			prod_div += '<div class="box-text float-left">';
			prod_div += ' <h3>' + products[i].productName + '</h3>';
			
			//ensure we have a product subtitle		
			if (products[i].subtitle != 'template') {
				prod_div += ' <h4>' + products[i].subtitle + '</h4>';				
			}
			
			//ensure we have a product description
			if (products[i].productDescription != 'template') {
				prod_div += ' <p>' + products[i].productDescription + '</p>';
			}

			//ensure we have a filename			
			if (products[i].filename != '') {
				prod_div += ' <p><a href="' + siteurl + 'products/' + products[i].filename + (attribute_search_history != '' ? '/?ashist=' + attribute_search_history : '') + '">View Product Page</a></p>';
			}
			
			prod_div += '</div>';			
			prod_div += '<div class="clear"></div>';
			prod_div += '</div>';
		}
	}	

	prod_div +=	'</div>';
	
	if ($('results')) {$('results').innerHTML = 'Found Matches: ' + prod_count;}	
	$('content').style.display = 'none';
	$('content-browse').innerHTML = prod_div;
	$('content-browse').style.display = 'block';
}

//-- COOKIE FUNCTIONS --//

/**
 * Function used to create cookie
 * @param {string} name
 * @param {string} value
 * @param {integer} days
 */
function create_cookie(name, value, days) {
	var expires = '';
	if (days) {
		var date = new Date();
		date.setTime(date.getTime() + (days*24*60*60*1000));
		expires = '; expires=' + date.toGMTString();
	} else {
		expires = '';
	}
	document.cookie = name + '=' + value + expires + '; path=/';
}

/**
 * Function used to read a cookie
 * @param {string} name
 * @return {string}
 */
function read_cookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for (var i = 0, cookie_length = ca.length; i < cookie_length; i++) {
		var c = ca[i];
		while (c.charAt(0) == ' ') c = c.substring(1, c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
	}
	return null;
}

//-- ALERA ELEMENTS CONFIGURATOR FUNCTIONS --//

/**
 * Function used to make element visible by setting the opacity to 100%
 * @param {string} element
 */
function pre_activate_selection(element) {
	element = $(element);

	//only activate if the className is not "activeSelection"
	if (element.className != 'activeSelection') {
		set_opacity(element, 1.0);
	}
}

/**
 * Function used to make element partially visible by setting the opacity to 20%
 * @param {string} element
 */
function de_activate_selection(element) {
	element = $(element);

	//only deactivate if the className is not "activeSelection"
	if (element.className != 'activeSelection') {
		set_opacity(element, 0.2);
		element.className = '';
	}
}

/**
 * Function used to deactivate (change opacity to 20% visible) child elements of our given
 * parent element and activate (change opacity to 100% visible) selected element
 * @param {string} parent_element
 * @param {string} selected_element
 */
function apply_selection(parent_element, selected_element) {
	var div_list = child_elements(parent_element);
	selected_element = $(selected_element);

	//hide our other items
	for (var i = 0, div_list_count = div_list.length; i < div_list_count; i++) {
		if (div_list[i].id != '' && div_list[i].id != selected_element.id) {
			//de-activate this item
			set_opacity(div_list[i], 0.2);

			//set className
			div_list[i].className = '';
		}
	}

	//activate our selection
	set_opacity(selected_element, 1.0);

	//set className
	selected_element.className = 'activeSelection';
}

//-- FILE DOWNLOAD DISCLAIMER FUNCTIONS --//

function toggle_download_terms(mode, filename) {
	mode = typeof(mode) != 'undefined' ? mode : 'hide';
	$('terms-agreement').style.display = (mode == 'show' && ($('terms-agreement').style.display == 'none') ? '' : 'none');

	//reset our file to our default
	if (filename == '') {
		$('file_to_download').value = 1;
		$('file_requested').innerHTML = '';
	} else {
		$('file_to_download').value = filename;
		$('file_requested').innerHTML = '<strong>Downloading file: ' + $('file_' + filename).innerHTML + '</strong>';
	}
}

//-- HELPER FUNCTIONS --//

/**
 * Function used to determine if a given object exists
 * @param {string} object
 * @return {boolean}
 */
function defined(object) {
	return (object != undefined);
}

/**
 * If provided with a string, returns the element in the document with matching ID; otherwise returns the passed element. Takes in an arbitrary number of arguments.
 */
function $(element) {
	if (arguments.length > 1) {
		for (var i = 0, elements = [], length = arguments.length; i < length; i++) {
			elements.push(document.getElementById(arguments[i]));
		}
		return elements;
	}

	if (is_string(element)) {
		element = document.getElementById(element);
	}

	return element;
}

/**
 * Internal function used by json_encode to safely escape offending characters
 * Original code taken from {@link http://mootools.net/}
 * @param {string} chr
 * @return {string} special_chars
 */
function replace_chars(chr) {
	var special_chars = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
	return special_chars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16);
}

/**
 * Converts an object or array to a JSON string
 * Original code taken from {@link http://mootools.net/docs/Utilities/JSON#JSON:encode}
 * @param {mixed} object
 * @return {object} JSON object
 */
function json_encode(object) {
	switch (typeof(object)){
		case 'string':
			return '"' + object.replace(/[\x00-\x1f\\"]/g, replace_chars) + '"';
		case 'array': case 'object':
				var string = [];
				for (var property in object) {
					var json = json_encode(object[property]);
					if (json) string.push(json_encode(property) + ':' + json);
				}
				return '{' + string + '}';
			case 'number': case 'boolean': return String(object);
			case false: return 'null';
		}

		return null;
}

/**
 * Converts a JSON string into an JavaScript object.
 * Original code taken from {@link http://mootools.net/docs/Utilities/JSON#JSON:decode}
 * @param {string} string to evaluate
 * @return {object} object represented by the JSON string
 */
function json_decode(string) {
        if (typeof(string) != 'string' || !string.length) return null;
        if (!(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
        return eval('(' + string + ')');
}

/**
 * Javascript equivalent of PHP's base64_encode function
 * @param {string} str_input
 * @return {string} encode
 */
function base64_encode(str_input) {
  var ascii=new String("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
  var encode=new String();
  var bits,dual,i=0;

  while (str_input.length>=i+3) {
    bits=(str_input.charCodeAt(i++) & 0xff) <<16
        | (str_input.charCodeAt(i++) & 0xff) <<8
        | str_input.charCodeAt(i++) & 0xff;

    encode+= ascii.charAt((bits & 0x00fc0000) >>18)
            + ascii.charAt((bits & 0x0003f000) >>12)
            + ascii.charAt((bits & 0x00000fc0) >> 6)
            + ascii.charAt((bits & 0x0000003f));
  }

  if ((str_input.length-i)>0 && (str_input.length-i)<3) {
    dual=Boolean(str_input.length -i -1);
    bits=((str_input.charCodeAt(i++) & 0xff) <<16) | (dual ? (str_input.charCodeAt(i) & 0xff) <<8 : 0);

    encode+= ascii.charAt((bits & 0x00fc0000) >>18)
            + ascii.charAt((bits & 0x0003f000) >>12)
            + (dual ? ascii.charAt((bits & 0x00000fc0) >>6) : '=')
            + '=';
  }
  return encode;
}

/**
 * Javascript equivalent of PHP's base64_decode function
 * @param {string} str_input
 * @return {string} decode
 */
function base64_decode(str_input) {
  var ascii=new String("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
  var decode,buffer=new String();
  var bits,i;

  for (i=0;i<str_input.length; i += 4) {
    bits=(ascii.indexOf(str_input.charAt(i)) & 0xff) <<18
        | (ascii.indexOf(str_input.charAt(i +1)) & 0xff) <<12
        | (ascii.indexOf(str_input.charAt(i +2)) & 0xff) << 6
        | ascii.indexOf(str_input.charAt(i +3)) & 0xff;

    buffer+=String.fromCharCode((bits & 0xff0000) >>16,(bits & 0xff00) >> 8,bits & 0xff);
  }

  if (str_input.charCodeAt(i-2)==61) {
    decode = buffer.substring(0,buffer.length-2);
  } else if (str_input.charCodeAt(i-1)==61) {
    decode = buffer.substring(0,buffer.length-1);
  } else {
    decode = buffer;
  }

  return decode;
}

/**
 * Function used to toggle display of given div
 * @param {string} element
 */
function toggle_element(element) { 
	$(element).style.display = ($(element).style.display == 'none' ? 'block' : 'none');
}

/**
 * Function to trim whitespace
 * @param {string} text
 * @return {string} text
 */
function trim(text) {
	return (text ? (text).toString().replace(/^\s+|\s+$/g, '') : '');
}

/**
 * Cross browser function used to add an option to a given select list
 * @param {object} select_element
 * @param {object} new_option
 */
function add_option(select_element, new_option) {
	//try DOM2 method first
	try {
			select_element.add(new_option, null);
	} catch (e) {
			//if that doesn't work use the internet explorer only method
			select_element.add(new_option, select_element.length);
	}
}

/**
 * Function to remove all options for a given select list
 * @param {object} element
 */
function remove_all_options(element) {
	var orig = element;
	element = $(element);

	if (element) {
			element.options.length = 1;
	}
}

/**
 * Function to format a string as currency with dollar sign, etc.
 * @param {mixed} number
 * @return {string}
 */
function format_currency(number) {
	number = number.toString().replace(/\$|\,/g,'');

	if(isNaN(number))
			number = "0";
	var sign = (number == (number = Math.abs(number)));
	number = Math.floor(number*100+0.50000000001);
	var cents = number%100;
	number = Math.floor(number/100).toString();

	if (cents < 10) {
			cents = "0" + cents;
	}//if (cents < 10)

	for (var i = 0; i < Math.floor((number.length-(1+i))/3); i++) {
			number = number.substring(0,number.length-(4*i+3)) + ',' + number.substring(number.length-(4*i+3));
	}//for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)

	return (((sign) ? '' : '-') + '$' + number + '.' + cents);
}

/**
 * Completely removes element from the document and returns it.
 * Original code taken from {@link http://www.prototypejs.org/api/element/remove}
 * @param {string} element
 * @return {object} element
 */
function remove(element) {
	if ($(element)) {
			element = $(element);
			element.parentNode.removeChild(element);
	}
}

/**
 * Scrolls the window so that element appears at the top of the viewport.
 * Original code taken from {@link http://www.prototypejs.org/api/element/scrollto}
 * @param {string} element
 * @return {object} element
 */
function scroll_to(element) {
	element = $(element);
	var pos_t = 0;
	var pos_l = 0;

	do {
		pos_t += element.offsetTop || 0;
		pos_l += element.offsetLeft || 0;
		element = element.offsetParent;
	} while (element);

	window.scrollTo(pos_l, pos_t);
	return element;
}

/**
 * Cross browser function to set our opacity for a given element
 * @param {string} element
 * @param {float} opacity
 */
function set_opacity(element, opacity) {
	element = $(element);

	// We need to handle opacity special in IE
	var user_agent = navigator.userAgent.toLowerCase();
	if (/msie/.test(user_agent) && !/opera/.test(user_agent)) {
			// IE has trouble with opacity if it does not have layout
			if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1;
			element.style.filter = (parseInt(opacity) + '' == 'NaN' ? '' : 'alpha(opacity=' + (opacity * 100) + ')');
	} else {
			element.style.opacity = (parseFloat(opacity) == 'NaN' ? '' : opacity);
	}
}

/**
 * Collects all of element's next siblings and returns them as an array of elements.
 * Original code taken from:
 * {@link http://www.prototypejs.org/api/element/nextSiblings}
 * {@link http://www.prototypejs.org/api/element/recursivelyCollect}
 * @param {string} element
 * @return {array} elements
 */
function next_siblings(element) {
	element = $(element);
	var elements = [];
	while ((element = element['nextSibling'])) {
		if (element.nodeType == 1) {
			elements.push($(element));
		}
	}
	return elements;
}

/**
 * Collects all of the element's children and returns them as an array of extended elements.
 * Original code taken from {@link http://www.prototypejs.org/api/element/childElements}
 * @param element
 * @return {array}
 */
function child_elements(element) {
	if (!(element = $(element).firstChild)) return [];
	while (element && element.nodeType != 1) element = element.nextSibling;
	if (element) return [element].concat(next_siblings(element));
	return [];
}

/**
 * Returns a list of child nodes with the supplied class name.
 * Original code taken from {@link http://snipplr.com/view/1696/get-elements-by-class-name/}
 */
function get_elements_by_class_name(classname, node)  {
    if(!node) node = document.getElementsByTagName("body")[0];
    var a = [];
    var re = new RegExp('\\b' + classname + '\\b');
    var els = node.getElementsByTagName("*");
    for(var i=0,j=els.length; i<j; i++)
        if(re.test(els[i].className))a.push(els[i]);
    return a;
}

/**
 * Function used to return an array from a passed in delimeted string
 * @param {string} item
 * @param {string} delimiter
 * @return {array}
 */
function explode_array(item, delimiter) {
	var temp_array = new Array(1);
	var count = 0;
	var temp_string = new String(item);

	while (temp_string.indexOf(delimiter)>0) {
			temp_array[count] = temp_string.substr(0,temp_string.indexOf(delimiter));
			temp_string = temp_string.substr(temp_string.indexOf(delimiter) + 1, temp_string.length - temp_string.indexOf(delimiter) + 1);
			count = count + 1
	}

	temp_array[count] = temp_string;
	return temp_array;
}

/**
 * Function used to open new window
 * @param {string} url
 * @param {string} window_name
 * @param {string} window_options
 */
function open_window(url, window_name, window_options) {
	window.open(url, window_name, window_options);
}

/**
 * Function used to retrieve a specified url querystring variable
 * @param {string} name
 * @return {string}
 */
function get_url_parameter(name) {
	name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	var regex_s = "[\\?&]" + name + " = ([^&#]*)";
	var regex = new RegExp(regex_s);
	var results = regex.exec(window.location.href);
	return ((results == null) ? '' : results[1]);
}

/**
 * Function used to write our breadcrumb contents to our page
 * @param {string} text
 */
function write_breadcrumb(text) {
	var breadcrumb = $('bread-crumbs');
	(breadcrumb) ? breadcrumb.innerHTML = '<b>' + text + '</b>' : '';
}

/**
 * Function used to toggle our expand/collapse class for a given element
 * @param {string} element
 */
function toggle_expand_collapse(element) {
	element = $(element);
	element.className = (element.className == 'expand') ? 'collapse' : 'expand';
}

/**
 * A Javascript equivalent of the PHP function print_r
 * Prints human-readable information about a variable
 * Original code taken from comments at {@link http://www.brandnewbox.co.uk/articles/details/a_print_r_equivalent_for_javascript/}
 * @param {object} theObj
 * @param {string} indent
 */
function print_r(theObj, indent) {
	var output = ""; 
	if (indent == undefined) {
		indent = " "; 
	} else { 
		indent += " ";
	}
	
	if (theObj.constructor == Array || theObj.constructor == Object) { 
		for(var p in theObj){ 
			if(theObj[p].constructor == Array|| theObj[p].constructor == Object){ 
				var type = (theObj[p].constructor == Array) ? "Array" : "Object"; 
				output += indent + "[" + p + "](" + type + ")=>\n"; 
				output += print_r(theObj[p], indent);
			} else { 		
				output += indent + "[" + p + "]:" + theObj[p] + "\n";
			}
		} 
	} 
	return output; 
}

//-- VALIDATION FUNCTIONS --//

/**
 * Returns true if mixed_var is of type string, false otherwise.
 * Original code taken from {@link http://www.prototypejs.org/api/object/isstring}
 * @param {mixed} mixed_var
 * @return {boolean}
 */
function is_string(mixed_var) {
	return (typeof(mixed_var) == 'string');
}

/**
 * Returns true if mixed_var is of type integer, false otherwise.
 * @param {mixed} mixed_var
 * @return {boolean}
 */
function is_integer(mixed_var) {
	var regex = /^[-+]?[1-9]\d*$/;
	return (regex.test(mixed_var) ? true : false);
}

/**
 * Returns true if mixed_var is of type float, false otherwise.
 * @param {mixed} mixed_var
 * @return {boolean}
 */
function is_float(mixed_var) {
	var regex = /^[-+]?\d*\.?\d*$/;
	return (regex.test(mixed_var) ? true : false);
}

/**
 * Returns true if mixed_var is of type currency, false otherwise.
 * @param {mixed} mixed_var
 * @return {boolean}
 */
function is_currency(mixed_var) {
	var regex =/^\$?(\d{1,3},?(\d{3},?)*\d{3}(\.\d{0,2})?|\d{1,3}(\.\d{0,2})?|\.\d{1,2}?)$/;
	return (regex.test(mixed_var) ? true : false);
}

/**
 * Returns true if mixed_var is of type email, false otherwise.
 * @param {mixed} mixed_var
 * @return {boolean}
 */
function is_email(mixed_var) {
	var regex=/^[a-zA-Z0-9._-]+@([a-zA-Z0-9.-]+\.)+[a-zA-Z0-9.-]{2,4}$/;
	return (regex.test(mixed_var) ? true : false);
}

/**
 * Returns true if mixed_var is of type date, false otherwise.
 * @param {mixed} mixed_var
 * @return {boolean}
 */
function is_date(mixed_var) {
	var regex=/^\d{1,2}\/\d{1,2}\/\d{4}$/;
	return (regex.test(mixed_var) ? true : false);
}

/**
 * Returns true if mixed_var is of type postal code, false otherwise.
 * @param {mixed} mixed_var
 * @return {boolean}
 */
function is_postalcode(mixed_var) {
	var regex=/^\d{5}-\d{4}|\d{5}|[A-Z]\d[A-Z] \d[A-Z]\d$/;
	return (regex.test(mixed_var) ? true : false);
}

/**
 * Returns true if mixed_var is of type phone, false otherwise.
 * @param {mixed} mixed_var
 * @return {boolean}
 */
function is_phone(mixed_var) {
	var regex=/^([a-zA-Z,#\/ \.\(\)\-\+\*]*[0-9]){7}[0-9a-zA-Z,#\/ \.\(\)\-\+\*]*$/;
	return (regex.test(mixed_var) ? true : false);
}

/**
 * Function used to validate form - uses our own custom attributes for determinig required fields, types to validate, etc.
 * @param {object} the_form
 * @return {boolean}
 */
function validate_form(the_form) {
	the_form = $(the_form);

	//default, all fields are required
	for (i = 0; i < the_form.length; i++) {
		if (the_form[i].id != '' && the_form[i].type != 'hidden') {
			if (the_form[i].type == 'select-one') {
				if (the_form[i].getAttribute('required') == 'required' && !the_form[i].selectedIndex > 0) {
					alert(($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + ' is required.');
					the_form[i].focus();
					return false;
				}
			} else if (the_form[i].type == 'radio' || the_form[i].type == 'checkbox' && the_form[i].getAttribute('required') == 'required') {
				//we need to ensure that at least on of our radio options is checked
				var radio_group = the_form[i].name;
				var checked = false;
				var inputs = the_form.getElementsByTagName('input');
				for (var i = 0, length = inputs.length; i < length; i++) {
					if (inputs[i].type == 'radio') {
						if (inputs[i].checked) {
								checked = true;
						}
					}
				}
	
				if (!checked) {
					alert(($('lbl_' + radio_group) ? $('lbl_' + radio_group).innerHTML : radio_group) + ' is required.');
					return false;
				}
			} else {
				if (the_form[i].getAttribute('required') == 'required') {
					switch (the_form[i].getAttribute('datatype')) {
						case 'integer':
								if (trim(the_form[i].value) == '' || !is_integer(the_form[i].value)) {
										alert(($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + ' must be an integer value.');
										the_form[i].focus();
										return false;
								}
								break;
						case 'float':
								if (trim(the_form[i].value) == '' || !is_float(the_form[i].value)) {
										alert(($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + ' must be a float value.');
										the_form[i].focus();
										return false;
								}
								break;
						case 'currency':
								if (trim(the_form[i].value) == '' || !is_currency(the_form[i].value)) {
										alert(($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + ' must be a currency value.');
										the_form[i].focus();
										return false;
								}
								break;
						case 'email':
								if (trim(the_form[i].value) == '' || !is_email(the_form[i].value)) {
										alert('Please enter a valid email address for ' + ($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + '.');
										the_form[i].focus();
										return false;
								}
								break;
						case 'date':
								if (trim(the_form[i].value) == '' || !is_date(the_form[i].value)) {
										alert('Please enter a valid date for ' + ($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + ' in the format (mm/dd/yyyy).');
										the_form[i].focus();
										return false;
								}
								break;
						case 'zip_code':
								if (trim(the_form[i].value) == '' || !is_postalcode(the_form[i].value)) {
										alert('Please enter a valid postal code for ' + ($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + '.');
										the_form[i].focus();
										return false;
								}
								break;
						case 'phone':
								if (trim(the_form[i].value) == '' || !is_phone(the_form[i].value)) {
										alert('Please enter a valid phone number for ' + ($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + '.');
										the_form[i].focus();
										return false;
								}
								break;
						case 'string':
						default:
								if (trim(the_form[i].value) == '' || !is_string(the_form[i].value)) {
										alert(($('lbl_' + the_form[i].id) ? $('lbl_' + the_form[i].id).innerHTML : the_form[i].id) + ' is required.');
										the_form[i].focus();
										return false;
								}
								break;
					}//switch (the_form[i].getAttribute('datatype'))
				}//if (the_form[i].getAttribute('required') == 'required')
			}//if (the_form[i].type == 'select-one')
		}//if (the_form[i].id != '' && the_form[i].type != 'hidden')
	}//for (i = 0; i < the_form.length; i++)

	return true;
}

/**
 * Function used to validate our distributor search form
 * for valid search combinations, either zip code or 
 * city & state are required
 * @param {object} the_form
 * @return {boolean}
 */
function validate_search(the_form) {	
	if ((the_form.zip.value.length < 5 || trim(the_form.zip.value) == '' || !is_postalcode(trim(the_form.zip.value))) && (the_form.city.value.length == 0 && the_form.state.selectedIndex == 0)) {
		alert("Please enter a valid zip code OR a valid city and state.");
		return false;
	} else {
		if (the_form.zip.value.length == 0) {
			if (the_form.city.value.length == 0 && the_form.state.selectedIndex == 0
				|| the_form.city.value.length > 0 && the_form.state.selectedIndex == 0
				|| the_form.state.selectedIndex > 0 && the_form.city.value.length == 0) {
				alert("Please enter the City and State or search by Zip code.");
				return false;
			}
		}
	}
	
	return true;
}

/**
 * Function to validate quantity field on our shopping cart page
 * @param {object} field
 * @param {boolean} in_cart
 * @return {boolean}
 */
function validate_quantity(field, in_cart) {
	var valid = '0123456789'
	var ok = 'yes';
	var temp;

	for (var i = 0; i < field.value.length; i++) {
		temp = '' + field.value.substring(i, i + 1);
		if (valid.indexOf(temp) == '-1') ok = 'no';
		if (field.value == '0') ok = 'no';
	}

	if (ok == 'no') {
			alert('Please enter a valid quantity.');

			//we need to set our cart qty for this item to the previous value (if updating from shopping cart)
			if (in_cart) {
				var id = field.id.toString().replace('cart_item_quantity_', '');
				field.value = $('_item_quantity_' + id).value;
			}

			field.select();
			return false;
	} else {
			return true;
	}
}

/**
 * Function used to validate our shopping cart order
 * @return {boolean}
 */
function validate_order() {
	var s_total = 0;
	var s_qty = 0;
	var items = $('cart-details').getElementsByTagName('input');
	var item_id = 0;

	//iterate through our hidden fields and get only our price and quantity fields (for calculating subtotal)
	for (var i = 0; i < items.length; i++) {
		if ((items[i].type == 'hidden') && (items[i].id != '') && (items[i].id.indexOf('_item_quantity_') != -1)) {
			item_id = items[i].id.toString().replace('_item_quantity_', '');
			s_qty += parseInt($('_item_quantity_' + item_id).value);
			s_total += (parseInt($('_item_quantity_' + item_id).value) * parseFloat($('_item_price_' + item_id).value));
		}
	}
	
	//let's cap our order somewhere?
	if (s_total > 1000000) { //set to 1 million
		alert('Please contact us to place your order');
		return false;
	} else {
		return true;
	}
}

/**
 * Check to ensure user selected all required configuration fields
 */
function validate_selections() {
	if (($('voltage').selectedIndex > 0) && ($('number_lamps').selectedIndex > 0) && ($('lamp_type').selectedIndex > 0) && ($('number_circuits').selectedIndex > 0)) {
		get_row_length_by_configuration();
	} else {
		remove_all_options($('length'));
		$('length').disabled = true;
		$('configure').disabled = true;
		$('results-div').innerHTML = '';
	}
}

/**
 * Function used to ensure user agrees to terms of use before downloading file (Alera specific - but copied to Columbia site so added here)
 * @return {boolean}
 */
function validate_agreement() {
	if (!($('agreement').checked)) {
		alert('You must agree to the terms of use agreement in order to download this file.');
		return false;
	} else {
		return true;
	}
}

/**
 * Function used to validate our password reset form (special because of confirm password)
 * @param {object} the_form
 * @return {boolean}
 */
function validate_password_reset_form (the_form) {
	//let's make sure the user entered a password and that the password
	//is at least 5 characters in length
	if (the_form.password.value.length < 5) {
		alert("Password must be at least 5 characters.");
		the_form.password.value = '';
		the_form.confirm_password.value = '';
		the_form.password.focus();
		return false;

	}

	//check confirm password field
	if (the_form.confirm_password.value.length < 5) {
		alert("Please confirm the password entered.");
		the_form.confirm_password.value = '';
		the_form.confirm_password.focus();
		return false;
	}

	//check to ensure the two passwords are identical
	if (the_form.password.value != the_form.confirm_password.value) {
		alert("The two passwords you entered do not match. Please re-enter your password.");
		the_form.password.value = '';
		the_form.confirm_password.value = '';
		the_form.password.focus();
		return false;
	}

	return true;
}

//-- CONTACT FORM FUNCTIONS --//

/**
 * Function used to process our contact forms, handles validation and
 * submission via ajax
 * @param {object} the_form
 * @return {boolean}
 */
function process_form(the_form) {
	if (validate_form(the_form)) {
		var object_array = new Array;
		
		for (i = 0; i < the_form.length; i++) {
			if (the_form[i].id != '' && the_form[i].type != 'reset' && the_form[i].type != 'submit') {
				var field_object = new Object;		
				field_object.id = the_form[i].id;
				field_object.label = ($('lbl_' + the_form[i].id) ? escape($('lbl_' + the_form[i].id).innerHTML) : '');
				field_object.value = escape(the_form[i].value);			
				field_object.required = the_form[i].getAttribute('required');
				field_object.datatype = the_form[i].getAttribute('datatype');
				field_object.type = the_form[i].type;					
				object_array[field_object.id] = field_object;
			}
		}
	
		alert('1/14/2009 - C.D.H.\n\nNeed to verify path for core form_processor.php page!');
		return false;
		
		var params = new Object();
		params._method = 'process_form_submission';
		params.data = json_encode(object_array);
			
		AjaxRequest.post({
			'url': '../../../core' + (aspb == 1 ? '_dev' : (aspb == 2 ? '_test' : (aspb == 3 ? '_qa' : '_prod'))) + '/includes/form_processor.php',
			'parameters': params,
			'onLoading': toggle_element('loading'),
			'onSuccess': function(t) {
				if (t.responseText != 1) {
					alert(t.responseText);
				} else {
					$('form-results').innerHTML = '<p>Thank you for your questions/comments.<br/>You will receive a reply from our respective department very soon.</p>';
					$('form-contents-div').style.display = 'none';
				}},
			'onError': function(t){alert('Ajax error:\n' + t.statusText);},
			'onComplete': toggle_element('loading')
		});
	}
			
	return false;
}
	
//-- SHOPPING CART FUNCTIONS --//

/**
 * Function used to add/update item in shopping cart. Checks to ensure
 * item isn't already in the cart, if so update routine runs
 * @param {integer} item_id
 */
function add_to_cart(item_id) {
	var total_items = $('total_items').value;
	var new_item_id = (parseInt(total_items) + 1);
	var item_name = ($('product_name_' + item_id) ? $('product_name_' + item_id).innerHTML : '');
	var item_number = ($('product_number_' + item_id) ? $('product_number_' + item_id).innerHTML : '');
	var item_description = $('product_description_' + item_id).innerHTML;
	var item_quantity = $('product_quantity_' + item_id).value;
	var item_price = ($('product_price_' + item_id).value / 100);
	var item_size = ($('product_size_' + item_id) ? $('product_size_' + item_id).value : '');

	if (item_quantity == '') {
		alert('Please enter a quantity for item: ' + item_name);
		return;
	}

	if ($('item_id_' + item_id + (item_size != '' ? '_' + item_size : ''))) {
		//item exists in cart already, update
		update_cart(item_id, $('item_id_' + item_id + (item_size != '' ? '_' + item_size : '')).value, item_quantity);
	} else {
		//item doesn't exist, add
		var row = build_shopping_cart_row(new_item_id, item_id, item_quantity, item_price, item_name, item_number, item_description, item_size);
		var target_element = $(total_items == 0 ? 'cart_header' : 'cart_item_' + total_items); //determine where to add
		var next = target_element.nextSibling;
		(next) ? target_element.parentNode.insertBefore(row, next) : target_element.parentNode.appendChild(row);
		
		//update total items in cart
		$('total_items').value = (parseInt(total_items)+parseInt(1));
		
		//update cart subtotal
		update_cart_subtotal();
	}

	//clear out our quantity
	$('product_quantity_' + item_id).value = '';

	//reset our size if applicable
	if (item_size != '') {
			$('product_size_' + item_id).selectedIndex = 0;
	}

	//scroll to our shopping cart details
	scroll_to('cart-details');
}

/**
 * Function to build our elements for a new shopping cart row
 * @param {integer} new_item_id
 * @param {integer} item_id
 * @param {integer} item_quantity
 * @param {string} item_price
 * @param {string} item_name Optional
 * @param {string} item_number Optional
 * @param {string} item_description
 * @param {string} item_size
 * @return {object} row
 */
function build_shopping_cart_row(new_item_id, item_id, item_quantity, item_price, item_name, item_number, item_description, item_size) {
	//Robin: "Holy Shit Batman! All this just to build our table row client side!!!"
	var row = '';
	var cell = '';
	var attribute = '';
	var link_node = '';
	var input = '';
	var image = '';
	row = document.createElement('tr');
	row.setAttribute('id', 'cart_item_' + new_item_id);
	row.setAttribute('class', 'cart-content');

	cell = document.createElement('td');
	cell.setAttribute('height', '30');

	link_node = document.createElement('a');
	link_node.setAttribute('href', 'javascript:void(0);');
	link_node.setAttribute('onclick', "scroll_to('product_" + item_id + "');");
	link_node.appendChild(document.createTextNode(((item_number != '') ? item_number + ' - ' + ((item_name != '') ? item_name : item_description) : '') + ((item_size != '') ? ' (' + item_size + ')' : '')));
	cell.appendChild(link_node);
	row.appendChild(cell);

	cell = document.createElement('td');
	cell.setAttribute('align', 'left');
	cell.setAttribute('height', '30');
	cell.appendChild(document.createTextNode(format_currency(item_price)));
	row.appendChild(cell);

	cell = document.createElement('td');
	cell.setAttribute('height', '30');

	input = document.createElement('input');
	input.setAttribute('type', 'hidden');
	input.setAttribute('id', 'item_id_' + item_id + (item_size != '' ? '_' + item_size : ''));
	input.setAttribute('name', 'item_id_' + item_id + (item_size != '' ? '_' + item_size : ''));
	input.setAttribute('value', new_item_id);
	cell.appendChild(input);

	input = document.createElement('input');
	input.setAttribute('type', 'hidden');
	input.setAttribute('id', 'item_name_' + new_item_id);
	input.setAttribute('name', 'item_name_' + new_item_id);
	input.setAttribute('value', (item_number != '' ? item_number : (item_name != '' ? item_name : item_description)));
	cell.appendChild(input);

	input = document.createElement('input');
	input.setAttribute('type', 'hidden');
	input.setAttribute('id', 'item_description_' + new_item_id);
	input.setAttribute('name', 'item_description_' + new_item_id);
	input.setAttribute('value', ((item_name != '') ? item_name : item_description) + ((item_size != '') ? ' (' + item_size + ')' : ''));
	cell.appendChild(input);

	input = document.createElement('input');
	input.setAttribute('type', 'hidden');
	input.setAttribute('id', 'item_quantity_' + new_item_id);
	input.setAttribute('name', 'item_quantity_' + new_item_id);
	input.setAttribute('value', item_quantity);
	cell.appendChild(input);

	input = document.createElement('input');
	input.setAttribute('type', 'hidden');
	input.setAttribute('id', 'item_price_' + new_item_id);
	input.setAttribute('name', 'item_price_' + new_item_id);
	input.setAttribute('value', item_price);
	cell.appendChild(input);

	input = document.createElement('input');
	input.setAttribute('type', 'text');
	input.setAttribute('id', 'cart_item_quantity_' + new_item_id);
	input.setAttribute('name', 'cart_item_quantity_' + new_item_id);
	input.setAttribute('value', item_quantity);
	input.setAttribute('size', '1');
	input.setAttribute('onchange', 'if(validate_quantity(this, true)){update_cart(' + item_id + ', ' + new_item_id + ', this.value, true);}');
	cell.appendChild(input);
	row.appendChild(cell);
	
	cell = document.createElement('td');
	cell.setAttribute('align', 'left');
	cell.setAttribute('height', '30');
	cell.setAttribute('id', 'cart_item_price_' + new_item_id);		
	cell.appendChild(document.createTextNode(format_currency(parseFloat(item_price) * parseInt(item_quantity))));
		
	row.appendChild(cell);

	cell = document.createElement('td');
	cell.setAttribute('height', '30');
	cell.setAttribute('align', 'center');

	image = document.createElement('img');
	image.setAttribute('src', 'images/merchandise-delete-icon.jpg');
	image.setAttribute('alt', 'Delete Item');
	
	link_node = document.createElement('a');
	link_node.setAttribute('href', 'javascript:remove_from_cart(' + new_item_id + ');');
	link_node.setAttribute('class', 'remove');
	link_node.appendChild(image);
	cell.appendChild(link_node);
	row.appendChild(cell);
	
	return row;
}

/**
 * Function used to update a single item in our shopping cart
 * @param {integer} item_id
 * @param {integer} cart_item - visible to user
 * @param {integer} quantity
 * @param {boolean} overwrite
 */
function update_cart(item_id, cart_item, quantity, overwrite) {	
	if (quantity != '') {
		//let's update our quantity for this item (since it already exists)
		var new_qty = (overwrite ? quantity : (parseInt($('item_quantity_' + cart_item).value) + parseInt(quantity)));
		var price = $('item_price_' + cart_item).value;

		$('cart_item_quantity_' + cart_item).value = new_qty;
		$('cart_item_price_' + cart_item).innerHTML = format_currency(new_qty * price);
		$('item_quantity_' + cart_item).value = new_qty;
	
		//update cart subtotal
		update_cart_subtotal();
	}
}

/**
 * Function to update our cart subtotal
 */
function update_cart_subtotal() {
	var c_image_style = (typeof(checkout_image_style) != 'undefined') ? checkout_image_style : 'white';
	var total_items = $('total_items').value;
	var s_total = 0;
	var s_qty = 0;
	var items = $('cart-details').getElementsByTagName('input');
	var item_id = 0;
	
	//iterate through our hidden fields and get only our price and quantity fields (for calculating subtotal)
	for (var i = 0, items_count = items.length; i < items_count; i++) {
		if ((items[i].type == 'hidden') && (items[i].id != '') && (items[i].id.indexOf('item_quantity_') != -1)) {
			item_id = items[i].id.toString().replace('item_quantity_', '');
			s_qty += parseInt($('item_quantity_' + item_id).value);
			s_total += (parseInt($('item_quantity_' + item_id).value) * parseFloat($('item_price_' + item_id).value));
		}
	}
	
	//format in readable format
	s_total = format_currency(s_total);
	
	//update our subtotal div
	$('cart_subtotal').innerHTML = '<strong>' + s_total + '</strong>';
	
	if (total_items == 0) {
		//disable our button
		$('btn-checkout').src = checkout_url + 'buttons/checkout.gif?merchant_id=' + merchant_id + '&w=160&h=43&style=' + c_image_style + '&variant=disabled&loc=en_US';
		$('btn-checkout').disabled = true;
	} else {
		//hide our empty cart row
		$('empty_cart').style.display = 'none';
	
		//enable our button
		$('btn-checkout').src = checkout_url + 'buttons/checkout.gif?merchant_id=' + merchant_id + '&w=160&h=43&style=' + c_image_style + '&variant=text&loc=en_US';
		$('btn-checkout').disabled = false;
	}
	
	$('cart-summary').innerHTML = '(' + s_qty + ') items in your cart ' + s_total;
}

/**
 * Function to remove all items from shopping cart
 */
function empty_cart() {
	var rows = get_elements_by_class_name('cart-content', $('cart-table'));
	var total_rows = parseInt(rows.length);

	//iterate through our shopping cart table and remove our items
	for (var i = 0; i < total_rows; i++) {
		if (rows[i].id.indexOf('cart_item_') != -1) {
			remove(rows[i].id);
		}
	}

	//update total items in cart
	$('total_items').value = 0;
	
	//update cart subtotal
	update_cart_subtotal();
	
	//show our empty cart row
	$('empty_cart').style.display = '';	
}

/**
 * Function to remove a single item from our shopping cart
 * @param {integer} item_id
 */
function remove_from_cart(item_id) {
	remove($('cart_item_' + item_id));
	
	//update total items in cart
	$('total_items').value = (parseInt($('total_items').value)-parseInt(1));
	
	//update cart subtotal
	update_cart_subtotal();
	
	if ($('total_items').value == 0) {
		//show our empty cart row
		$('empty_cart').style.display = '';
	}
}

//-- ROW LENGTH CONFIGURATOR FUNCTIONS --//
//-- These functions need to be moved to Alera's local functions.js file once we consolidate their site - no use in having it in the core --//


/**
 * Function to retrieve our product row length, outputs
 * results w/generated image to div
 */
function get_product_row_length() {
	$('results-div').innerHTML = '';
	var row_length = $('length').value;
	var product = $('product').value;
	
	if (product == '' || row_length == '') {
		alert('Please select a valid Product and Row Length');
		return;
	} else {
		//get our product row data
		var failure = function() {alert('Please consult factory.');}
		var success = function(t) {
			if (t.responseText == '') {
				alert('Please consult factory.');
			} else {
				$('results-div').innerHTML = t.responseText;
			}
		}
	
		var parameters = new Object();
		parameters._method = 'get_product_row_length';
		parameters.product = product;
		parameters.row_length = row_length;

		AjaxRequest.post({
			'url': 'includes/ajax.php',
			'parameters': parameters,
			'onLoading': toggle_element('loading'), //crl-loader
			'onSuccess': success,
			'onError': failure,
			'onComplete': toggle_element('loading') //crl-loader
		});
	}
}

/**
 * Function to retrieve our list of row lengths for the
 * selected configuration, populates our select list with
 * returned options
 */
function get_row_length_by_configuration() {
	//clear out our generated image
	$('results-div').innerHTML = '';

	//reset our length
	remove_all_options($('length'));
	$('length').disabled = true;
	$('configure').disabled = true;

	var voltage = $('voltage').value;
	var number_lamps = $('number_lamps').value;
	var lamp_type = $('lamp_type').value;
	var number_circuits = $('number_circuits').value;

	if (voltage == '' && number_lamps == '' && lamp_type == '' && number_circuits == '') {
			alert('Please select an option from each drop down menu');
			return;
	} else {
			var failure = function(t) {alert('Unable to retrieve available row length(s) for this product');$('length').disabled = true;}
			var success = function(t) {
					if (t.responseText == '') {
							alert('Unable to retrieve available row length(s) for this product');
							$('length').disabled = true;
					} else {
							var option_list = json_decode(t.responseText);
							var select_list = $('length');

							//let's iterate through our option items array
							for (var i = 0, option_list_count = option_list.length; i < option_list_count; i++) {
									add_option(select_list, new Option(option_list[i].row_length));
							}

							//enable our select list
							$('length').disabled = false;
					}
			}

			var parameters = new Object();
			parameters._method = 'get_row_length_by_configuration';
			parameters.voltage = voltage;
			parameters.number_lamps = number_lamps;
			parameters.lamp_type = lamp_type;
			parameters.number_circuits = number_circuits;

			AjaxRequest.post({
					'url': 'includes/ajax.php',
					'parameters': parameters,
					'onLoading': toggle_element('loading'), //crl-loader
					'onSuccess': success,
					'onError': failure,
					'onComplete': toggle_element('loading') //crl-loader
			});
	}
}

/**
 * Function used to retrieve configuration options by product, populates
 * series of select lists with default values for the selected product
 * @param {integer} product
 */
function get_configuration_list_by_product(product) {
	if (product != '') {
		//clear out our generated image
		if ($('results-div')) {
			$('results-div').innerHTML = '';
		}
	
		//remove our length options
		remove_all_options($('length'));
	
		if ($('length')) {
			//disable our field
			$('length').disabled = true;
		}
	
		if ($('configure')) {
			//disable our submit button
			$('configure').disabled = true;
		}
	
		var failure = function() {alert('Unable to retrieve row length configuration for this product');}
		var success = function(t) {
				if (t.responseText == '') {
						alert('Unable to retrieve row length configuration for this product');
				} else {
						//set our select list array
						var select_lists =  new Array($('voltage'), $('number_lamps'), $('lamp_type'), $('number_circuits'));
						var select_options = json_decode(t.responseText);
	
						//load our returned options for each select list
						for (var r = 0, select_list_count = select_lists.length; r < select_list_count; r++) {
								remove_all_options(select_lists[r].id);
	
								for (var i = 0, select_options_count = select_options[select_lists[r].id].length; i < select_options_count; i++) {
										add_option(select_lists[r], new Option(select_options[select_lists[r].id][i]));
								}
	
								//enable our select list
								select_lists[r].disabled = false;
						}
				}
		}
	
		var parameters = new Object();
		parameters._method = 'get_configuration_list_by_product';
		parameters.product = product;
	
		AjaxRequest.post({
				'url': 'includes/ajax.php',
				'parameters': parameters,
				'onLoading': toggle_element('loading'), //crl-loader
				'onSuccess': success,
				'onError': failure,
				'onComplete': toggle_element('loading') //crl-loader
		});
	} else {
		reset_row_configurator();
	}
}

/**
 * Function used to get our list of products for the select product type
 * @param {string} select_to_populate
 * @param {integer} product_type
 */
function get_product_list_by_type(select_to_populate, product_type) {
	if (product_type != '') {
		var success = function(t) {
			if (t.responseText == '') {
				alert('Unable to retrieve product(s) for this product type');
				$(select_to_populate).disabled = true;
			} else {
				//remove all our previously populated options
				remove_all_options(select_to_populate);
	
				var new_options = json_decode(t.responseText);
	
				//iterate through our objects and build out the retrieved options
				for (var i = 0; i < new_options.length; i++) {
						add_option($(select_to_populate), new Option(new_options[i].productnamedescr, new_options[i].idproductname));
				}
	
				//enable our select list
				$(select_to_populate).disabled = false;
				$('configure').disabled = false;
			}
		}
	
		var parameters = new Object();
		parameters._method = 'get_product_list_by_type';
		parameters.product_type = product_type;
	
		AjaxRequest.post({
				'url': 'includes/ajax.php',
				'parameters': parameters,
				'onLoading': toggle_element('loading'),//ps-loader
				'onSuccess': success,
				'onError': function(t) {alert('Unable to retrieve product(s) for this product type');$(select_to_populate).disabled = true;},
				'onComplete': toggle_element('loading')//ps-loader
		});
	} else {
		remove_all_options($(select_to_populate));
		$(select_to_populate).disabled = true;
		remove_all_options($('number_lamps'));
		$('number_lamps').disabled = true;
		$(select_to_populate).selectedIndex = 0;
	
		//disable our search button if we have nothing in our catalog number contains field
		if ($F('catalog_number').length == 0) {
			$('configure').disabled = true;
		}
	}
}

/**
 * Function used to retrieve row list by product and populate
 * the passed in select list with the results
 * @param {string} select_to_populate
 * @param {integer} product
 */
function get_product_row_list(select_to_populate, product) {
	//clear out our generated image
	$('results-div').innerHTML = '';
	
	if (product != '') {
		var failure = function(t) {alert('Unable to retrieve available row length(s) for this product');$(select_to_populate).disabled = true;}
		var success = function(t) {
				if (t.responseText == '') {
						alert('Unable to retrieve available row length(s) for this product');
						$(select_to_populate).disabled = true;
				} else {
						//remove all our previously populated options
						remove_all_options(select_to_populate);
	
						var new_options = json_decode(t.responseText);
	
						//iterate through our objects and build out the retrieved options
						for (var i = 0; i < new_options.length; i++) {
								add_option($(select_to_populate), new Option(new_options[i].productnamedescr, new_options[i].idproductname));
						}
	
						//enable our select list
						$(select_to_populate).disabled = false;
				}
		}
	
		var parameters = new Object();
		parameters._method = get_product_row_list;
		parameters.product = product;
	
		AjaxRequest.post({
			'url': 'includes/ajax.php',
			'parameters': parameters,
			'onLoading': toggle_element('loading'), //crl-loader
			'onSuccess': success,
			'onError': failure,
			'onComplete': toggle_element('loading') //crl-loader
		});
	} else {
		$(select_to_populate).disabled = true;
		$('doWork').disabled = true;
		$(select_to_populate).selectedIndex = 0;
		$('results-div').innerHTML = '';
	}
}

/**
 * Function used to toggle our row length configurator button
 * only show if user has selected the first set of options
 */
function toggle_row_length_configuration_button() {
	//clear out our generated image
	$('results-div').innerHTML = '';
	
	if ($('length').selectedIndex == 0) {
		$('configure').disabled = true;
	} else {
		$('configure').disabled = false;
	}
}

/**
 * Function used to reset our row length configurator options
 * back to the default settings
 */
function reset_row_configurator() {
	//set our product select menu to the first value
	$('product').selectedIndex = 0;
	
	//remove all our options
	remove_all_options($('voltage'));
	remove_all_options($('number_lamps'));
	remove_all_options($('lamp_type'));
	remove_all_options($('number_circuits'));
	remove_all_options($('length'));
	
	//disable our fields
	$('voltage').disabled = true;
	$('number_lamps').disabled = true;
	$('lamp_type').disabled = true;
	$('number_circuits').disabled = true;
	$('length').disabled = true;
	
	//clear our results div (image section)
	$('results-div').innerHTML = '';
	
	//disable our submit button
	$('configure').disabled = true;
}

//-- PHOTOMETRY SEARCH FUNCTIONS --//

/**
 * Reset our photometry search fields back to the defaults
 */
function reset_photometry_search() {
	$('product_type').selectedIndex = 0;
	remove_all_options($('product'));
	$('product').disabled = true;
	remove_all_options($('number_lamps'));
	$('number_lamps').disabled = true;
	$('catalog_number').value = '';
	$('search').disabled = true;
	$('results-div').innerHTML = '';
	$('product-image-div').innerHTML = '';	
}

/**
 * Function used to process our ajax photometry search
 * @param {string} siteurl
 */
function get_photometry_search(siteurl) {
	$('results-div').innerHTML = '';
	
	var product_type = $('product_type').value;
	var product = $('product').value;
	var number_lamps = $('number_lamps').value;
	var catalog_number = $('catalog_number').value;
	
	if (product_type == '' && product == '' && number_lamps == '' && catalog_number == '') {
			alert('Please select at least one search criteria.');
			return;
	} else {
			var success = function(t) {
					if (t.responseText == '') {
							alert('Please consult factory.');
					} else {
							var ds = json_decode(t.responseText);
	
							for (var i = 0, ds_count = ds.length; i < ds_count; i++) {
									$('results-div').innerHTML += '<div>' +
											'<strong>' + ds[i].catnum + '</strong><br />' +
											'<i>Description:&nbsp;</i>' + ds[i].lumdescr + '<br />' +
											'<i>Test Number:&nbsp;</i>' + ds[i].testnum + '&nbsp;&nbsp;<a href="' + siteurl + 'products/ies/ies_files/' + ds[i].testnum + '.IES" target="_blank">IES File</a>&nbsp;&nbsp;<a href="' + $rel + 'products/ies/ies_reports/' + ds[i].testnum + '.pdf" target="_blank">PDF Test Report</a>' +
											'</div>' +
											'<div class="spacer"><span>Spacer</span></div>';
	
							}
					}
			}
	
			var parameters = new Object();
			parameters._method = get_photometry_search;
			parameters.product_type = product_type;
			parameters.product = product;
			parameters.number_lamps = number_lamps;
			parameters.catalog_number = catalog_number;
	
			AjaxRequest.post({
					'url': 'includes/ajax.php',
					'parameters': parameters,
					'onLoading': toggle_element('ps-loader'),
					'onSuccess': success,
					'onError': function(){alert('Please consult factory.');},
					'onComplete': toggle_element('ps-loader')
			});
	}
}

/**
 * Function used to toggle our photometry search button, only show if user
 * has selected the first set of options
 */
function toggle_photometry_search_button() {
	var pt = $('product_type').value;
	var p = $('product').value;
	var nl = $('number_lamps').value;
	var cn = $('catalog_number').value;
	
	if (cn.length > 0) {
		$('search').enable();
	} else if (p == '' && pt == '' && nl == '' && cn == '') {
		$('search').disabled = true;
	}
}

//-- LIVE SEARCH FUNCTIONS --//

/**
 * Original code taken from {@link http://wiki.flux-cms.org/display/BLOG/LiveSearch}
 */ 
var liveSearchReq = false;
var t = null;
var liveSearchLast = "";
var isIE = false;

/**
 *
 */
function liveSearchInit() {	
	if (navigator.userAgent.indexOf("Safari") > 0) {
		$('livesearch').addEventListener("keydown",liveSearchKeyPress,false);
	} else if (navigator.product == "Gecko") {		
		$('livesearch').addEventListener("keypress",liveSearchKeyPress,false);
		$('livesearch').addEventListener("blur",liveSearchHideDelayed,false);
	} else {
		$('livesearch').attachEvent('onkeydown',liveSearchKeyPress);
		isIE = true;
	}
	$('livesearch').setAttribute("autocomplete","off");
}

/**
 *
 */
function liveSearchHideDelayed() {
	window.setTimeout("liveSearchHide()",200);
}

/**
 *
 */
function liveSearchHide() {
	$("search_results").style.display = "none";
	var highlight = $("LSHighlight");
	if (highlight) {
		highlight.removeAttribute("id");
	}
}

/**
 *
 */
function liveSearchKeyPress(event) {	
	if (event.keyCode == 40 ) {//KEY DOWN
		highlight = $("LSHighlight");
		if (!highlight) {
			highlight = $("search_results_shadow").firstChild.firstChild;
		} else {
			highlight.removeAttribute("id");
			highlight = highlight.nextSibling;
		}
		if (highlight) {
			highlight.setAttribute("id","LSHighlight");
		} 
		if (!isIE) { event.preventDefault(); }
	} else if (event.keyCode == 38 ) {//KEY UP
		highlight = $("LSHighlight");
		if (!highlight) {
			highlight = $("search_results").firstChild.firstChild.lastChild;
		} 
		else {
			highlight.removeAttribute("id");
			highlight = highlight.previousSibling;
		}
		if (highlight) {
				highlight.setAttribute("id","LSHighlight");
		}
		if (!isIE) { event.preventDefault(); }
	} else if (event.keyCode == 27) {//ESC
		highlight = $("LSHighlight");
		if (highlight) {
			highlight.removeAttribute("id");
		}
		$("search_results").style.display = "none";
	} else if (event.keyCode == 8 && isIE) {//BACKSPACE - required for IE
		liveSearchStart();
	}
}

/**
 *
 */
function liveSearchStart(site) {
	if (t) {
		window.clearTimeout(t);
	}
	t = window.setTimeout("liveSearchDoSearch('" + site + "')",200);
}

/**
 *
 */
function liveSearchDoSearch(site) {
	if (typeof(liveSearchRootSubDir) == "undefined") {
		liveSearchRootSubDir = "";
	}
	
	if (typeof(liveSearchParams) == "undefined") {
		liveSearchParams2 = "";
	} else {
		liveSearchParams2 = "&" + liveSearchParams;
	}
	
	if (liveSearchLast != document.forms.searchform.q.value) {
		if (liveSearchReq && liveSearchReq.readyState < 4) {
			liveSearchReq.abort();
		}
		
		if (document.forms.searchform.q.value == "") {
			liveSearchHide();
			liveSearchLast = "";
			return false;
		}

		var success = function(t) {
			var res = $("search_results");
			res.style.display = "block";
			var sh = $("search_results_shadow");
	
			if (trim(t.responseText) == '') {
				liveSearchHide();
			} else {
				sh.innerHTML = t.responseText;
			}
		}
		
		var parameters = new Object();
		parameters._method = 'product_search_suggest';
		parameters.q = document.forms.searchform.q.value;

		AjaxRequest.post({
						 'url': 'includes/ajax.php',
						 'parameters': parameters,
						 'onLoading': toggle_element('loading'),
						 'onSuccess': success,
						 'onError': function(){alert('Unable to retrieve list of products.')},
						 'onComplete': toggle_element('loading')						 
		});
	}
}

/**
 * 
 */
function liveSearchSubmit() {
	var highlight = $("LSHighlight");
	if (highlight && highlight.firstChild) {
		window.location = liveSearchRootSubDir + highlight.firstChild.nextSibling.getAttribute("href");
		return false;
	} 
	else {
		return true;
	}
}

function closeResults() {
	$("search_results").style.display = "none";
}

//-- QUICK SEARCH FUNCTIONS --//

/**
 * Client side recordset paging 
 * Original code taken from {@link http://www.4guysfromrolla.com/webtech/050901-1.shtml}
 */
var first, last, nav_first, nav_last, pre_first = 0, pre_last = 9;

/**
 * Function used to set our active paging links
 * @param string id
 */
function set_active(id) {
	//clear out any other active elements
	for (var i = 0; i < document.getElementById('search-nav-top').getElementsByTagName("a").length;i++) {
		document.getElementById('search-nav-top').getElementsByTagName("a")[i].className = "nav-paging";
	}
	
	for (var i = 0; i < document.getElementById('search-nav-bottom').getElementsByTagName("a").length;i++) {
		document.getElementById('search-nav-bottom').getElementsByTagName("a")[i].className = "nav-paging";		
	}	
	
	document.getElementById('navLinkT' + id).className = 'nav-paging-active';
	document.getElementById('navLinkB' + id).className = 'nav-paging-active';
}

/**
 * Function used to write out our previous/next links
 */
function nav() {
	//decode our results
	results = json_decode(results);	
    var str_nav_top = str_nav_bottom = nav_next = nav_previous = '', total_pages = Math.ceil(results.length / 10);

	//write out our page links
	for (var p = 0; p < total_pages; p++) {
		if (p == 0) {
			pre_first = 0;			
			pre_last = (((p + 1) >= total_pages) ? results.length : 9);
			
			nav_first = pre_first;
			nav_last = pre_last;			
			first = nav_first;
			last = nav_last;			
		} else {
			if ((p+1) >= total_pages) {
				pre_first = pre_last + 1;
				pre_last = results.length;
			} else {
				pre_first += 10;
				pre_last += 10;
			}
		}
			
		str_nav_top += "<a id=\"navLinkT" + p + "\" href=\"javascript:show_search_results(" + pre_first + "," + pre_last + ");set_active(" + p + ");\" class=\"nav-paging\">" + (p+1) + "</a>&nbsp;";
		str_nav_bottom += "<a id=\"navLinkB" + p + "\" href=\"javascript:show_search_results(" + pre_first + "," + pre_last + ");set_active(" + p + ");\" class=\"nav-paging\">" + (p+1) + "</a>&nbsp;";
	}
	
	//add our html to the page		
	document.getElementById('search-nav-top').innerHTML = str_nav_top;	
	document.getElementById('search-nav-bottom').innerHTML = str_nav_bottom;
}

/**
 * Drop Down Tabs Menu
 * Original code taken from {@link http://www.dynamicdrive.com/dynamicindex1/droptabmenu.htm}
 * 
 * Modification by mbdecker 2/16/08, see comments below for delayhidemnu()
 */

var tabdropdown={
	disappeardelay: 200, //set delay in miliseconds before menu disappears onmouseout
	disablemenuclick: false, //when user clicks on a menu item with a drop down menu, disable menu item's link?
	enableiframeshim: 1, //1 or 0, for true or false

	//No need to edit beyond here////////////////////////
	dropmenuobj: null, ie: document.all, firefox: $&&!document.all, previousmenuitem:null,
	currentpageurl: window.location.href.replace("http://"+window.location.hostname, "").replace(/^\//, ""), //get current page url (minus hostname, ie: http://www.dynamicdrive.com/)

	getposOffset:function(what, offsettype){
		var totaloffset=(offsettype=="left")? what.offsetLeft : what.offsetTop;
		var parentEl=what.offsetParent;
			while (parentEl!=null){
				totaloffset=(offsettype=="left")? totaloffset+parentEl.offsetLeft : totaloffset+parentEl.offsetTop;
				parentEl=parentEl.offsetParent;
			}
		return totaloffset;
	},

	showhide:function(obj, e, obj2){ //obj refers to drop down menu, obj2 refers to tab menu item mouse is currently over
		if (this.ie || this.firefox)
			this.dropmenuobj.style.left=this.dropmenuobj.style.top="-500px"
		if (e.type=="click" && obj.visibility==hidden || e.type=="mouseover"){
			if (obj2.parentNode.className.indexOf("default")==-1) //if tab isn't a default selected one
				obj2.parentNode.className="selected"
			obj.visibility="visible"
			}
		else if (e.type=="click")
			obj.visibility="hidden"
	},

	iecompattest:function(){
		return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
	},

	clearbrowseredge:function(obj, whichedge){
		var edgeoffset=0
		if (whichedge=="rightedge"){
			var windowedge=this.ie && !window.opera? this.standardbody.scrollLeft+this.standardbody.clientWidth-15 : window.pageXOffset+window.innerWidth-15
			this.dropmenuobj.contentmeasure=this.dropmenuobj.offsetWidth
		if (windowedge-this.dropmenuobj.x < this.dropmenuobj.contentmeasure)  //move menu to the left?
			edgeoffset=this.dropmenuobj.contentmeasure-obj.offsetWidth
		}
		else{
			var topedge=this.ie && !window.opera? this.standardbody.scrollTop : window.pageYOffset
			var windowedge=this.ie && !window.opera? this.standardbody.scrollTop+this.standardbody.clientHeight-15 : window.pageYOffset+window.innerHeight-18
			this.dropmenuobj.contentmeasure=this.dropmenuobj.offsetHeight
			if (windowedge-this.dropmenuobj.y < this.dropmenuobj.contentmeasure){ //move up?
				edgeoffset=this.dropmenuobj.contentmeasure+obj.offsetHeight
				if ((this.dropmenuobj.y-topedge)<this.dropmenuobj.contentmeasure) //up no good either?
					edgeoffset=this.dropmenuobj.y+obj.offsetHeight-topedge
			}
			this.dropmenuobj.firstlink.style.borderTopWidth=(edgeoffset==0)? 0 : "1px" //Add 1px top border to menu if dropping up
		}
		return edgeoffset
	},

	dropit:function(obj, e, dropmenuID){
		if (this.dropmenuobj!=null){ //hide previous menu
			this.dropmenuobj.style.visibility="hidden" //hide menu
			if (this.previousmenuitem!=null && this.previousmenuitem!=obj){
				if (this.previousmenuitem.parentNode.className.indexOf("default")==-1) //If the tab isn't a default selected one
					this.previousmenuitem.parentNode.className=""
			}
		}
		this.clearhidemenu()
		if (this.ie||this.firefox){
			obj.onmouseout=function(){tabdropdown.delayhidemenu(obj)}
			obj.onclick=function(){return !tabdropdown.disablemenuclick} //disable main menu item link onclick?
			this.dropmenuobj=$(dropmenuID)
			this.dropmenuobj.onmouseover=function(){tabdropdown.clearhidemenu()}
			this.dropmenuobj.onmouseout=function(e){tabdropdown.dynamichide(e, obj)}
			this.dropmenuobj.onclick=function(){tabdropdown.delayhidemenu(obj)}
			this.showhide(this.dropmenuobj.style, e, obj)
			this.dropmenuobj.x=this.getposOffset(obj, "left")
			this.dropmenuobj.y=this.getposOffset(obj, "top")
			this.dropmenuobj.style.left=this.dropmenuobj.x-this.clearbrowseredge(obj, "rightedge")+"px"
			this.dropmenuobj.style.top=this.dropmenuobj.y-this.clearbrowseredge(obj, "bottomedge")+obj.offsetHeight+1+"px"
			this.previousmenuitem=obj //remember main menu item mouse moved out from (and into current menu item)
			this.positionshim() //call iframe shim function
		}
	},

	contains_firefox:function(a, b) {
		while (b.parentNode)
		if ((b = b.parentNode) == a)
			return true;
		return false;
	},

	dynamichide:function(e, obj2){ //obj2 refers to tab menu item mouse is currently over
		var evtobj=window.event? window.event : e
		if (this.ie&&!this.dropmenuobj.contains(evtobj.toElement))
			this.delayhidemenu(obj2)
		else if (this.firefox&&e.currentTarget!= evtobj.relatedTarget&& !this.contains_firefox(evtobj.currentTarget, evtobj.relatedTarget))
			this.delayhidemenu(obj2)
	},

	delayhidemenu:function(obj2){
		/*
			Changed this line by adding "tabdropdown.hideshim();" call.  The hideshim function was not being callsed
			which caused the iFrame to not be visible, but remain in the document flow in IE6.  This prevented users
			from clicking links that were hidden behind the invisible iframe
		*/
		this.delayhide=setTimeout(function(){tabdropdown.hideshim(); tabdropdown.dropmenuobj.style.visibility='hidden'; if (obj2.parentNode.className.indexOf('default')==-1) obj2.parentNode.className=''},this.disappeardelay) //hide menu
	},

	clearhidemenu:function(){
		if (this.delayhide!="undefined")
			clearTimeout(this.delayhide)
	},

	positionshim:function(){ //display iframe shim function
		if (this.enableiframeshim && typeof this.shimobject!="undefined"){
			if (this.dropmenuobj.style.visibility=="visible"){
				this.shimobject.style.width=this.dropmenuobj.offsetWidth+"px"
				this.shimobject.style.height=this.dropmenuobj.offsetHeight+"px"
				this.shimobject.style.left=this.dropmenuobj.style.left
				this.shimobject.style.top=this.dropmenuobj.style.top
			}
		this.shimobject.style.display=(this.dropmenuobj.style.visibility=="visible")? "block" : "none"
		}
	},

	hideshim:function(){
		if (this.enableiframeshim && typeof this.shimobject!="undefined")
			this.shimobject.style.display='none'
	},

	isSelected:function(menuurl){
		menuurl = menuurl.replace("http://"+menuurl.hostname, "").replace(/^\//, "");
		return (tabdropdown.currentpageurl==menuurl);
	},

	init:function(menuid, dselected){
		if (defined($(menuid))) {
			this.standardbody=(document.compatMode=="CSS1Compat")? document.documentElement : document.body //create reference to common "body" across doctypes
			var menuitems=$(menuid).getElementsByTagName("a")
			for (var i=0; i<menuitems.length; i++){
				if (menuitems[i].getAttribute("rel")){
					var relvalue=menuitems[i].getAttribute("rel")
					$(relvalue).firstlink=$(relvalue).getElementsByTagName("a")[0]
					menuitems[i].onmouseover=function(e){
						var event=typeof e!="undefined"? e : window.event
						tabdropdown.dropit(this, event, this.getAttribute("rel"))
					}
				}
				if (dselected=="auto" && typeof setalready=="undefined" && this.isSelected(menuitems[i].href)){
					menuitems[i].parentNode.className+=" selected default"
					var setalready=true
				}
				else if (parseInt(dselected)==i)
					menuitems[i].parentNode.className+=" selected default"
			}
			
			if (this.enableiframeshim && document.all && !window.XDomainRequest && !this.iframeshimadded){ //enable iframe shim in IE5.5 thru IE7?
				document.write('<IFRAME id="iframeshim" src="about:blank" frameBorder="0" scrolling="no" style="left:0; top:0; position:absolute; display:none;z-index:90; background: transparent;"></IFRAME>')
				this.shimobject=document.getElementById("iframeshim") //reference iframe object
				this.shimobject.style.filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
				this.iframeshimadded=true
			}			
		}
	}
}
