// set a cookie
	
	// 02/15/03 - initial development
	// 05/14/04 - expanded to allow saving multiple values within a single cookie

	function set_cookie(name, key, value) {

		// specify a default cookie name prefix for this project, to group cookies together
		name_prefix = "";
		value_exists = 0;
		
		// the following cookie parameters are optional ... change values to null if you don't need them
		hours = null;
		path = cookie_path;						
		domain = null;
		
		cookie_value = get_cookie(name, "all"); // get the entire cookie string so we can update the values
		key_value_array = cookie_value.split("&"); // split the cookie string into an array of key=value strings
		
		// search through the list of key=value strings for the presence of the specified key
		for (key_value=0; key_value<key_value_array.length; key_value++) {
			if (key_value_array[key_value].indexOf(key + "=") == 0) {
			
				// when we find it, overwrite the value of that array element
				key_value_pair = key_value_array[key_value].split("=");
				key_value_key = key_value_pair[0];
				key_value_array[key_value] = key_value_key + "=" + escape(value);
				
				// then combine the key=value strings back into a single string
				cookie_value = key_value_array.join('&');
				value_exists = 1; // flag this key as already being in the cookie string so that you don't add it to the cookie string again
				break;

			}
		}
		
		// if the cookie string doesn't already contain this key, add the key=value string
		if (value_exists == 0) {
			ampersand = (cookie_value != "") ? "&" : "" ;
			cookie_value += ampersand + key + "=" + escape(value);
		}
		
		expiration_date = (hours) ? new Date((new Date()).getTime() + hours*3600000).toGMTString() : false ;
		cookie_string = name_prefix + name + "=" + escape(cookie_value) + ((expiration_date)?(';expires=' +expiration_date):'') + ((path)?(';path='+path):'') + ((domain)?(';domain='+domain):'');
		document.cookie = cookie_string;
	
	}


// get values from a cookie

	// 02/15/03 - initial development
	// 05/14/04 - expanded to allow saving multiple values within a single cookie

	function get_cookie(name, key) {
	
		name_prefix = ""; // specify a default cookie name prefix for this project, to group cookies together
		output_value = "";
		
		if (document.cookie != "") {
			cookie_array = document.cookie.split("; ");

			// search for the cookie with this name
			for (cookie=0; cookie < cookie_array.length; cookie++) {
				if (cookie_array[cookie].indexOf(name_prefix + name + "=") == 0) {

					cookie_pair = cookie_array[cookie].split("=");
					cookie_value = unescape(cookie_pair[1]); // the value is the list of key=value strings that we saved into this cookie
	
					if (key == "all") {
						output_value = cookie_value;
						break;
					} else {
						key_value_array = cookie_value.split("&");
					
						// search through the list of key=value strings for the value of the requested key
						for (key_value=0; key_value<key_value_array.length; key_value++) {
							if (key_value_array[key_value].indexOf(key + "=") == 0) {
							
								key_value_pair = key_value_array[key_value].split("=");
								output_value = unescape(key_value_pair[1]);
								break;
										
							}	
						}
						
					}
					
				}
			}
			
		}
		
		return output_value;
		
	}
	
	
// open a popup window, specifying source, width, and height, and optionally a name; if no name, choose a random one

	function popup(source, width, height, window_name) {
		if (! window_name) { 
			now = new Date();
			window_name = now.getTime();
		} else {
			window_name = window_name.replace(/ /g, "_");
		}
		popup_window = window.open(source, window_name, "width=" + String(width) + ",height=" + String(height) + ",location=no,menubar=no,directories=no,toolbar=no,scrollbars=yes,resizable=yes,status=yes");
		popup_window.focus();
		// return popup_window; // oops, this creates a weird behavior in Firefox and Win/IE
	}


// ajax functions
// ajax_request currently only supports asynchronous connections

	function ajax_initialize() {
		ajax = "";
		if (typeof(XMLHttpRequest) != "undefined") {
			ajax = new XMLHttpRequest();
		} else {
			// need to check for additional versions here?
			ajax = new ActiveXObject("Microsoft.XMLHTTP");
		}
		return ajax;
	}
	
	function ajax_request(URL, success_code, failure_code, method, mode, data) {
		// method: GET or POST
		// mode: text or XML
		// data: query string
	
		// in IE, we have to initialize before every request or subsequent request don't call the monitor
		ajax_initialize();
		
		// set some defaults
		if (!failure_code) { failure_code = "alert('There was a problem with the AJAX request.');"; }
		if (!method) { method = "GET"; }
		if (!mode) { mode = "text"; }
		
		// if we're using the GET method but passing in data, add it to the URL
		if ((method == "GET")&&(data)) {
			delimiter = (URL.indexOf("?") != -1) ? "&" : "?" ;
			URL += delimiter + data;
		}
		
		// pass this function's arguments through so the monitor function can see them
		success_code_passthrough = success_code;
		failure_code_passthrough = failure_code;
		mode_passthrough = mode;
		
		// perform the request
		ajax.onreadystatechange = ajax_monitor;
		ajax.open(method, URL, true);
		ajax.setRequestHeader("Ajax-Request", "1");
		if (method == "POST") {
			ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        	ajax.send(data);
		} else {
        	ajax.send(null);
        }
	}
	
	function ajax_monitor() {
		if (ajax.readyState == 4) {
			if (ajax.getResponseHeader("Ajax-Redirect")) {
				top.location = ajax.getResponseHeader("Ajax-Redirect");
			} else {
				if (ajax.status == 200) {
					if (mode_passthrough == "XML") {
						ajax_response = ajax.responseXML;
					} else {
						ajax_response = ajax.responseText;
					}
					eval(success_code_passthrough);
				} else {
					ajax_response = ajax.statusText;
					eval(failure_code_passthrough);
				}
			}
		}
	}
	
	function ajax_serialize(input, encode) {
		// convert an object into a string of name/value pairs for including in an HTTP request
		// we need to encode POST values, but not GET values
		output = new Array();
		for (key in input) {
			value = input[key];
			if (encode) {
				value = encodeURIComponent(value);
			}
			output[output.length] = key + "=" + value;
		}
		output = output.join("&");
		return output;
	}
	
	function ajax_unserialize(input, decode) {
		// convert a string of name/value pairs into an object for retrieving from an HTTP response
		input = input.split("&");
		output = new Object();
		for (n=0; n < input.length; n++) {
			pair = input[n].split("=");
			key = pair[0];
			value = pair[1];
			if (decode) {
				value = decodeURIComponent(value);
			}
			output[key] = value;
		}
		return output;
	}

// figure out whether a variable has been set or not without generating an undefined error if it hasn't
// possible types are "undefined", "object", "boolean", "number", "string" or "function", with everything else being "object"
// this does not work on function arguments inside a function; even if the argument is set, this still returns false
// but in that case we can just check for a value without getting an error

	function isset(variable, type) {
		if (type) {
			eval("result = (typeof(" + variable + ") == type)");
		} else {
			eval("result = (typeof(" + variable + ") != 'undefined')");
		}
		return result;
	}
	

// returns the index of an array element, something that ought to be built into JavaScript but isn't!
// returns -1 if not present

	function get_position(string, array) {
		count = array.length;
		for (n=0; n < count; n++) {
			if (array[n] == string) {
				return n;
				break;
			}
		}
		return -1;
	}


// sets a menu to a given text or value

	function set_menu(form_name, field_name, text_or_value, key) {
		eval("these_options = document." + form_name + "." + field_name + ".options");
		for (n=0; n < these_options.length; n++) {
			eval("this_text_or_value = these_options[n]." + text_or_value);
			if (this_text_or_value == key) {
				eval("document." + form_name + "." + field_name + ".selectedIndex = " + n);
				break;
			}
		}
		return "";
	}


// sets a radio button to a given value (we can't set the text of radio buttons)

	function set_radio(form_name, field_name, value) {
		eval("these_elements = document." + form_name + "." + field_name);
		for (n=0; n < these_elements.length; n++) {
			eval("this_value = these_elements[n].value");
			if (this_value == value) {
				these_elements[n].checked = true;
				break;
			}
		}
		return "";
	}


// sets a checkbox group to a given value (we can't set the text of checkboxes)

	function set_checkbox(form_name, field_name, value, checked) {
		eval("these_elements = document." + form_name + ".elements['" + field_name + "']");
		if (these_elements.length > 0) {
			for (n=0; n < these_elements.length; n++) {
				eval("this_value = these_elements[n].value");
				if (this_value == value) {
					these_elements[n].checked = checked;
					break;
				}
			}
		} else {
			eval("this_value = these_elements.value");
			if (this_value == value) {
				these_elements.checked = checked;
			}
		}
		return "";
	}


// set date menus to a new SQL-standard date
// leave date blank to select today's date
// set to -1 to clear the menu

	function select_date(form_and_menu, new_date) {
		if (new_date != "-1") {
			if (new_date == "") {
				date = new Date();
				
				day = date.getDate();
				month = date.getMonth() + 1;
				year = date.getFullYear();
				
			} else {
				date = new_date;
				
				year = date.substring(0, date.indexOf("-"));
				month = date.substring(date.indexOf("-") + 1, date.lastIndexOf("-"));
				day = date.substring(date.lastIndexOf("-") + 1);
				
			}
					
			eval("document." + form_and_menu + "_month.selectedIndex = month");
			eval("document." + form_and_menu + "_day.selectedIndex = day");
			eval("document." + form_and_menu + "_year.selectedIndex = year - document." + form_and_menu + "_year.options[1].value + 1");
		} else {
			eval("document." + form_and_menu + "_month.selectedIndex = 0");
			eval("document." + form_and_menu + "_day.selectedIndex = 0");
			eval("document." + form_and_menu + "_year.selectedIndex = 0");
		}
	}


// set time menus to a new SQL-standard time
// leave time blank to select the current time
// set to -1 to clear the menu

	function select_time(form_and_menu, new_time, increment) {
		if (new_time != "-1") {
			if (new_time == "") {
				time = new Date();
				
				hours = time.getHours();
				minutes = time.getMinutes();
				seconds = time.getSeconds();

			} else {
				time = new_time;
				
				hours = time.substring(0, time.indexOf(":"));
				minutes = time.substring(time.indexOf(":") + 1, time.lastIndexOf(":"));
				seconds = time.substring(time.lastIndexOf(":") + 1);
				
			}
			
			if (hours >= 12) {
				ampm_index = 2;
				if (hours > 12) {
					hours = hours - 12;
				}
			} else {
				ampm_index = 1;
				if (hours == 0) {
					hours = 12;
				}
			}
			
			if (increment) {
				// this assumes that the increment is for minutes only and not for seconds
				minutes = Math.floor(minutes / increment);
			}
			
			eval("document." + form_and_menu + "_hours.selectedIndex = hours");
			eval("document." + form_and_menu + "_minutes.selectedIndex = minutes + 1");
			eval("document." + form_and_menu + "_seconds.selectedIndex = seconds + 1");
			eval("document." + form_and_menu + "_ampm.selectedIndex = " + ampm_index);
		} else {
			eval("document." + form_and_menu + "_hours.selectedIndex = 0");
			eval("document." + form_and_menu + "_minutes.selectedIndex = 0");
			eval("document." + form_and_menu + "_seconds.selectedIndex = 0");
			eval("document." + form_and_menu + "_ampm.selectedIndex = 0");
		}
	}


// return an SQL-standard timestamp for the current time

	function timestamp() {
		time = new Date();
		
		year = time.getFullYear();
		month = time.getMonth() + 1;
		day = time.getDate();
		hours = time.getHours();
		minutes = time.getMinutes();
		seconds = time.getSeconds();
		
		if (month < 10) { month = "0" + month; }
		if (day < 10) { day = "0" + day; }
		if (hours < 10) { hours = "0" + hours; }
		if (minutes < 10) { minutes = "0" + minutes; }
		if (seconds < 10) { seconds = "0" + seconds; }

		result = year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
		return result;
	}


