if (typeof(console)=="undefined") {
	console = { log: function() {} };
}

function genPass(length) {
	var pwd;
	pwd = "";
	for (i=0;i<length;i++) {
		pwd += String.fromCharCode(Math.floor((Math.random()*25+65)));
	}
	return pwd;
}

function setSelect(pForm, id) {
	if (pForm.sel.length) {
		pForm.sel[id].checked = true;
	}
	else {
		pForm.sel.checked = true;
	}
}

/**
fields: should be in {name1: label1, name2: label2, ...} format
*/
function checkForBlanks(formOrTable, prefix, fields, noAlert, checkAllFormFields) {
	if (typeof(formOrTable.getValue)=="function") {
		var table = formOrTable;
		fields = prefix;
		noAlert = fields;
		checkAllFormFields = noAlert;

	}
	else {
		var form = formOrTable;
		var blanksFound = [];

		for (var i=0; i<form.elements.length; i++) {
			var found = form.elements[i].name.match(new RegExp("^"+prefix+"(.*)"));
			if (found) {
				if (form.elements[i].value=="" || form.elements[i].value==null) {
					if (checkAllFormFields) {
						blanksFound[blanksFound.length] = typeof(fields[found[1]])=="undefined" ? form.elements[i].name : fields[found[1]];
					}
					else if (typeof(fields[found[1]])!="undefined") {
						blanksFound[blanksFound.length] = fields[found[1]];
					}
				}
			}
		}
		if (blanksFound.length>0) {
			if (!noAlert) {
				str = "The following required fields are blank:\n";
				for (var i=0; i<blanksFound.length; i++) {
					str+= blanksFound[i]+"\n";
				}
				alert(str);
				return true;
			}
			return blanksFound;
		}
	}
}

function moveOptions(from, to) {
	var i;
	for (i = 0; i<from.options.length; i++) {
		if (from.options[i].selected) {
			opt = from.options[i];
			opt2 = new Option(opt.text, opt.value, false, false);
			to[to.length] = opt2;
			from.options[i] = null;
			i--;
		}
	}
}

function forEachIndex(arr, callback) {
	for (var i=0; i<arr.length; i++) {
		///Relying on closures, here. Efficiency shouldn't be a problem, because
		///function isn't returned to anything (efficiency shouldn't be a problem in any case
		///where the function doesn't refer to the parent scope either, but apparently it is).
		callback(i);
	}
}

function addMultipleSelect(selBox, text, value) {
	if (!value) {
		value = text;
	}
	if (text!="") {
		opt = new Option(text, value, false, false);
		selBox.options[selBox.options.length] = opt;
		selectNone(selBox);
		return true;
	}
	return false;
}

function remMultipleSelect(selBox) {
	var i;
	for (i = 0; i<selBox.options.length; i++) {
		if (selBox.options[i].selected) {
			selBox.options[i] = null;
			i--;
		}
	}
}

function removeAllOptions(selBox) {
	selBox.options.length = 0;
	/*for (var i=selBox.options.length-1; i>=0; i--) {
		selBox.options[i] = null;
	}*/
}

function moveTo(selBox, pos) {
	var prevSelected = false;
	var noMove = false;
	for (var i=0; i<selBox.options.length; i++) {
		if (selBox.options[i].selected) {
			if (!(prevSelected && noMove) && (i>0)) {
				var j = i;
				while (j>pos) {
					var o1 = selBox.options[j];
					var o3 = new Option(o1.text, o1.value, false, false);
					var o2 = selBox.options[j - 1];
					var o4 = new Option(o2.text, o2.value, false, false);
					selBox.options[j] = o4;
					selBox.options[j - 1] = o3;
					selBox.options[j].selected = false;
					prevSelected=true;
					noMove=false;
					selBox.options[j - 1].selected=true;
					j--;
				}
			}
			else {
				prevSelected=true;
				noMove=true;
			}
		}
		else {
			prevSelected=false;
			noMove=false;
		}
	}
}

function moveUp(selBox) {
	var prevSelected = false;
	var noMove = false;
	for (var i=0; i<selBox.options.length; i++) {
		if (selBox.options[i].selected) {
			if (!(prevSelected && noMove) && (i>0)) {
				var o1 = selBox.options[i];
				var o3 = new Option(o1.text, o1.value, false, false);
				var o2 = selBox.options[i - 1];
				var o4 = new Option(o2.text, o2.value, false, false);
				selBox.options[i] = o4;
				selBox.options[i - 1] = o3;
				selBox.options[i].selected = false;
				prevSelected=true;
				noMove=false;
				selBox.options[i - 1].selected=true;
			}
			else {
				prevSelected=true;
				noMove=true;
			}
		}
		else {
			prevSelected=false;
			noMove=false;
		}
	}
}

function moveDown(selBox) {
	var prevSelected = false;
	var noMove = false;
	for (var i=(selBox.options.length-1); i>=0; i--) {
		if (selBox.options[i].selected) {
			if (!(prevSelected && noMove) && (i+1<selBox.options.length)) {
				var o1 = selBox.options[i];
				var o3 = new Option(o1.text, o1.value, false, false);
				var o2 = selBox.options[i + 1];
				var o4 = new Option(o2.text, o2.value, false, false);
				selBox.options[i] = o4;
				selBox.options[i + 1] = o3;
				selBox.options[i].selected = false;
				prevSelected=true;
				noMove=false;
				selBox.options[i + 1].selected=true;
			}
			else {
				prevSelected=true;
				noMove=true;
			}
		}
		else {
			prevSelected=false;
			noMove=false;
		}
	}
}

function setSelectFromText(sel, txt) {
	for (var i=0; i<sel.options.length; i++) {
		if (sel.options[i].text==txt) {
			sel.options[i].selected = true;
			return;
		}
	}
}

function selectAll(selBox) {
	for (var i=0; i<selBox.options.length; i++) {
		selBox.options[i].selected = true;
	}
}

function setAllChecks(frm, named, val) {
	for (var i=0; i<frm.elements.length; i++) {
		if (frm.elements[i].name==named) {
			frm.elements[i].checked = val;
		}
	}
}

/*Duplicates the above, but ah, who cares.*/
function selectNone(selBox) {
	for (var i=0; i<selBox.options.length; i++) {
		selBox.options[i].selected = false;
	}
}

function getFirstSelected(selBox) {
	for (var i=0; i<selBox.options.length; i++) {
		if (selBox.options[i].selected) {
			return selBox.options[i];
		}
	}
	return null;
}

/*Sets all the values in the form to the default nothing for the type of control*/
function clearForm(frm, elToFocus, allowRestore) {
	for (var i=0; i<frm.elements.length; i++) {
		///If it's my custom search control
		if (frm.elements[i].type=="select-one" && !frm.elements[i].getAttribute("noclear")) {
			if (allowRestore) { frm.elements[i].clearedValue = frm.elements[i].value; }
			var firstText = frm.elements[i].options[0].text;
			if (firstText == "All" || firstText == "" || firstText.charAt(firstText.length-1) == ":") {
				frm.elements[i].selectedIndex = 0;
			}
			else {
				frm.elements[i].selectedIndex = -1;
			}
		}
		else if (frm.elements[i].type=="select-multiple" && !frm.elements[i].getAttribute("noclear")) {
			if (allowRestore) {
				frm.elements[i].clearedValue = "";
				for (var j=0; j<frm.elements[i].options.length; j++) {
					if (frm.elements[i].options[j].selected) {
						frm.elements[i].clearedValue += ","+j;
					}
				}
			}
			selectNone(frm.elements[i]);
		}
		else if (frm.elements[i].getAttribute("doclear")) {
			//Custom search control
			eval(frm.elements[i].getAttribute("doclear"));
		}
		else if (frm.elements[i].type=="text" || frm.elements[i].type=="textarea") {
			if (allowRestore) { frm.elements[i].clearedValue = frm.elements[i].value; }
			frm.elements[i].value = "";
		}
	}
	if (elToFocus) {
		elToFocus.focus();
	}
}

function restoreForm(frm, elToFocus) {
	for (var i=0; i<frm.elements.length; i++) {
		if (typeof(frm.elements[i].clearedValue)!="undefined") {
			///If it's my custom search control
			if (frm.elements[i].type=="select-one" && !frm.elements[i].getAttribute("noclear")) {
				frm.elements[i].value = frm.elements[i].clearedValue;
			}
			else if (frm.elements[i].type=="select-multiple" && !frm.elements[i].getAttribute("noclear")) {
				var clearedValues = frm.elements[i].clearedValue.split(',');
				for (var j=0; j<clearedValues.length; j++) {
					if (!isNaN(parseInt(clearedValues[j]))) {
						frm.elements[i].options[clearedValues[j]].selected = true;
					}
				}
			}
			else if (frm.elements[i].getAttribute("dorestore")) {
				//Custom search control
				eval(frm.elements[i].getAttribute("dorestore"));
			}
			else if (frm.elements[i].type=="text" || frm.elements[i].type=="textarea") {
				frm.elements[i].value = frm.elements[i].clearedValue;
			}
		}
	}
	if (elToFocus) {
		elToFocus.focus();
	}
}

function getForm(el) {
	while (el && el.tagName!="FORM") {
		el = el.parentNode;
	}
	return el;
}

function pushArr(arr, el) {
	arr[arr.length] = el;
}

function verifyLockDate(txt, dt1) {
	var dt = dateStringToDate(txt.value);
	if (!dt) {
		alert("Date blank or not in required format");
		return false;
	}
	var dt1 = dt.getTime();
	if (dt1<lockBefore) {
		alert("Can't enter dates before "+dateToDateString(new Date(lockBefore)));
		txt.focus();
		return false;
	}
	return true;
}

/** I no longer use the following: **/
function transactionToggleCancel(checkbox, payrecid) {
	var cancelform = document.getElementById("CancelledForm"+payrecid);
	var frm = checkbox.form;
	if (checkbox.checked) {
		cancelform.style.display = "block";
		var canceldate = frm["CancelledDate"+payrecid];
		var debtdate = frm["CancelledDebtDate"+payrecid];
		if (canceldate && canceldate.value=="") {
			canceldate.value = dateToDateString(new Date());
		}
		if (debtdate && debtdate.value == "") {
			debtdate.value = dateToDateString(new Date());
		}
	}
	else {
		cancelform.style.display = "none";
	}
	checkbox.focus();
}

function transactionCancelConfirm(tbl, cancelName, fieldDesc) {
	var str = "";
	var pks = tbl.getAllSelectedPks();
	for (var i=0; i<pks.length; i++) {
		var ev = "'"+fieldDesc.replace("'", "\\'").replace(/\$([^$]+)\$/g, "'+tbl.getPkValue(pks[i], '$1')+'")+"'";
		var tmp = eval(ev);
		str += "* "+tmp.replace(/[\r\n]+/g, " ") + "\n";
	}
	if (confirm('Are you sure you wish to cancel the following '+cancelName+'?\n'+str)) {
		tbl.closeTable();
		return true;
	}
	return false;
}

function round(num, decimals) {
	var p = Math.pow(10,decimals);
	return Math.round(num*p)/p;
}

function checkPwd(frm) {
	if (frm.pwd.value == "y") {
		return true;
	}
	alert("incorrect password");
	return false;
}

var deleteClicked = false;

function checkDelete(thing) {
	if (deleteClicked) {
		deleteClicked = false;
		return confirm("Delete the "+thing+"?");
	}
	return true;
}

var SC_PERMANENT = -1;
function setCookie(name, value, expire, path) {
	if (expire==SC_PERMANENT) { expire = new Date(2030,0,1); }
	document.cookie = name + "=" + escape(value)
	+ ((expire == null) ? "" : ("; expires=" + expire.toGMTString()))
	+ ((path==null)? "; path=/" : ("; path="+path));
}

function getCookie(name) {
   var search = name + "="
   if (document.cookie.length > 0) { // if there are any cookies
	  offset = document.cookie.indexOf(search)
	  if (offset != -1) { // if cookie exists
		 offset += search.length
		 // set index of beginning of value
		 end = document.cookie.indexOf(";", offset)
		 // set index of end of cookie value
		 if (end == -1)
			end = document.cookie.length
		 return unescape(document.cookie.substring(offset, end))
	  }
	  return "";
   }
   return "";
}

function setTransactionJournalDates(frm) {
	if (!frm.fromDate.value) {
		setCookie('fromDate', 'null');
	}
	else {
		setCookie('fromDate', dateStringToDate(frm.fromDate.value).toGMTString());
	}
	if (!frm.toDate.value) {
		setCookie('toDate', 'null');
	}
	else {
		setCookie('toDate', dateStringToDate(frm.toDate.value).toGMTString());
	}
}

function changeQsUrl(url, nameValues) {
    url = url.replace(/^&|&$/g, "");
    found = url.match(/^([^?]*\??)(.*)/);
    if (found) {
    	if (found[1].charAt(found[1].length-1)!='?') {
    		found[1] += '?';
    	}
    	return found[1]+changeQs(nameValues, found[2]);
    }
    return "";
}

function changeQs(nameValues, qs) {
	var qs = "&"+qs;
	for (name in nameValues) {
		var re = new RegExp("&"+name+"=[^&]*", "gi");
		qs = qs.replace(re, "");
		qs = qs.replace(/^&/, "");
		if (qs!="") { qs += "&"; }
		qs += name + "=" + escape(nameValues[name]);
	}
	qs = qs.replace(/^&/, "");
	return qs;
}

///Just gets first instance of var in qs
function getFirstQsVar(name, qs) {
	var qs = "&"+qs;
	var re = new RegExp("&"+name+"=([^&]*)", "i");
	var found = qs.match(re);
	if (found) {
		return unescape(found[1]);
	}
	return null;
}

function modalMessage(msg, title) {
	var divEl = document.createElement("div");
	divEl.id = "modalMessage";
	divEl.innerHTML = msg;
	document.body.appendChild(divEl);
	hideSelectObjects(divEl, '');
}

function labelClick(label) {
	var forText = label.getAttribute("for");
	if (!forText) { forText = label.getAttribute("htmlFor"); }
	if (!label.form.toRestore) {
		clearForm(label.form, label.form[forText], true);
		label.form.toRestore = true;
	}
	else {
		restoreForm(label.form, label.form[forText]);
		label.form.toRestore = false;
	}
}

function inspectObj(obj) {
	var str = typeof(obj)+" {";
	for (var i in obj) {
		str += i+":"+obj[i];
	}
	for (var i=0; i<obj.length; i++) {
		str += i+":"+obj[i];
	}
	str += "}";
	return str;
}

function handleSaveForm(formName, exec) {
	handleSaveForm_exec = exec;
	handleSaveForm_formName = formName;
	window.onkeypress = function(event) {
		event = geo(event);
		if ((event.altKey || event.ctrlKey) && ((event.which | 32)==115 || (event.keyCode | 32)==115) ) {
			if (handleSaveForm_exec) {
				handleSaveForm_exec();
			}
			else {
				document.forms[handleSaveForm_formName].onsubmit();
			}
			document.forms[handleSaveForm_formName].submit();
			event.stopPropagation();
			event.preventBubble();
			event.preventDefault();
		}
		return true;
	}
}

function arraySearch(array, value) {
	for (var i=0; i<array.length; i++) {
		if (array[i] == value) {
			return i;
		}
	}
	return -1;
}

function getLabelForId(id) {
	var label;
	var labels = document.getElementsByTagName('label');

	for (var i = 0; (label = labels[i]); i++) {
		if (label.htmlFor == id) {
			return label;
		}
	}

	return false;
}

function selectMenuChanged(sel) {
	var o = sel.options[sel.selectedIndex];
	sel.selectedIndex = 0;
	if (o.getAttribute("href")) {
		window.location.href = o.getAttribute("href");
	}
	else if (o.getAttribute("js")) {
		eval(o.getAttribute("js"));
	}
}

function radioSelectLabel(rb) {
	rb.checked = true;
	var radioButtons = rb.form[rb.name];
	for (var i=0; i<radioButtons.length; i++) {
		var label = document.getElementById(rb.name + radioButtons[i].value + "Label");
		removeClassName(label, 'radioLabelSelected');
	}
	var selectedLabel = document.getElementById(rb.name + rb.value + "Label");
	addClassName(selectedLabel, 'radioLabelSelected');
}

function switchAccountOpenType(joinType) {
	if (joinType==1) {
		gbid("createAccount").style.display = "none";
		gbid("weblogin").style.display = DISPLAYTABLE;
	}
	else {
		gbid("createAccount").style.display = DISPLAYTABLE;
		gbid("weblogin").style.display = "none";
	}
}

function openerOpen(loc) {
	if (window.opener && !window.opener.closed) {
		window.opener.location.href = loc;
		window.opener.focus();
	}
	else {
		window.location.href = loc;
	}
}

///Very basic. Could only prevent simple auto harvesting.
function ds(v) {
	for (i=0; i<v.length; i++) {
		if (v.charCodeAt(i)<48) {
			document.write(v.charAt(i));
		}
		else if (i>0) {
			var p = v.charCodeAt(i-1) % 11;
			var c = v.charCodeAt(i);
			document.write(String.fromCharCode(c + p));
		}
		else {
			document.write(v.charAt(i));
		}
	}
}

function pausecomp(Amount) {
	var d = new Date(); //today's date
	var mill;
	var diff;

	while (1) {
		mill = new Date(); // Date Now
		diff = mill-d; //difference in milliseconds
		if( diff > Amount ) {break;}
	}
}

///Global variable (shudder)
var httpr;

/**
Check if the browser knows how to be dynamic
*/
function checkHttpRequest() {
	if (typeof(XMLHttpRequest)!="undefined") {
		return true;
	}
	else {
		/*@cc_on @*/
		/*@if (@_jscript_version >= 5)
		// JScript gives us Conditional compilation, we can cope with old IE versions.
		// and security blocked creation of the objects.
		 try {
		  new ActiveXObject("Msxml2.XMLHTTP");
		  return true;
		 } catch (e) {
		  try {
		   new ActiveXObject("Microsoft.XMLHTTP");
		   return true;
		  } catch (E) {
		   return false;
		  }
		 }
		@end @*/
	}
	return false;
}

/**
callback: takes httpr as an argument (which is possible due to the niceties of closures)
httpr.responseText contains text
httpr.readyState = 4 means response was valid
*/
function getLivePage(loc, callback) {
	var httpr = null;
	if (typeof(XMLHttpRequest)!="undefined") {
		httpr = new XMLHttpRequest();
	}
	else {
		/*@cc_on @*/
		/*@if (@_jscript_version >= 5)
		// JScript gives us Conditional compilation, we can cope with old IE versions.
		// and security blocked creation of the objects.
		 try {
		  httpr = new ActiveXObject("Msxml2.XMLHTTP");
		 } catch (e) {
		  try {
		   httpr = new ActiveXObject("Microsoft.XMLHTTP");
		  } catch (E) {
		   httpr = false;
		  }
		 }
		@end @*/
	}
	httpr.open("GET", loc);
	httpr.onreadystatechange = function() { callback(httpr); }
	httpr.send(null);
}

function postAndGetLivePage(loc, postData, callback) {
	if (typeof(XMLHttpRequest)!="undefined") {
		httpr = new XMLHttpRequest();
	}
	else {
		/*@cc_on @*/
		/*@if (@_jscript_version >= 5)
		// JScript gives us Conditional compilation, we can cope with old IE versions.
		// and security blocked creation of the objects.
		 try {
		  httpr = new ActiveXObject("Msxml2.XMLHTTP");
		 } catch (e) {
		  try {
		   httpr = new ActiveXObject("Microsoft.XMLHTTP");
		  } catch (E) {
		   httpr = false;
		  }
		 }
		@end @*/
	}
	var dataToSend = "";
	var first = true;
	for (var i in postData) {
		if (first) { first = false; } else { dataToSend += "&"; }
		dataToSend += i +"="+ escape(postData[i]);
	}
	httpr.open("POST", loc);
	httpr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	httpr.onreadystatechange = callback;
	httpr.send(dataToSend);
}

function getArrayFromEncoded(enc) {
	var arrSplit = enc.split(/&/);
	var arr = {};
	for (var i in arrSplit) {
		var kv = arrSplit[i].split(/=/);
		arr[kv[0]] = typeof(kv[1])=="undefined" ? "" : unescape(kv[1]);
		//alert(arr[kv[0]]);
	}
	return arr;
}

/**
Match a single expression. The expression to be matched should
be indicated in the tag by ().
tag - the re pattern
num - which () expression to match (1 is the first)
returns: the matched expression, or the empty string
*/
String.prototype.matchSingle = function(tag, num) {
	if (!num) { num = 1; }
	var found = this.match(tag);
	if (found) {
		return found[num];
	}
	return "";
}

function fixIESelectInnerHTML(sel, innerhtml) {
	///Workaround IE bug;
	if (innerhtml && sel.options.length==0) {
		var div = document.createElement("div");
		div.innerHTML = '<select>'+innerhtml+'</select>';
		var newSel = div.firstChild;
		removeAllOptions(sel);
		for (var i=0; i<newSel.options.length; i++) {
			sel.options[i] = new Option(newSel.options[i].text, newSel.options[i].value);

			if (typeof(adjustCallback)!="undefined") { adjustCallback(sel.options, i); }
		}
	}
}

/**
Used from Table_LiveSelect
*/
var currentSel = null;
var currentSelValue = null;
function liveSelect_fieldEdit(dt, tr, livePage, field, linkedFields) {
	var args = "";
	if (linkedFields) {
		for (var i in linkedFields) {
			if (isNaN(i)) {
				args += linkedFields[i] +"="+ escape(dt.getTrValue(tr.rowIndex, i))+"&";
			}
			else {
				args += linkedFields[i] +"="+ escape(dt.getTrValue(tr.rowIndex, linkedFields[i]))+"&";
			}
		}
	}
	args += field +"="+escape(dt.getTrValue(tr.rowIndex, field));
	var sel = dt.getFieldHandler(field).selectControl;
	currentSel = sel;
	currentSelValue = sel.value;
	sel.options[sel.options.length] = new Option("Loading...","Loading...");
	sel.value = "Loading...";
	function liveSelect_fieldEdit_Update(httpr) {
		if (httpr.readyState==4) {
			var currentVal = currentSelValue;
			currentSel.innerHTML = httpr.responseText;
			fixIESelectInnerHTML(currentSel, httpr.responseText);
			currentSel.value = currentVal;
		}
	}
	getLivePage(livePage+"?"+args, liveSelect_fieldEdit_Update);
}

/**
Inserting a tab in textarea. From:
http://www.webdeveloper.com/forum/showthread.php?s=&threadid=32317
*/
function setSelectionRange(input, selectionStart, selectionEnd) {
  if (input.setSelectionRange) {
    input.focus();
    input.setSelectionRange(selectionStart, selectionEnd);
  }
  else if (input.createTextRange) {
    var range = input.createTextRange();
    range.collapse(true);
    range.moveEnd('character', selectionEnd);
    range.moveStart('character', selectionStart);
    range.select();
  }
}

function replaceSelection (input, replaceString) {
	if (input.setSelectionRange) {
		var selectionStart = input.selectionStart;
		var selectionEnd = input.selectionEnd;
		input.value = input.value.substring(0, selectionStart)+ replaceString + input.value.substring(selectionEnd);

		if (selectionStart != selectionEnd){
			setSelectionRange(input, selectionStart, selectionStart + 	replaceString.length);
		}else{
			setSelectionRange(input, selectionStart + replaceString.length, selectionStart + replaceString.length);
		}

	}else if (document.selection) {
		var range = document.selection.createRange();

		if (range.parentElement() == input) {
			var isCollapsed = range.text == '';
			range.text = replaceString;

			 if (!isCollapsed)  {
				range.moveStart('character', -replaceString.length);
				range.select();
			}
		}
	}
}


// We are going to catch the TAB key so that we can use it, Hooray!
function catchTab(item,e){
	var origScrollTop = item.scrollTop;
	if(navigator.userAgent.match("Gecko")){
		c=e.which;
	}else{
		c=e.keyCode;
	}
	if(c==9){
		replaceSelection(item,String.fromCharCode(9));
		setTimeout("document.getElementById('"+item.id+"').focus(); document.getElementById('"+item.id+"').scrollTop = "+origScrollTop+";",0);
		return false;
	}

}
