// show a warning message to users of unsupported browsers

	function check_browser_support() {
		//alert(navigator.appVersion); return; // test user agent strings
		unsupported = new Array("MSIE 6");
		supported = 1;
		warned = 1;
		for (n=0; n<unsupported.length; n++) {
			if (navigator.appVersion.indexOf(unsupported[n]) != -1) {
				supported = 0;
			}
		}
		if (!supported) {
			warned = get_cookie("browser_support", "warned");
		}
		if ((!supported)&&(!warned)) {
			alert("Your browser is not supported by this website. Please consider upgrading to a newer browser. Otherwise, portions of this site may not display or function correctly.");
			set_cookie("browser_support", "warned", 1);
		}
	}


// 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
	}


// show an email link on a page in a way that spam harvesters can't see

	function show_email(user, domain, tld, label, subject, body) {
		if (!label) { label = user + "@" + domain + "." + tld; }
		if (!subject) { subject = ""; }
		if (!body) { body = ""; } else {
			body = body.replace(/\n/g, "%0A");
			body = body.replace(/\"/g, "'");
		}
		document.write("<a href=\"mailto:" + user + "@" + domain + "." + tld + "?subject=" + subject + "&body=" + body + "\">" + label + "<\/a>");
	}


// 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;
	}


// search some menu code for a page or section name and set its link ID to "active"
// it would be better to scan the objects within the given div, look for the object whose href matches the page, and change that object's class, but this seems to work fine for now

	function set_active_item(menu_name, page) {
		if (document.getElementById(menu_name)) {
			if (page) {
		
				// these menu items don't have IDs, so we have to get the HTML and parse the anchor tags
				menu_code = document.getElementById(menu_name).innerHTML; // note that IE capitalizes HTML tags, so we have to use case-insensitive regexps below
				re = new RegExp("(<a)([^>]*href=\"[^>]*" + page + "[^>]*\")", "i");
				menu_code = menu_code.replace(re, "$1 class=\"menu_active\"$2");
				document.getElementById(menu_name).innerHTML = menu_code;

			}
		}
	}
	

// set the class for a CSS element given its ID (class is a reserved word)

	function set_CSS_class(element, new_class) {
		document.getElementById(element).className = new_class;
	}


// load the specified code, or the contents of the specified container, into a modal layer
// this assumes we have div IDs called modal_background, modal_box and modal_content

	function load_code_modal(container, code) {
		if (container) {
			code = document.getElementById(container).innerHTML;
		}
		document.getElementById("modal_content").innerHTML = code;
		document.getElementById("modal_background").style.height = document.body.scrollHeight + "px"; // set the background to the same size as the window
		document.getElementById("modal_background").style.display = "block";
	}

	function close_modal() {
		document.getElementById("modal_background").style.display = "none";
	}


// load the specified code into the specified container with animation
// also unload the previous code, and unload the code if you call the same code twice in a row
// if we don't provide any code, we'll assume the container already contains the code and we'll just manage the reveal
// if the three link arguments are set, we'll also change the class of the link as we load and unload the container

	function load_code_reveal(container, code, link, link_class_open, link_class_close) {
		// always empty the last container, or initialize the variable
		if (isset("last_container")&&(last_container != "")) {
			if (last_container != container) {
				// if we're closing the previous one so we can open a new one, don't animate the closing
				hide(last_container);
			} else {
				// if we're closing the one we just opened, animate the closing
				reveal(container, "", 0, 1, "");
			}
			if (link) {
				if (isset("last_link")&&(last_link != "")) {
					set_CSS_class(last_link, link_class_open);
				}
			}
		} else {
			last_container = "";
		}
		
		// if the new container is different from the last one, load it; otherwise reset it so it loads next time
		if (last_container != container) {
			//document.getElementById(container).innerHTML = code; // no animation
			reveal(container, code, 1, 1, ""); // animation
			last_container = container;
			if (link) {
				set_CSS_class(link, link_class_close);
				last_link = link;
			}
		} else {
			last_container = "";
			last_link = "";
		}
	}


// reveal an element's content from 0 height to its full height
// element = ID
// content = HTML to put into the element before animating (use "" to leave existing content)
// direction = 1: in, 0: out
// duration = seconds
// callback = code to run when this is done

	function reveal_in_prep(element) {
		// show but collapse the element so we can preload its content
		document.getElementById(element).style.height = 0;
		document.getElementById(element).style.overflow = "hidden";
		show(element);
	}

	function reveal_out_prep(element) {
		// set the element's attributes so we can gradually collapse it
		document.getElementById(element).style.overflow = "hidden";
	}

	function reveal_in_release(element) {
		// restore the element to normal display when we're done
		document.getElementById(element).style.height = "auto";
		document.getElementById(element).style.overflow = "auto";
	}

	function reveal_out_release(element) {
		// hide the element; this isn't necessary in most cases but for video on the iPad it is
		hide(element);
	}

	function reveal(element, content, direction, duration, callback) {
		// find out if we're already running; if not, set everything up
		if (!isset("start_time")||(!start_time)) {
			start_time = new Date().getTime();
			last_time = start_time;
			proportion_complete = 0;
			if (direction) {
				reveal_in_prep(element);
				if (content) {
					document.getElementById(element).innerHTML = content;
				}
			} else {
				reveal_out_prep(element);
			}
			full_size = document.getElementById(element).scrollHeight;
			target_size = (direction) ? full_size : 0 ;
			minimum_step = 10; // milliseconds; used to minimize processing by reducing the resolution of the change
		}

		// step through the sizes until we reach full size
		if (proportion_complete < 1) {
			// control the "resolution" of our changes to avoid slowing the browser down too much
			// find out how far along we are
			current_time = new Date().getTime();
			elapsed_time = current_time - start_time;
			proportion_complete = elapsed_time / (duration * 1000);
			//console.log(proportion_complete);
				
			// change the size in proportion to our progress
			height = (direction) ? (proportion_complete * full_size) : ((1 - proportion_complete) * full_size) ;
			change_size(element, height);
			//console.log("changing to " + height + " on the way to " + target_size);
			
			// repeat
			setTimeout("reveal('" + element + "', '', " + direction + ", " + duration + ", \"" + callback + "\")", minimum_step);
		} else {
			// make sure we end up at our target size
			change_size(element, target_size);
			if (direction) {
				reveal_in_release(element);
			} else {
				reveal_out_release(element);
			}
			start_time = 0;
			eval(callback);
		}
	}
	
	function change_size(element, height) {
		document.getElementById(element).style.height = height + "px";
	}
	

// hide or show an element
// element = ID

	function hide(element) {
		document.getElementById(element).style.display = "none";
	}

	function show(element) {
		document.getElementById(element).style.display = "block";
	}



