var DISPLAYTABLEROW;
var DISPLAYTABLE;
if (document.all) {
	DISPLAYTABLEROW = 'block';
	DISPLAYTABLE = 'block';
}
else {
	DISPLAYTABLEROW = 'table-row';
	DISPLAYTABLE = 'table';
}

var ie = document.all ? true : false;
var ie6//@cc_on=ScriptEngineMajorVersion()<=6 /*actually, if ie6 or lower*/

/*function copyArr(arr) { var newArr = []; for (var i=0; i<arr.length; i++) { newArr[i] = arr[i]; } return newArr; }
if (ie) { var console = {}; console.log = function() { alert(copyArr(arguments).join(" ")); } }*/

function gbid(id) { return document.getElementById(id); }
function dot(msg) { var newEl = document.createElement("div"); newEl.appendChild(document.createTextNode(msg)); document.body.appendChild(newEl); }
function dotr(msg) { document.body.appendChild(document.createElement("div")).innerHTML += msg; }
function dmsg(msg, html) {
	var msgPane = document.getElementById("debuggingMessagePane");
	if (!msgPane) {
		var msgPane = document.createElement("div");
		msgPane.id = "debuggingMessagePane";
		document.body.appendChild(msgPane);
		document.body.style.marginBottom = "50%";
	}
	if (html) {
		msgPane.appendChild(document.createElement("div")).innerHTML += msg;
	}
	else {
		msgPane.appendChild(document.createTextNode(msg));
	}
}

/**
Adapted from http://www.dustindiaz.com/getelementsbyclass/
*/
function getElementsByClass(searchClasses,node,tag) {
	if (typeof(searchClasses)!="object") { searchClasses = [searchClasses]; }
	var classElements = new Array();
	if ( node == null )
		node = document;
	if ( tag == null )
		tag = '*';
	var els = node.getElementsByTagName(tag);
	var elsLen = els.length;
	var patterns = [];
	for (var i=0; i<searchClasses.length; i++) {
		patterns[patterns.length] = new RegExp("(^|\\s)"+searchClasses[i]+"(\\s|$)", "i");
	}
	for (i = 0, j = 0; i < elsLen; i++) {
		var testPassed = true;
		for (var pi=0; pi<patterns.length; pi++) {
			if (!patterns[pi].test(els[i].className)) {
				testPassed = false;
			}
		}
		if (testPassed) {
			classElements[j] = els[i];
			j++;
		}
	}
	return classElements;
}

function hasClassName(el, name) {
  var i, list;

  list = el.className.split(" ");
  for (i = 0; i < list.length; i++)
    if (list[i] == name)
      return true;

  return false;
}

function addClassName(el, name) {
	if (!el.className) {
		el.className = name;
	}
	else if (el.className.search(name)==-1) {
		el.className += " " + name;
	}
}

function removeClassName(el, name) {
	el.className = el.className.replace(name, '').replace(/^\s*|\s*$/g, '');
	if (!el.className) {
		if (el.hasAttribute) {
			el.removeAttribute("class");
		}
		else if (el.attributes) {
			el.removeAttributeNode(el.attributes["class"]);
		}
	}
}

function elHasAttribute(el, attr) {
	//alert(el.parentNode+";"+);
	if (typeof(el)=="undefined") { alert(el+":"+elHasAttribute.caller); }
	if (ie) return typeof(el[attr])!="undefined";
	return el.hasAttribute(attr);
}

function getElAttribute(el, attr) {
	if (ie) return el[attr];
	return el.getAttribute(attr);
}

function setElAttribute(el, attr, str) {
	if (ie) {
		el[attr] = str;
		if (el.setAttribute) {
			return el.setAttribute(attr, str);
		}
		return str;
	}
	return el.setAttribute(attr, str);
}

function firstChild(el) {
	el = el.firstChild;
	while (el) {
		if (typeof(el.tagName)!="undefined") {
			return el;
		}
		el = el.nextSibling;
	}
	return null;
}

getFirstChild = firstChild;

function nextSibling(el) {
	while (el.nextSibling) {
		if (typeof(el.nextSibling.tagName)!="undefined") {
			return el.nextSibling;
		}
		el = el.nextSibling;
	}
	return null;
}

getNextSibling = nextSibling;

function previousSibling(el) {
	while (el.previousSibling) {
		if (typeof(el.previousSibling.tagName)!="undefined") {
			return el.previousSibling;
		}
		el = el.previousSibling;
	}
	return null;
}

getPreviousSibling = previousSibling;

function lastChild(el) {
	el = el.lastChild;
	while (el) {
		if (typeof(el.tagName)!="undefined") {
			return el;
		}
		el = el.previousSibling;
	}
	return null;
}

getLastChild = lastChild;

/// Also true if el==ancestor
function hasAncestor(el, ancestor) {
	while (el) {
		if (el==ancestor) {
			return true;
		}
		el = el.parentNode;
	}
	return false;
}

function getContainerWithTagOfClass(node, tagName, className) {
  while (node != null) {
    if (node.tagName != null && node.tagName == tagName &&
			hasClassName(node, className)) {
		return node;
	}
    node = node.parentNode;
  }
  return node;
}

function getContainerWithTagName(node, tagName) {
  while (node != null) {
    if (node.tagName != null && node.tagName.search(new RegExp(tagName, "i"))!=-1 ) {
			return node;
		}
		node = node.parentNode;
  }
  return node;
}

function getContainer(node, tagName, className) {
  while (node != null) {
    if (node.tagName != null && node.tagName.search(new RegExp(tagName, "i"))!=-1 &&
			(!className || hasClassName(node, className))) {
		return node;
	}
    node = node.parentNode;
  }
  return node;
}

function getFirstTagChild(el) {
	for (var i=0; i<el.childNodes.length; i++) {
		if (typeof(el.childNodes[i].tagName)!="undefined") {
			return el.childNodes[i];
		}
	}
	return null;
}

/** Removes scrolls of divs, etc. because I'm normally only ever interested
in distance from top of virtual page, not of virtual sections within the virtual page **/
function getElLeft(el, untilParentEl) {
	var origEl = el;
	/// Moz sets body offsetLeft to -borderWidth
	/// I don't know what IE or other browsers do does
	var val = 0;
	if (typeof(windowBorderLeft)!="undefined") {
		val = windowBorderLeft;
	}
	else {
		val = -document.body.offsetLeft*2;
	}
	while (el && el!=untilParentEl ) {
		val += el.offsetLeft;
		el = el.offsetParent;
	}
	/// Account for scrolls
	el = origEl.parentNode;
	while (el && el!=untilParentEl ) {
		if (el && el!=document.body && el.tagName!="HTML" && el.scrollLeft) {
			val -= el.scrollLeft;
		}
		el = el.parentNode;
	}
	return val;
}

function getElTop(el, untilParentEl) {
	var origEl = el;
	/// Moz sets body offsetTop to -borderHeight
	var val = 0;
	if (typeof(windowBorderTop)!="undefined") {
		val = windowBorderTop;
	}
	else {
		val = -document.body.offsetTop*2;
	}
	while (el && el!=untilParentEl ) {
		val += el.offsetTop;
		el = el.offsetParent;
	}
	/// Remove scrolls
	el = origEl.parentNode;
	while (el && el!=untilParentEl ) {
		if (el && el!=document.body && el.tagName!="HTML" && el.scrollTop) {
			val -= el.scrollTop;
		}
		el = el.parentNode;
	}
	return val;
}

function getElWidth(el) {
	return el.offsetWidth;
}

function getElHeight(el) {
	return el.offsetHeight;
}

function getElRight(el) {
	return getElLeft(el)+getElWidth(el);
}

function getElBottom(el) {
	return getElTop(el)+getElHeight(el);
}

function getScrollLeft() {
	if (document.documentElement.scrollLeft) { return document.documentElement.scrollLeft; }
	if (document.body.scrollLeft) { return document.body.scrollLeft; }
	else if (window.scrollX) { return window.scrollX; }
	else { return 0; }
}

function getScrollTop() {
	if (document.documentElement.scrollTop) { return document.documentElement.scrollTop; }
	if (document.body.scrollTop) { return document.body.scrollTop; }
	else if (window.scrollY) { return window.scrollY; }
	else { return 0; }
}

function getInnerWindowWidth() {
	if (window.innerWidth) { return window.innerWidth; }
	else if (document.documentElement) { return document.documentElement.clientWidth; }
	else if (document.body.clientWidth) { return document.body.clientWidth; }
	else { return 0; }
}

function getInnerWindowHeight() {
	if (window.innerHeight) { return window.innerHeight; }
	else if (document.documentElement) { return document.documentElement.clientHeight; }
	else if (document.body.clientHeight) { return document.body.clientHeight; }
	else { return 0; }
}

function getPageWidth() {
	if (window.innerWidth && window.scrollMaxX) {// Firefox
		pageWidth = window.innerWidth + window.scrollMaxX;
	}
	else if (document.body.scrollWidth > document.body.offsetWidth) { // all but Explorer Mac
		pageWidth = document.body.scrollWidth;
	}
	else { // works in Explorer 6 Strict, Mozilla (not FF) and Safari
		pageWidth = document.body.offsetWidth;
  }
  return pageWidth;
}

function getPageHeight() {
	if (window.innerHeight && window.scrollMaxY) {// Firefox
		pageHeight = window.innerHeight + window.scrollMaxY;
	}
	else if (document.documentElement && document.documentElement.clientHeight) {
		pageHeight = document.documentElement.clientHeight;
	}
	else if (document.body.scrollHeight > document.body.offsetHeight) { // all but Explorer Mac
		pageHeight = document.body.scrollHeight;
	}
	else { // works in Explorer 6 Strict, Mozilla (not FF) and Safari
		pageHeight = document.body.offsetHeight;
  }
  return pageHeight;
}

//////////////////////////////////
/// Selections

function range_clearSelection() {
	if (document.selection) {
		document.selection.empty();
	}
}

//////////////////////////////////
///Utilities

///Popups
function popupElement(el, top, left) {
	//alert(top);
	if (typeof(el)=="string") {
		el = document.getElementById(el);
	}
	/*if (el.parentNode!=document.body) {
		el.parentNode.removeChild(el);
		document.body.appendChild(el);
	}*/
	//alert(el.style.visibility);
	el.style.visibility = 'hidden';
	el.style.display = 'block';
	var newTop = top-getScrollTop();
	var newLeft = left-getScrollLeft();
	var elWidth = getElWidth(el);
	var elHeight = getElHeight(el);
	//alert((evt.left+efWidth)+":"+document.body.clientWidth);
	if ( (newLeft+elWidth)>getInnerWindowWidth()) {
		newLeft = left-elWidth;
		if (newLeft<0) {
			newLeft = 0;
		}
	}
	if ( (newTop+elHeight)>getInnerWindowHeight()) {
		newTop = newTop-elHeight;
		if (newTop<0) {
			newTop = 0;
		}
	}
	el.style.top = (getScrollTop() + newTop) + "px";
	el.style.left = (getScrollLeft() + newLeft) + "px";
	el.style.visibility = 'visible';
	//el.style.border = "solid 40px red";
	//alert(el.id);

	///Hack to hide select objects
	if (document.all) {
		var width = getElWidth(el);
		var height = getElHeight(el);
		var els = document.getElementsByTagName('select');
		top = newTop;
		left = newLeft;
		for (var i=0; i<els.length; i++) {
			var selTop = getElTop(els[i])-getScrollTop();
			var selLeft = getElLeft(els[i])-getScrollLeft();
			var selWidth = getElWidth(els[i]);
			var selHeight = getElHeight(els[i]);
			if ((	(top<selTop && top+height>selTop)
					|| (top>selTop && top+height<selTop+selHeight)
					|| (top<selTop+selHeight && top+height>selTop+selHeight))
					&&
					(	(left<selLeft && left+width>selLeft)
					|| (left>selLeft && left+width<selLeft+selWidth)
					|| (left<selLeft+selWidth && left+width>selLeft+selWidth))
					) {
				els[i].style.visibility = 'hidden';
			}
		}
	}
	el.style.position = "absolute";
	if (el.parentNode == null) {
		document.body.appendChild(el);
	}
}

function dismissPopup(el) {
	if (typeof(el)=="string") {
		el = document.getElementById(el);
	}
	///Hack to re-show select objects
	var top = getElTop(el);
	var left = getElLeft(el);
	var width = getElWidth(el);
	var height = getElHeight(el);
	var els = document.getElementsByTagName('select');
	for (var i=0; i<els.length; i++) {
		var selTop = getElTop(els[i]);
		var selLeft = getElLeft(els[i]);
		var selWidth = getElWidth(els[i]);
		var selHeight = getElHeight(els[i]);
			if ((	(top<selTop && top+height>selTop)
					|| (top>selTop && top+height<selTop+selHeight)
					|| (top<selTop+selHeight && top+height>selTop+selHeight))
					&&
					(	(left<selLeft && left+width>selLeft)
					|| (left>selLeft && left+width<selLeft+selWidth)
					|| (left<selLeft+selWidth && left+width>selLeft+selWidth))
				) {
			els[i].style.visibility = 'visible';
		}
	}

	///Actual dismiss
	el.style.display = 'none';
}

/** Very crude popup menu stuff **/
var currentMousedMenu = null;
var currentActiveMenu = null;
var dismissPopupTimeout = 1000;
//var mcount = 0;

function popupElementMenu(el, top, left) {
	//dot(mcount+":"+currentActiveMenu+"; "); mcount++;
	if (typeof(el)=="string") {
		el = document.getElementById(el);
	}
	if (currentActiveMenu && currentActiveMenu!=el.id) {
		dismissPopupMenu(currentActiveMenu, true);
	}
	popupElement(el, top, left);
	currentActiveMenu = el.id;
}

function dismissPopupMenu(el, force) {
	if (typeof(el)=="string") {
		el = document.getElementById(el);
		//alert(el);
	}
	if (!force && el.id==currentMousedMenu) {
		return;
	}
	dismissPopup(el);
	if (currentActiveMenu==el.id) {
		currentActiveMenu = 0;
	}
}

function elSetSelectionRange(el, start, end) {
	if (el.createTextRange) {
		var trange = el.createTextRange();
		trange.moveStart("character", start);
		trange.moveEnd("character", end);
		trange.select();
	}
	else if (el.setSelectionRange) {
		//displayEl.selectionStart();
		el.setSelectionRange(start, end);
	}
}

/** Should merge with the above 2 functions **/
function hideSelectObjects(elToPopup, ignorePrefix, elAncestor) {
	if (!document.all) { return; }
	///Hack to hide select objects
	var top = getElTop(elToPopup);
	var left = getElLeft(elToPopup);
	var width = getElWidth(elToPopup);
	var height = getElHeight(elToPopup);
	var els = document.getElementsByTagName('select');
	//dot("{"+top+","+left+","+width+","+height+"}");
	for (var i=0; i<els.length; i++) {
		if (ignorePrefix && (
						(els[i].name && String(els[i].name).search(new RegExp("^"+ignorePrefix))!=-1)
						|| (els[i].id && els[i].id.search(new RegExp("^"+ignorePrefix))!=-1)
		)) { continue; }
		//alert(els[i].id+":"+elToPopup.id+":"+hasAncestor(els[i], elToPopup));
		if (hasAncestor(els[i], elToPopup) || hasAncestor(els[i], elAncestor)) { continue; }
		var selTop = getElTop(els[i]);
		var selLeft = getElLeft(els[i]);
		var selWidth = getElWidth(els[i]);
		var selHeight = getElHeight(els[i]);
		//dot("["+selTop+","+selLeft+","+selWidth+","+selHeight+"]");
			if ((	(top<selTop && top+height>selTop)
					|| (top>selTop && top+height<selTop+selHeight)
					|| (top<selTop+selHeight && top+height>selTop+selHeight))
					&&
					(	(left<selLeft && left+width>selLeft)
					|| (left>selLeft && left+width<selLeft+selWidth)
					|| (left<selLeft+selWidth && left+width>selLeft+selWidth))
				) {
			els[i].style.visibility = 'hidden';
		}
	}
}

function showSelectObjects(elToDismiss, ignorePrefix) {
	if (!document.all) { return; }
	///Hack to re-show select objects
	var top = getElTop(elToDismiss);
	var left = getElLeft(elToDismiss);
	var width = getElWidth(elToDismiss);
	var height = getElHeight(elToDismiss);
	var els = document.getElementsByTagName('select');
	for (var i=0; i<els.length; i++) {
		if (els[i].name && String(els[i].name).search(new RegExp("^"+ignorePrefix))!=-1) {
			continue;
		}
		var selTop = getElTop(els[i]);
		var selLeft = getElLeft(els[i]);
		var selWidth = getElWidth(els[i]);
		var selHeight = getElHeight(els[i]);
			if ((	(top<selTop && top+height>selTop)
					|| (top>selTop && top+height<selTop+selHeight)
					|| (top<selTop+selHeight && top+height>selTop+selHeight))
					&&
					(	(left<selLeft && left+width>selLeft)
					|| (left>selLeft && left+width<selLeft+selWidth)
					|| (left<selLeft+selWidth && left+width>selLeft+selWidth))
				) {
			els[i].style.visibility = 'visible';
		}
	}
}

if (typeof(onloads)=="undefined") { onloads = []; }
function doOnload(event) {
	for (var i in onloads) {
		onloads[i](event);
	}
}


function newEl(tag, innerHTML, props) {
	if (!innerHTML) { innerHTML = ''; }
	/// If tag looks like html, treat like html fragment with just 1 element
	if (tag.search(/</)!=-1) {
		var div = document.createElement("div");
		div.innerHTML = tag.replace(/^[^<]*/, ''); /// Get rid of anything at the start that''s not tag
		return div.firstChild;
	}
	/// Otherwise, treat as tag name
	else {
		var el = document.createElement(tag);
		for (var prop in props) {
			if (prop=="className") { el.className = props.className; }
			else {
				el.setAttribute(prop, props[prop]);
			}
		}
		el.innerHTML = innerHTML;
		return el;
	}
}

function newDiv(content, props) { return newEl("div", content, props); }

/// This isn't even correct (width includes borders, for example), but it will do for now
function getClassProperty(className, property, parentNode, tag) {
	if (!tag) { tag = "div"; }
	if (!parentNode) { parentNode = document.body; }
	var el = document.createElement(tag);
	el.className = className;
	el.style.visibility = "hidden";
	parentNode.appendChild(el);
	var propertyValue = null;
	if (property.search(/width|height|top|left/)!=-1) {
		propertyValue
			= el['offset' + property.charAt(0).toUpperCase() + property.substr(1)];
	}
	else {
		/// Get computed value or something
	}
	parentNode.removeChild(el);
	return propertyValue;
}

if(typeof HTMLElement!="undefined" && HTMLElement.prototype.__defineGetter__ != 'undefined'){
	function htmlToString(str) {
		str = str.replace(/&quot;/g, '"');
		str = str.replace(/&nbsp;/g, ' ');
		str = str.replace(/&gt;/g, ">");
		str = str.replace(/&lt;/g, "<");
		str = str.replace(/&amp;/g, "&");
		return str;
	}
	/// For whatever reason, it doesn't work unless I put it in the onload,
	/// and that's no because of extensions
	onloads.push(function() {
		HTMLElement.prototype.__defineGetter__("innerText", function() {
			var tmp = this.innerHTML.replace(/\n*<br>\n*/gi,"\n");
			return htmlToString(tmp.replace(/<[^>]+>/g,""));
		});

		HTMLElement.prototype.__defineSetter__("innerText", function(txtStr){
			var parsedText = document.createTextNode(txtStr);
			this.innerHTML = "";
			this.appendChild( parsedText );
		});

		HTMLIFrameElement.prototype.__defineGetter__("document", function() {
			return this.contentDocument;
		})
	});
}

function moveElTo(el, top, left) {
	if (typeof(top)=="object") { left = top.left; top = top.top; }
	el.style.top = top+"px";
	el.style.left = left+"px";
}