/*
=====================================================
Common Routines
=====================================================
*/

reqList = new Array();

function getFieldValue(_form, _fieldname) {
	var value;
	if (_form && _form.elements && _fieldname) {
		for (var i = 0; i < _form.elements.length; i++) {
			if (_form.elements[i]) {
				if (_form.elements[i].name == _fieldname) {
					if ((_form.elements[i].type == 'radio') || (_form.elements[i].type == 'checkbox')) {
						if (_form.elements[i].checked) { value = _form.elements[i].value; }
					} else {
						value = _form.elements[i].value;
					}
				}
			}
		}
	}
	return value;
}

function setFieldValue(_form, _fieldname, _value) {
	var success = false;
	if (_form && _form.elements && _fieldname) {
		for (var i = 0; i < _form.elements.length; i++) {
			if (_form.elements[i]) {
				if (_form.elements[i].name == _fieldname) {
					if ((_form.elements[i].type == 'radio') || (_form.elements[i].type == 'checkbox')) {
						if (_form.elements[i].value == _value) { _form.elements[i].checked = true; success = true; }
						else { _form.elements[i].checked = false; }
					} else {
						_form.elements[i].value = _value;
						success = true;
					}
				}
			}
		}
	}
	return success;
}

function readForm(_form, _data) {
	var args = new Object();
	for (var field = 0; field < _form.elements.length; field++) {
		var name = _form.elements[field].name;
		if (_form.elements[field].smIsEditor) {
//			var editor = FCKeditorAPI.GetInstance(_form.elements[field].editorName);
//			_form.elements[field].value = editor.GetXHTML();
//			_form.elements[_form.elements[field].editorName].noSend = true;
			_form.elements[field].value = _form.elements[field].CKeditor.getData();
		}
		if (_form.elements[field].name) {
			if ((_form.elements[field].type == 'radio') || (_form.elements[field].type == 'checkbox')) {
				if (_form.elements[field].checked) {
					if (args[name]) {
						args[name].values.push(_form.elements[field].value);
					} else {
						args[name] = {
							value:	_form.elements[field].value,
							values:	[_form.elements[field].value]
						};
					}
				}
			} else {
				if (args[name]) {
					args[name].values.push(_form.elements[field].value);
				} else {
					args[name] = {
						value:	_form.elements[field].value,
						values:	[_form.elements[field].value]
					};
				}
			}
		}
	}
	return args;
}


function fillForm(_data, _form) {
//	debugObject(_data, '_data');
	var editorTotal = 0;
	var isStandard = false;
	if (_data.list && _data.list.item && _data.list.item.length) { isStandard = true; }
	
	for (var i = 0; i < _form.elements.length; i++) {
		var field = _form.elements[i];
		var data = _data;
		if (isStandard) {
			data = _data.list.item[0];
		} else if (_data.length) {
			data = _data[0];
		}
		
		if (field.className == 'editor') { editorTotal++; }
		
		if (field.name) {
			var name = field.name;
			var datePart = '';
			
			var dateField = field.name.match('^(.+?)\.(date|time|meridian|merbutton|tz|field|menu)$');
			if (dateField && dateField[2]) {
				name = dateField[1];
				datePart = dateField[2];
			}
			var nameArray = name.split('\.');
//			debugObject(nameArray, 'nameArray');
			var value = '';
			if (isStandard) {
				var container = data;
				for (var j = 0; j < nameArray.length; j++) {
					if (nameArray[j] && (typeof container == 'object')) {
						container = container[nameArray[j]];
					}
				}
				value = container;
			}
			
			else if (nameArray[0] && ((nameArray[0] == 'file') || (nameArray[0] == 'media')) && nameArray[1] && data['item'] && data['item'][nameArray[0]]) {
				value = data['item'][nameArray[0]][nameArray[1]];
// 				log.add(field.name + ': item, ' + nameArray[0] + ', ' + nameArray[1] + ' = ' + value);
			} else if (nameArray[0] && ((nameArray[0] == 'file') || (nameArray[0] == 'media')) && nameArray[1] && data['setting'] && data['setting'][nameArray[0]]) {
				value = data['setting'][nameArray[0]][nameArray[1]];
// 				log.add(field.name + ': item, ' + nameArray[0] + ', ' + nameArray[1] + ' = ' + value);
			} else if (nameArray[0] && nameArray[1] && nameArray[2] && data[nameArray[0]] && data[nameArray[0]][nameArray[1]]) {
				value = data[nameArray[0]][nameArray[1]][nameArray[2]];
// 				log.add(field.name + ': ' + nameArray[0] + ', ' + nameArray[1] + ', ' + nameArray[2] + ' = ' + value);
			} else if (nameArray[0] && nameArray[1] && data[nameArray[0]]) {
				value = data[nameArray[0]][nameArray[1]];
// 				log.add(field.name + ': ' + nameArray[0] + ', ' + nameArray[1] + ' = ' + value);
			} else if (nameArray[0]) {
				value = data[nameArray[0]];
// 				log.add(field.name + ': ' + nameArray[0] + ' = ' + value);
			}
// 			debug('field ' + name + ' = ' + value);
			
			if (value) {
				if (datePart == 'date') {
					var dateArray = value.match('^([0-9]+)\-([0-9]+)\-([0-9]+)');
					if (dateArray[3]) {
						var month = Number(dateArray[2]);
						var day = Number(dateArray[3]);
						field.value = month + '/' + day + '/' + dateArray[1];
					}
				} else if (datePart == 'time') {
					var timeArray = value.match(' ([0-9]+)(:[0-9]+)');
					if (timeArray && timeArray[1] && timeArray[2]) {
						var hour = Number(timeArray[1]);
						if (hour < 1) { hour += 12; }
						else if (hour > 12) { hour -= 12; }
						else { hour = Number(hour); }
						field.value = hour + timeArray[2];
					}
//					debug('time ' + field.name + ' = ' + field.value);
				} else if (datePart == 'meridian') {
					var timeArray = value.match(' ([0-9]+)(:[0-9]+(?::[0-9]+)?)');
					if (timeArray && timeArray[1] && timeArray[2]) {
						var hour = timeArray[1];
						var meridian = 'am';
						if (hour > 11) { meridian = 'pm'; }
						field.value = meridian;
					}
				} else if (datePart == 'merbutton') {
					var timeArray = value.match(' ([0-9]+)(:[0-9]+(?::[0-9]+)?)');
					if (timeArray && timeArray[1] && timeArray[2]) {
						var hour = timeArray[1];
						var meridian = 'am';
						if (hour > 11) { meridian = 'pm'; }
						field.value = meridian;
					}
				} else if (datePart == 'tz') {
					field.value = '-6';
				} else if (datePart == 'field') {
					var valueArray = value.match('^([a-zA-Z0-9_]+)');
					if (valueArray && valueArray[1]) { field.value = valueArray[1]; }
				} else if (datePart == 'menu') {
					var valueArray = value.match('^[a-zA-Z0-9_]+ +(.+)');
					if (valueArray && valueArray[1]) { field.value = valueArray[1]; }
				} else if (field.type == 'checkbox') {
					if (typeof value == 'object') {
						field.checked = false;
						for (var j = 0; j < value.length; j++) {
							if (value[j] == field.value) { field.checked = true; }
						}
					}
					else if (value == field.value) { field.checked = true; }
					else { field.checked = false; }
				} else if (field.type == 'radio') {
					if (value == field.value) { field.checked = true; }
					else { field.checked = false; }
				} else if (field.sm_item && (field.sm_item.type == 'upload')) {
					field.sm_item.addURL(value);
				} else {
					// Make sure it isn't a hidden field for a checkbox
					var is_checkbox = false;
					if (field.type == 'hidden') {
						for (var j = 0; j < _form.elements.length; j++) {
							if ((_form.elements[j].name == field.name) && (_form.elements[j].type == 'checkbox')) { is_checkbox = true; }
						}
					}
					if (!is_checkbox) {
						field.value = value;
						if (field.smIsEditor) {
							if (field.CKeditor.setData) {
								field.CKeditor.setData(value);
								CKEDITOR.on('instanceReady', function() {
									// Added to show CKEditor in Firefox
									if (field.parentNode) {
										field.parentNode.setAttribute('style', 'display: block;');
									}
								} );
							}
							else { CKEDITOR.on('instanceReady', function() {
								field.CKeditor.setData(value);
								// Added to show CKEditor in Firefox
								if (field.parentNode) {
									field.parentNode.setAttribute('style', 'display: block;');
								}
							}); }
						}
					}
				}
			} else {
				if (field.type == 'select-one') {
					var done = false;
					for (var j = 0; j < field.options.length; j++) {
						if (!done && (field.options[j].value == 0)) {
							field.selectedIndex = j;
							done = true;
						}
					}
				} else if (field.type == 'radio') {
					if (field.value == 0) { field.checked = true; }
				}
			}
			if (field.afterLoad) { field.afterLoad(); }
		}
	}
//	for (var i = 0; i < _form.elements.length; i++) {
//		var field = _form.elements[i];
//		if (field.onchange) { debug('onchange ' + field.name); field.onchange(); }
//	}
	
	if (_form.pauseKey && !editorTotal) {
//		debug('unpausing after fillForm');
		unpauseScreen(_form.pauseKey);
	}
// 	if (editorTotal) {
// 		_form.editorTotal = editorTotal;
// 		finishFill(_form);
// 	}
	if (_form.afterFillForm) {
		_form.afterFillForm(_data, _form.afterFillFormArgs);
	}
	unpauseScreen(_form.pauseKey);
}

/*
function finishFill(_form) {
	_form.filled = true;
//	debug('ffill: finished filling form');
	if (_form.editorList) {
//		debug('ffill: found a list');
		for (var i = 0; i < _form.editorList.length; i++) {
			var editorInstance = _form.editorList[i];
//			debug('ffill: going to fill ' + editorInstance);
			fillFCKeditor(editorInstance);
		}
	}
	if (_form.filled && (_form.editorTotal <= _form.editorCnt)) {
//		debug('ffill: all good');
		unpauseScreen(_form.pauseKey);
	}
}

function fillFCKeditor(editorInstance) {
	var editorField = editorInstance.Name.match('^(.+?)-([a-z0-9]+)$');
	if (editorField && editorField[1] && editorField[2] && editorInstance) {
		var form = document.getElementById('form_' + editorField[2]);
		if (form[editorField[1]].value) {
			// Safari doesn't do the insert the first time,
			//   so first I do a bogus insert for Safari before the real one
			if (RegExp(" AppleWebKit/").test(navigator.userAgent)) {
				editorInstance.InsertHtml('');
			}
			// Real insert
			editorInstance.InsertHtml(form[editorField[1]].value);
			
// 			var oCKeditor = CKEDITOR.appendTo('ckeditor_' + form[editorField[1]].name);
// 			if (oCKeditor.setData) { oCKeditor.setData(form[editorField[1]].value); }
// 			else { CKEDITOR.on('loaded', function() { oCKeditor.setData(form[editorField[1]].value); }); }
			
		}
	}
}


function FCKeditor_OnComplete(editorInstance) {
//	debug('onComplete ' + editorInstance);
	finishFCKeditor(editorInstance);
}

function finishFCKeditor(editorInstance) {
	var editorField = editorInstance.Name.match('^(.+?)-([a-z0-9]+)$');
	if (editorField && editorField[1] && editorField[2] && editorInstance) {
		var _form = document.getElementById('form_' + editorField[2]);
		debug('looking for field ' + editorField[1]);
		_form[editorField[1]].editorName = editorInstance.Name;
		_form[editorField[1]].smIsEditor = true;
		_form[editorField[1]].smIsEditorComplete = true;
		if (_form.editorCnt) { _form.editorCnt++; }
		else { _form.editorCnt = 1; }
//		debug('ffck: count ' + _form.editorCnt);
		if (_form.filled) {
//			debug('ffck: fill is finished');
			fillFCKeditor(editorInstance);
		} else if (_form.editorList) {
//			debug('ffck: fill not finished, adding to list');
			_form.editorList.push(editorInstance);
		} else {
//			debug('ffck: fill not finished, starting list');
			_form.editorList = new Array();
			_form.editorList.push(editorInstance);
		}
		if (_form.filled && (_form.editorTotal <= _form.editorCnt)) {
//			debug('ffck: all good');
			unpauseScreen(_form.pauseKey);
		}
		// I think this was for the editor in Page and is no longer needed
		if (_form[editorField[1]].shouldResize) {
			_form[editorField[1]].shouldResize = false;
			_form.parentEditor.resizeY();
		}
	}
}
*/

function sendForm(_url, _function, _form, _data, _functionFail) {
	var args = new Array();
	var exist = new Object();
	var blank = new Object();
	for (var field = 0; field < _form.elements.length; field++) {
		if (_form.elements[field].noSend) {
		} else {
			if (_form.elements[field].smIsEditor) {
// 				var editor = FCKeditorAPI.GetInstance(_form.elements[field].editorName);
// 				_form.elements[field].value = editor.GetXHTML();
// 				_form.elements[_form.elements[field].editorName].noSend = true;
				_form.elements[field].value = _form.elements[field].CKeditor.getData();
			}
			if (_form.elements[field].name) {
				if ((_form.elements[field].type == 'radio') || (_form.elements[field].type == 'checkbox')) {
					if (_form.elements[field].checked) {
						args.push(encodeURIComponent(_form.elements[field].name) + '=' + encodeURIComponent(_form.elements[field].value));
						exist[_form.elements[field].name] = 1;
					} else {
						blank[_form.elements[field].name] = 1;
					}
				} else if (_form.elements[field].type == 'file') {
					var matchArray = _form.elements[field].name.match(/^(\w+)/);
					if (matchArray && matchArray[1]) {
						key = uniqueKey();
						if (_form.elements[field].value) {
							args.push(encodeURIComponent(matchArray[1] + '.key') + '=' + encodeURIComponent(key));
							submitToiFrame(_form, '/members/upload?prefix=' + matchArray[1] + '&key=' + key, key);
						} else if (_form.elements[matchArray[1] + '.id'] && _form.elements[matchArray[1] + '.id'].value) {
							submitToiFrame(_form, '/members/upload?prefix=' + matchArray[1] + '&id=' + _form.elements[matchArray[1] + '.id'].value, key);
						}
					}
				} else {
					args.push(encodeURIComponent(_form.elements[field].name) + '=' + encodeURIComponent(_form.elements[field].value));
				}
			}
		}
	}
	
	for (var fieldname in blank) {
		if (!exist[fieldname]) {
			args.push(encodeURIComponent(fieldname) + '=');
		}
	}
	if (_data) {
		for (var fieldname in _data) {
			args.push(encodeURIComponent(fieldname) + '=' + encodeURIComponent(_data[fieldname]));
		}
	}
	var query_string = args.join('&');
	sendRequest(_url, _function, _form, query_string, _functionFail);
}

function submitToiFrame(_form, _url, _id) {
	debug('Sending to iframe ' + _id + ' to ' + _url);
	if (_form && _form.pauseElement) {
		_form.pauseKey = uniqueKey();
		pauseScreen(_form.pauseKey, _form.pauseElement, _form.pauseMessage);
	}
	var iframe = document.createElement('iframe')
	iframe.setAttribute('id', 'upload_' + _id);
	iframe.setAttribute('name', 'upload_' + _id);
	iframe.setAttribute('class', 'upload_frame');
	iframe.style.display = 'none';
	document.body.appendChild(iframe);
	_form.action = _url
	_form.target = 'upload_' + _id;
	_form.submit();
}

function submitToiFrameFinish(_windowKey, _listKey) {
	debug('_windowKey: ' + _windowKey);
	debug('_listKey: ' + _listKey);
	if (_windowKey) {
		var window = windows.findWindowByKey(_windowKey);
		if (window) {
			if (window.form) { unpauseScreen(window.form.pauseKey); }
			window.close();
		}
	}
	if (_listKey) {
		var listElement = document.getElementById('smlist_' + _listKey);
		if (listElement && listElement.sm_list) { listElement.sm_list.reload(); }
	}
}

function uniqueKey() {
	var d = new Date();
	var num = d.getTime().toString().substring(5) + Math.round(10000*Math.random()).toString();
	var ascii = num % 52 + 65;
	if (ascii > 90) { ascii += 6; }
	var key = String.fromCharCode(ascii);
	num = Math.floor(num / 52);
	while (num > 0) {
		var ascii = num % 62 + 48;
		if (ascii > 57) { ascii += 7; }
		if (ascii > 90) { ascii += 6; }
		key += String.fromCharCode(ascii);
		num = Math.floor(num / 62);
	}
	return key;
}

function sendObject(_url, _function, _object, _data) {
	if (_data) {
		var args = new Array();
		for (var key in _data) {
			args.push(encodeURIComponent(key) + '=' + encodeURIComponent(_data[key]));
		}
		var query_string = args.join('&');
		sendRequest(_url, _function, _object, query_string);
	}
}


function sendArray(_url, _function, _object, _name, _data) {
	if (_name && _data) {
		var args = new Array();
		for (var i = 0; i < _data.length; i++) {
			args.push(encodeURIComponent(_name) + '=' + encodeURIComponent(_data[i]));
		}
		var query_string = args.join('&');
		sendRequest(_url, _function, _object, query_string);
	}
}


function sendRequest(_url, _function, _object, _data, _functionFail) {
	// branch for native XMLHttpRequest object
	if (_object && _object.pauseElement) {
		_object.pauseKey = uniqueKey();
		pauseScreen(_object.pauseKey, _object.pauseElement, _object.pauseMessage);
	}
	var cacheKey = uniqueKey();
	if (window.XMLHttpRequest) {
		var req = new XMLHttpRequest();
		req.processFunction = _function;
		req.processFunctionFail = _functionFail;
		req.callingObject = _object;
		req.url = _url;
		req.onreadystatechange = processRequest;
		if (_data) {
			debug('POST ' + _url);
			req.open("POST", _url, true);
			req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			req.send(_data);
		} else {
			if (_url.match(/\?/)) { _url = _url + '&' + cacheKey; }
			else { _url = _url + '?' + cacheKey; }
			debug('GET ' + _url);
			req.open("GET", _url, true);
			req.send(null);
		}
		reqList.push(req);
	// branch for IE/Windows ActiveX version
	} else if (window.ActiveXObject) {
		var req = new ActiveXObject("Microsoft.XMLHTTP");
		if (req) {
			req.onreadystatechange = processRequest;
			if (_data) {
				req.open("POST", _url, true);
				req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
				req.send(_data);
			} else {
				if (_url.match(/\?/)) { _url = _url + '&' + cacheKey; }
				else { _url = _url + '?' + cacheKey; }
				req.open("GET", _url, true);
				req.send(null);
			}
			req.processFunction = _function;
			req.processFunctionFail = _functionFail;
			req.callingObject = _object;
			reqList.push(req);
		}
	}
}


function processRequest() {
//	only if req shows "loaded"
	var complete = false;
	for (var i = 0; i < reqList.length; i++) {
		var req = reqList[i];
//		debug('--> check ' + req.url);
		if (req.complete) {
			complete = true;
		} else if (req.readyState == 4) {
//			debug('----> ready 4 ' + req.url + ', status=' + req.status);
			// only if "OK"
			if (req.status == 200) {
				req.complete = true;
				complete = true;
//				debug('------> 200: processRequest(' + req.url + ')');
				var results = req.responseText;
				var response;
				if (req.responseText && req.responseText.match(/^\{/)) {
					response = JSON.parse(req.responseText);
				} else if (req.responseXML) {
					response = convertXMLtoObj(req.responseXML, 0);
				}
				if (req.processFunction) {
					req.processFunction(response.sitemasonAPI, req.callingObject);
				} else if (req.callingObject && req.callingObject.pauseKey) {
					unpauseScreen(req.callingObject.pauseKey);
				}
			} else {
				req.complete = true;
				complete = true;
				if (req.processFunctionFail) {
					req.processFunctionFail(req.callingObject);
				} else {
					alert("There was a problem connecting to the server:\n" + req.statusText);
					if (req.callingObject && req.callingObject.pauseKey) {
						unpauseScreen(req.callingObject.pauseKey);
					}
				}
			}
		}
	}
	if (complete) {
		var tmpArray = new Array();
		for (var j = 0; j < reqList.length; j++) {
			if (!reqList[j].complete) {
//				debug('--> keeping ' + reqList[j].url);
				tmpArray.push(reqList[j]);
			}
		}
		reqList = tmpArray;
	}
}


var pauseScreenList = new Object();

function pauseScreen(_name, _pauseObject, _pauseMessage) {
	if (_name && !pauseScreenList[_name] && _pauseObject) {
		pauseScreenList[_name] = createDiv({ className: 'pause_screen' });
		pauseScreenList[_name].style.position = 'absolute';
		pauseScreenList[_name].style.top = _pauseObject.offsetTop + 'px';
		pauseScreenList[_name].style.left = _pauseObject.offsetLeft + 'px';
		pauseScreenList[_name].style.width = (_pauseObject.offsetWidth - 2) + 'px';
		pauseScreenList[_name].style.height = (_pauseObject.offsetHeight - 2) + 'px';
		_pauseObject.parentNode.appendChild( pauseScreenList[_name] );
		if (!_pauseMessage) { _pauseMessage = 'Loading...'; }
		_pauseMessage += '<br /><img src="/members/resources/interface/images/indicators/activity_blue_bar.gif" width="220" height="19" alt="" />';
		var pauseMessage = createDiv({ className: 'message', html: _pauseMessage });
// 		var matchArray = pauseScreenList[_name].style.height.match(/(\d+)/);
// 		if (matchArray && matchArray[1]) {
// 			pauseMessage.style.marginTop = Math.floor((matchArray[1]/2) - 30) + 'px';
// 		}
		pauseScreenList[_name].appendChild( pauseMessage );
	}
}


function unpauseScreen(_name) {
	if (_name) {
		if (pauseScreenList[_name]) {
			if (pauseScreenList[_name]) {
				pauseScreenList[_name].parentNode.removeChild(pauseScreenList[_name]);
			}
			delete pauseScreenList[_name];
		}
	}
}


function convertXMLtoObj(_xml, _depth) {
	var xml = _xml;
	var hash = new Object();
	var tabs = '';
	for (var tab = 0; tab < _depth; tab++) { tabs += '- '; }
	if (xml && xml.childNodes && (typeof xml == 'object')) {
		var cnt = 0;
		for (var a = 0; a < xml.childNodes.length; a++) {
			var name = xml.childNodes[a]['nodeName'];
			if (xml.childNodes[a]['nodeName'] == '#text') {
			} else if (typeof xml.childNodes[a] == 'object') {
				var type = getAttr(xml.childNodes[a], 'type');
				if (type == 'array') {
					if (!hash[name]) {
//						debug(tabs + name);
						if ((typeof xml.childNodes[a] == 'object') && (xml.childNodes[a].childNodes.length > 1)) {
							var value = xml.childNodes[a].firstChild.data;
//							debug(tabs + '- |' + cnt + '| ' + value + ' (' + typeof xml.childNodes[a] + ', ' + xml.childNodes[a].childNodes.length + ')');
							hash[name] = [convertXMLtoObj(xml.childNodes[a], Number(_depth) + 2)];
						} else if (xml.childNodes[a].childNodes.length == 0) {
							hash[name] = [''];
						} else if (xml.childNodes[a].firstChild) {
							var value = xml.childNodes[a].firstChild.data;
//							debug(tabs + '- |' + cnt + '| ' + value);
							hash[name] = [value];
						}
					} else {
						if ((typeof xml.childNodes[a] == 'object') && (xml.childNodes[a].childNodes.length > 1)) {
							var value = xml.childNodes[a].firstChild.data;
//							debug(tabs + '- [' + cnt + '] ' + value + ' (' + typeof xml.childNodes[a] + ', ' + xml.childNodes[a].childNodes.length + ')');
							hash[name].push(convertXMLtoObj(xml.childNodes[a], Number(_depth) + 2));
						} else if (xml.childNodes[a].childNodes.length == 0) {
							hash[name] = [''];
						} else if (xml.childNodes[a].firstChild) {
							var value = xml.childNodes[a].firstChild.data;
//							debug(tabs + '- [' + cnt + '] ' + value);
							hash[name].push(value);
						}
					}
					cnt++;
				} else if ((typeof xml.childNodes[a] == 'object') && (xml.childNodes[a].childNodes.length > 1)) {
					var value = '';
					var isString = true;
					for (var i = 0; i < xml.childNodes[a].childNodes.length; i++) {
						if (typeof xml.childNodes[a].childNodes[i].data != 'string') { isString = false; }
					}
					if (isString) {
						for (var i = 0; i < xml.childNodes[a].childNodes.length; i++) {
							value = value + xml.childNodes[a].childNodes[i].data;
						}
//						debug(tabs + name + ': ' + value);
						hash[name] = value;
						cnt++;
					} else {
//						debug(tabs + name + ':: ' + value + ' (' + typeof xml.childNodes[a] + ', ' + xml.childNodes[a].childNodes.length + ')');
						hash[name] = convertXMLtoObj(xml.childNodes[a], Number(_depth) + 1);
						cnt++;
					}
				} else if (xml.childNodes[a].firstChild) {
					var value = xml.childNodes[a].firstChild.data;
//					debug(tabs + name + ': ' + value);
					hash[name] = value;
					cnt++;
				} else {
//					debug('convertXMLtoObj: Found a blank XML element - ' + name);
				}
			}
		}
	}
	return hash;
}


function readLocationHash(_key) {
	var hash = location.hash;
	var hashValues = [];
	if (hash.match(/=/)) {
		hash = hash.replace(/^#/, '');
		var pairs = hash.split('&');
		for (var key in pairs) {
			var nv = pairs[key].split('=');
			var name = decodeURIComponent(nv[0]);
			hashValues[name] = decodeURIComponent(nv[1]);
		}
	}
	if (_key) { return hashValues[_key]; }
	else { return hashValues; }
}

function removeFromLocationHash(_valuesToHide) {
	var hashValues = readLocationHash();
	var valuesToHide = [];
	if (!_valuesToHide) { location.hash = ''; return; }
	else if (typeof _valuesToHide == 'object') { valuesToHide = _valuesToHide; }
	else if (typeof _valuesToHide == 'string') { valuesToHide = [_valuesToHide]; }
	else { return; }
	
	var shouldRewriteHash = false;
	var newHash = [];
	for (var name in hashValues) {
		var found = false;
		for (var i = 0; i < valuesToHide.length; i++) {
			if (valuesToHide[i] == name) { found = true; }
		}
		if (found) { shouldRewriteHash = true; }
		else { newHash.push(encodeURIComponent(name) + '=' + encodeURIComponent(hashValues[name])); }
	}
	if (shouldRewriteHash) { location.hash = newHash.join('&'); }
}

// Load HTML from a URL

// Sets '.html' in the given object to the contents of the given URL.
//   loadHTML(this, '/members/resources/interface/html/tag_entry.html');
function loadHTML(_object, _url) {
	sendHTMLrequest(_url, _common_setHTML, _object);
}

function _common_setHTML(_html, _object) {
	_object.html = _html;
}

// Calls the given function and passes the text contents of the given URL as the first argument. An optional object may be given that will be passed through to the called function as the second argument.
//   sendHTMLrequest('/members/resources/interface/html/tag_entry.html', setContents, this);
function sendHTMLrequest(_url, _function, _object) {
	// branch for native XMLHttpRequest object
	if (window.XMLHttpRequest) {
		var htmlReq = new XMLHttpRequest();
		htmlReq = new XMLHttpRequest();
		htmlReq.processFunction = _function;
		htmlReq.callingObject = _object;
		htmlReq.onreadystatechange = _common_processHTMLrequest;
		htmlReq.open("GET", _url, true);
		htmlReq.send(null);
		reqList.push(htmlReq);
	// branch for IE/Windows ActiveX version
	} else if (window.ActiveXObject) {
		var htmlReq = new ActiveXObject("Microsoft.XMLHTTP");
		if (htmlReq) {
			htmlReq.processFunction = _function;
			htmlReq.callingObject = _object;
			htmlReq.onreadystatechange = _common_processHTMLrequest;
			htmlReq.open("GET", _url, true);
			htmlReq.send();
			reqList.push(htmlReq);
		}
	}
}

function _common_processHTMLrequest() {
//	only if req shows "loaded"
	var complete = false;
	for (var i = 0; i < reqList.length; i++) {
		var htmlReq = reqList[i];
//		debug('--> check ' + htmlReq.url);
		if (htmlReq.complete) {
			complete = true;
		} else if (htmlReq.readyState == 4) {
//			debug('----> ready 4 ' + htmlReq.url);
			// only if "OK"
			if (htmlReq.status == 200) {
				htmlReq.complete = true;
				complete = true;
				var results = htmlReq.responseText;
				var parts = results.match(/^(.*?)(?:\n|\r)/m);
				var body = results.replace(/^(.*?)(?:\n|\r)/m, '');
				if (htmlReq.processFunction) {
					htmlReq.processFunction(results, htmlReq.callingObject);
				}
			} else {
				alert("There was a problem retrieving the HTML:\n" + htmlReq.statusText);
			}
		}
	}
	if (complete) {
		var tmpArray = new Array();
		for (var j = 0; j < reqList.length; j++) {
			if (!reqList[j].complete) {
//				debug('--> keeping ' + reqList[j].url);
				tmpArray.push(reqList[j]);
			}
		}
		reqList = tmpArray;
	}
}


// HTML and DOM functions

// Returns the number of pixels from the left side of the window for the given element.
function findPosX(obj, _stop) {
	var curleft = 0;
	var cnt = 0;
	var stop = 'stop traversing';
	if (_stop) { stop = _stop; }
	if (obj.offsetParent) {
		while (obj.offsetParent && (obj.id != stop)) {
//			cnt += 1;
//			log.add(cnt + ': ' + curleft + ' (left) +=' + obj.offsetLeft + ' - ' + obj.id);
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
		}
	}
	else if (obj.x) { curleft += obj.x; }
	return curleft;
}

// Returns the number of pixels from the top of the window for the given element.
function findPosY(obj, _stop) {
	var curtop = 0;
	var cnt = 0;
	var stop = 'stop traversing';
	if (_stop) { stop = _stop; }
	if (obj.offsetParent) {
		while (obj.offsetParent && (obj.id != stop)) {
//			cnt += 1;
//			log.add(cnt + ': ' + curtop + ' (top) +=' + obj.offsetTop + ' - ' + obj.id);
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else if (obj.y) { curtop += obj.y; }
	return curtop;
}

// Returns a div with the given attributes.
function createDiv(_param) {
	var newDiv = document.createElement('div');
	if (_param) {
		if (_param.id) { newDiv.setAttribute('id', _param.id); }
		if (_param.name) { newDiv.setAttribute('name', _param.name); }
		if (_param.className) { newDiv.setAttribute('class', _param.className); }
		if (_param.html) { newDiv.innerHTML = _param.html; }
		if (_param.style) {
			for (var name in _param.style) {
				var value = _param.style[name];
				newDiv.style[name] = value;
			}
		}
		if (_param.onmousemove) { newDiv.onmousemove = _param.onmousemove; }
		if (_param.onmousedown) { newDiv.onmousedown = _param.onmousedown; }
		if (_param.onmouseup) { newDiv.onmouseup = _param.onmouseup; }
	}
	return newDiv;
}

// Returns an array of the option values for the given select element.
function selectToArray(_select) {
	var newArray = new Array();
	if (_select && _select.options) {
		for (var i = 0; i < _select.options.length; i++) {
			if (_select.options[i] && _select.options[i].value) {
				newArray.push(_select.options[i].value);
			}
		}
	}
	return uniqueArray(newArray);
}

function selectToArrayObject(_select) {
	var newArray = new Array();
	if (_select && _select.options) {
		for (var i = 0; i < _select.options.length; i++) {
			if (_select.options[i] && _select.options[i].text) {
				newArray.push( { label: _select.options[i].text, value: _select.options[i].value, selected: _select.options[i].selected } );
			}
		}
	}
	return uniqueArray(newArray);
}

function selectedOptionsToArray(_select) {
	var newArray = new Array();
	if (_select && _select.options) {
		for (var i = 0; i < _select.options.length; i++) {
			if (_select.options[i] && _select.options[i].selected && _select.options[i].value) {
				newArray.push(_select.options[i].value);
			}
		}
	}
	return uniqueArray(newArray);
}

// Replaces options in a select with the given array.
function arrayToSelect(_array, _select) {
	if (_array && _select && _select.options) {
		var newArray = uniqueArray(_array);
		_select.options.length = 0;
		for (var i = 0; i < newArray.length; i++) {
			if ((typeof newArray[i] == 'object') && newArray[i].label) {
				var is_selected = false;
				if (newArray[i].selected) { is_selected = true; }
				_select.appendChild(new Option(newArray[i].label, newArray[i].value, is_selected, is_selected));
			} else if (newArray[i]) {
				_select.appendChild(new Option(newArray[i], newArray[i], false, false));
			}
		}
		return true;
	}
	return false;
}

// Adds options in a select with the given array.
function addOptionsToSelect(_array, _select) {
	if (_array && _select) {
		var selectOptions = selectToArrayObject(_select);
		combineArrays(selectOptions, _array);
		arrayToSelect(selectOptions, _select);
		return true;
	}
	return false;
}

function removeOptionsFromSelect(_select, _array) {
	if (_array && _select) {
		var newArray = Array();
		var selectOptions = selectToArrayObject(_select);
		for (var i = 0; i < selectOptions.length; i++) {
			if (selectOptions[i] && (typeof selectOptions[i] == 'object')) {
				if (!arrayContains(_array, selectOptions[i].value)) {
					newArray.push( { label: selectOptions[i].label, value: selectOptions[i].value, selected: selectOptions[i].selected } );
				}
			} else if (selectOptions[i]) {
				if (!arrayContains(_array, selectOptions[i])) {
					newArray.push(selectOptions[i]);
				}
			}
		}
		arrayToSelect(newArray, _select);
		return true;
	}
	return false;
}

// Drop shadows
function enableDropShadow(_element, _color, _offsetX, _offsetY, _radius) {
	if (_element) {
		var color = _color || 'black';
		var offsetX = Number(_offsetX) || 0;
		var offsetY = Number(_offsetY) || 0;
		var radius = Number(_radius) || 0;
		if (navigator.userAgent.match('MSIE')) {
			var shadowElement;
			var ieRadius = Math.ceil(radius * .4);
			if (_element.sm_shadowElement) {
				shadowElement = _element.sm_shadowElement;
				shadowElement.style.backgroundColor = _color;
				shadowElement.style.top = (_element.offsetTop - ieRadius + offsetY) + 'px';
				shadowElement.style.left = (_element.offsetLeft - ieRadius + offsetX) + 'px';
				shadowElement.style.width = _element.offsetWidth + 'px';
				shadowElement.style.height = _element.offsetHeight + 'px';
				shadowElement.style.filter = 'progid:DXImageTransform.Microsoft.Blur(enabled=true,pixelradius=' + ieRadius + ')';
				shadowElement.style.display = '';
			} else {
				shadowElement = document.createElement('div');
				shadowElement.style.position = 'absolute';
				shadowElement.style.backgroundColor = _color;
				shadowElement.style.top = (_element.offsetTop - ieRadius + offsetY) + 'px';
				shadowElement.style.left = (_element.offsetLeft - ieRadius + offsetX) + 'px';
				shadowElement.style.width = _element.offsetWidth + 'px';
				shadowElement.style.height = _element.offsetHeight + 'px';
				shadowElement.style.filter = 'progid:DXImageTransform.Microsoft.Blur(enabled=true,pixelradius=' + ieRadius + ')';
				shadowElement.sm_shadowValues = {
					radius:		ieRadius,
					offsetX:	offsetX,
					offsetY:	offsetY
				};
				_element.parentNode.insertBefore(shadowElement, _element);
				_element.sm_shadowElement = shadowElement;
			}
			return shadowElement;
		} else {
			_element.style.boxShadow = color + ' ' + offsetX +'px ' + offsetY +'px ' + radius +'px';
			_element.style.webkitBoxShadow = color + ' ' + offsetX +'px ' + offsetY +'px ' + radius +'px';
			_element.style.MozBoxShadow = color + ' ' + offsetX +'px ' + offsetY +'px ' + radius +'px';
		}
	}
}

function moveDropShadow(_element) {
	if (navigator.userAgent.match('MSIE')) {
		if (_element.sm_shadowElement) {
			var values = _element.sm_shadowElement.sm_shadowValues;
			_element.sm_shadowElement.style.top = (_element.offsetTop - values.radius + values.offsetY) + 'px';
			_element.sm_shadowElement.style.left = (_element.offsetLeft - values.radius + values.offsetX) + 'px';
		}
	}
}

function hideDropShadow(_element) {
	if (navigator.userAgent.match('MSIE')) {
		if (_element.sm_shadowElement) {
			_element.sm_shadowElement.style.display = 'none';
		}
	}
}

function disableDropShadow(_element) {
	if (navigator.userAgent.match('MSIE')) {
		if (_element.sm_shadowElement) {
			_element.parentNode.removeChild(_element.sm_shadowElement);
			delete(_element.sm_shadowElement);
		}
	} else {
		_element.style.webkitBoxShadow = '';
		_element.style.MozBoxShadow = '';
	}
}

// Gradients (incomplete)
function enableGradient(_element, _direction, _startColor, _endColor) {
	if (_element) {
		if (!_startColor && _element.style.backgroundColor) {
			_startColor = _element.style.backgroundColor;
		}
		debug('_startColor: ' + _startColor);
		if (_startColor) {
			if (!_endColor) {
				
			}
		}
	}
// 	background: -webkit-gradient(linear, left top, 50% 100%, from(#daddeb), to(#9a9fb6));
// 	background: -moz-linear-gradient(top left, #daddeb, #9a9fb6);
// 	-ms-filter: "progid:DXImageTransform.Microsoft.Gradient(Enabled=true, startColorstr=#daddeb, endColorstr=#9a9fb6)";
}

// Text Functions
function ucFirst(value) {
   return value.substr(0, 1).toUpperCase() + value.substr(1);
}

function reduceText(_element, _maxWidth, _minFontSize) {
	if (_element && _maxWidth) {
		if (!_minFontSize) { _minFontSize = 7; }
		var fontSizeStyle = getStyle(_element, 'font-size');
		var fontSizeParts = fontSizeStyle.match(/^(\d+)px/);
		var fontSize = _minFontSize;
		if (fontSizeParts) { fontSize = fontSizeParts[1]; }
		else { return false; }
		if (fontSize <= _minFontSize) { return false; }
		
		var answer = true;
		if (_element.offsetWidth > _maxWidth) {
			fontSize--;
			_element.style.fontSize = fontSize + 'px';
			answer = reduceText(_element, _maxWidth, _minFontSize);
		}
		return answer;
	}
}

function summarize(_element, _maxWidth, _location, _amount) {
	if (_element && _maxWidth) {
		if (!_element.originalText) { _element.originalText = _element.innerHTML; }
		var workingText = _element.originalText;
		if (!_location) { _location = 'middle'; }
		if (!_amount) { _amount = 0; }
		if (workingText.length < 10) { return false; }
		
		if (_element.offsetWidth > _maxWidth) {
			_amount += 2;
			var tempAmount = Number(_amount + 3);
			if (_location == 'left') {
				var regEx = new RegExp('^.{' + tempAmount + '}');
				workingText = _element.originalText.replace(regEx, '...');
			} else if (_location == 'right') {
				var regEx = new RegExp('(.{' + tempAmount + '})$');
				workingText = _element.originalText.replace(regEx, '...');
			} else if (_location == 'middle') {
				var halfLength = Math.floor((_element.originalText.length - _amount)/2);
				var regEx = new RegExp('^(.{' + halfLength + '})(?:.{' + tempAmount + '})');
				workingText = _element.originalText.replace(regEx, "$1...");
			}
			_element.innerHTML = workingText;
			summarize(_element, _maxWidth, _location, _amount);
		}
		return true;
	}
}

// from Quirks Mode (modified) - http://www.quirksmode.org/dom/getstyles.html
function getStyle(_element, _styleProp) {
	function regexReplaceWithUppercase(str) {
		var newStr = str.replace(/\-/, '');
		return newStr.toUpperCase();
	}
	if (_element.currentStyle) {
		var newStyleProp = _styleProp.replace(/(\-.)/g, regexReplaceWithUppercase);
		var y = _element.currentStyle[newStyleProp];
	} else if (window.getComputedStyle) {
		var y = document.defaultView.getComputedStyle(_element, null).getPropertyValue(_styleProp);
	}
	return y;
}


// Array Functions

function addToArray(_array, _item) {
	_array.push(_item);
	var newArray = uniqueArray(_array);
	return newArray;
}

function removeFromArray(_array, _item) {
	var newArray = new Array();
	for (var i = 0; i < _array.length; i++) {
		if (_array[i] != _item) { newArray.push(_array[i]); }
	}
	return newArray;
}

function arrayToList(_array) {
	var newArray = uniqueArray(_array);
	var list = newArray.join(', ');
	return list;
}

function listToArray(_list) {
	var newArray = new Array();
	if (_list) {
		var _array = _list.split(/\s*,\s*/);
		if (_array) {
			newArray = uniqueArray(_array);
		}
	}
	return newArray;
}

function arrayToCR(_array) {
	var newArray = uniqueArray(_array);
	var list = newArray.join("\n");
	return list;
}

function CRToArray(_list) {
	var newArray = new Array();
	if (_list) {
		var _array = _list.split(/\s*\n\s*/);
		if (_array) {
			newArray = uniqueArray(_array);
		}
	}
	return newArray;
}

function uniqueArray(_array) {
	var newArray = new Array();
	if (_array) {
		for (var i = 0; i < _array.length; i++) {
			if (_array[i] && !arrayContains(newArray, _array[i])) { newArray.push(_array[i]); }
		}
	}
	var sortedArray = newArray.sort(sortAlpha);
	return sortedArray;
}

function arrayContains(_array, _string) {
	if (_array && _string) {
		for (var i = 0; i < _array.length; i++) {
			if (typeof _array[i] == 'object') {
				if ((typeof _string == 'object') && (_array[i] == _string)) { return true; }
				else if (_array[i].value && (_array[i].value == _string)) { return true; }
			} else if (_array[i] == _string) { return true; }
		}
	}
	return false;
}

function indexInArray(_array, _string) {
	if (_array && _string) {
		for (var i = 0; i < _array.length; i++) {
			if (typeof _array[i] == 'object') {
				if ((typeof _string == 'object') && (_array[i] == _string)) { return i; }
				else if (_array[i].value && (_array[i].value == _string)) { return i; }
			} else if (_array[i] == _string) { return i; }
		}
	}
	return;
}

function combineArrays(_array1, _array2) {
	if (_array1 && _array2) {
		for (var i = 0; i < _array2.length; i++) {
			_array1.push(_array2[i]);
		}
	}
}

function sortAlpha(a, b) {
	var al;
	var bl;
	if ((typeof a == 'object') && a.label) { al = a.label.toLowerCase(); }
	else { al = a.toLowerCase(); }
	if ((typeof b == 'object') && b.label) { bl = b.label.toLowerCase(); }
	else { bl = b.toLowerCase(); }
	if (al < bl) { return -1; }
	else if (al > bl) { return 1; }
	else { return 0; }
}

function toArray(_object, _key) {
	var newArray = new Array();
	if (typeof _object == 'object') {
		for (var i = 0; i < _object.length; i++) {
			if (_key && (typeof _object[i] == 'object') && _object[i][_key]) {
				newArray.push(_object[i][_key]);
			} else if (typeof _object[i] == 'string') {
				newArray.push(_object[i]);
			}
		}
	} else if (typeof _object == 'string') {
		newArray.push(_object);
	}
	return uniqueArray(newArray);
}


// Debugging
//   Uses Firebug's console API when available. http://getfirebug.com/console.html

log = new Log('debug');
function Log(_id) {
	this.element = document.getElementById(_id);
	if (this.element) {
		this.element.style.display = 'none';
	}
	this.active = false;
	this.show = _logShow;
	this.hide = _logHide;
	this.scrollOff = _logScrollOff;
	this.scrollOn = _logScrollOn;
	this.clear = _logClear;
	this.add = _logAdd;
	this.replace = _logReplace;
	this.height = 150;
	this.odd = true;
}

function _logShow() {
	this.active = true;
	if (this.element) {
		this.element.style.height = Number(log.height - 2) + 'px';
		this.element.style.display = '';
	}
}

function _logHide() {
	this.active = false;
	if (this.element) {
		this.element.style.display = 'none';
	}
}

function _logScrollOff() {
	if (this.element) {
		this.element.style.overflow = 'hidden';
	}
}

function _logScrollOn() {
	if (this.element) {
		this.element.style.overflow = 'scroll';
	}
}

function _logClear() {
	if (this.active) {
		this.odd = true;
		if (this.element) {
			this.element.innerHTML = '';
		}
	}
}

function _logAdd(_text) {
	if (this.active) {
		this.show();
		if (!_text) {
			_text = '&nbsp;';
		}
		if (this.element) {
			if (this.odd) {
				this.element.appendChild( createDiv( { className: 'odd', html: _text } ) );
				this.odd = false;
			} else {
				this.element.appendChild( createDiv( { className: 'even', html: _text } ) );
				this.odd = true;
			}
			this.element.scrollTop = this.element.scrollHeight - this.height + 17;
		}
	}
}

function _logReplace(_text) {
	if (this.active) {
		this.clear();
		this.add(_text);
	}
}

function debugInfo(_text) { debug(_text, 'info'); }
function debugWarn(_text) { debug(_text, 'warn'); }
function debugError(_text) { debug(_text, 'error'); }

function debug(_text, _level) {
	if (arguments && arguments.callee && arguments.callee.caller) {
		var callerFunc = arguments.callee.caller.toString();
		var callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous");
		_text = callerFuncName + ': ' + _text;
	}
	if (window.console) {
		if (_level == 'info') { console.info("%s", _text); }
		else if (_level == 'warn') { console.warn("%s", _text); }
		else if (_level == 'error') { console.error("%s", _text); }
		else { console.log("%s", _text); }
	}
	if (log) {
		log.add(_text);
	}
}

function debugObject(_object, _label, _limit) {
	if (arguments && arguments.callee && arguments.callee.caller) {
		var callerFunc = arguments.callee.caller.toString();
		var callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous");
		_label = callerFuncName + ': ' + _label;
	}
	if (window.console) {
		console.info("%s", _label);
		if (console.dir) {
			console.dir(_object);
		} else {
			var output = printObject(_object, _limit, _label);
			console.log(output);
		}
	}
	if (log && log.active) {
		var output = printObject(_object, _limit, _label);
		log.add('<hr />' + output + '<hr />');
	}
}

function debugClear() {
	if (log) {
		log.clear();
	}
}

var printObject_count = 0;
function printObject(_object, _limit, _label, _args) {
	var content = '';
	if (_label) { content = _label + '<br />'; }
	if (!_limit || (_limit == 0)) { _limit = 7; }
	var _loop_limit = 150;
	var _total_limit = 500;
	var _depth = 1;
	if (_args) { _depth = _args.depth; }
	else { printObject_count = 0; }
	if (_object) {
		if (printObject_count < Number(_total_limit)) {
			if (_object && (_depth == 0) && _label) {
				content = 'object ' + _label + '<br />';
				_depth = Number(_depth) + 1;
			}
			var tabs = '';
			for (var tab = 0; tab < _depth; tab++) { tabs += ': . '; }
			if (typeof _object == 'object') {
	//			debug('! ' + typeof _object + ' ' + _object + ' ' + _object.length + ' ' + _depth);
				var length_count = 0;
				var shouldContinue = true;
				var cnt = 0;
				while (shouldContinue) {
					if (_object[cnt]) {
						var i = _object[cnt];
						cnt++;
	// 				for (var i in _object) {
						length_count++;
						if (length_count < Number(_loop_limit)) {
							printObject_count++;
							var lineNumbers;
							if (printObject_count < 10) { lineNumbers = '...' + printObject_count; }
							else if (printObject_count < 100) { lineNumbers = '..' + printObject_count; }
							else if (printObject_count < 1000) { lineNumbers = '.' + printObject_count; }
							lineNumbers += ',';
							if (length_count < 10) { lineNumbers += '..' + length_count; }
							else if (length_count < 100) { lineNumbers += '.' + length_count; }
							var label = i;
							if (_object.length) { label = '[' + i + ']'; }
							if (typeof _object[i] == 'object') {
								if (hasProperties(_object[i])) {
									if (Number(_depth) < Number(_limit)) {
										if ((_depth > 1) && ((i == 'element') || (i == 'subelement') || (i == 'parent') || (i == 'form') || (i == 'parentNode') || (i == 'previousSibling') || (i == 'nextSibling') || (i == 'body'))) {
											content += tabs + label + ' -- LIMITED from element list<br />';
	// 										debug(lineNumbers + ' ' + tabs + label + ' -- LIMITED from element list<br />');
										} else {
											content += tabs + label + ' -- object<br />';
	// 										debug(lineNumbers + ' ' + tabs + label + ' -- object<br />');
											content += printObject(_object[i], _limit, null, {
												depth:	Number(_depth) + 1
											});
										}
									} else {
										content += tabs + label + ' -- LIMITING to depth of ' + _limit + '<br />';
	// 									debug(lineNumbers + ' ' + tabs + label + ' -- LIMITING to depth of ' + _limit + '<br />');
									}
								} else {
									content += tabs + label + ': (null)<br />';
	// 								debug(lineNumbers + ' ' + tabs + label + ': (null)<br />');
								}
							} else if (typeof _object[i] == 'function') {
								content += tabs + 'function ' + label + '();<br />';
	// 							debug(lineNumbers + ' ' + tabs + 'function ' + label + '();<br />');
							} else if (typeof _object[i] == 'string') {
								content += tabs + label + ': ' + _object[i] + '<br />';
	// 							debug(lineNumbers + ' ' + tabs + label + ': ' + _object[i] + '<br />');
							} else {
								content += tabs + label + ': ' + _object[i] + '<br />';
	// 							debug(lineNumbers + ' ' + tabs + label + ': ' + _object[i] + '<br />');
							}
						} else if (length_count == Number(_loop_limit)) {
							content += tabs + 'LIMITING to length of ' + _loop_limit + '<br />';
	// 						debug(tabs + 'LIMITING to length of ' + _loop_limit + '<br />');
						}
					} else { shouldContinue = false;}
				}
			} else {
				content += _object;
			}
		} else if (printObject_count == Number(_total_limit)) {
			content += tabs + 'LIMITING to total length of ' + _total_limit + '<br />';
// 			debug(tabs + 'LIMITING to length of ' + _total_limit + '<br />');
		}
	}
	return content;
}

// Workaround to get IE8 to work. It doesn't seem to have getAttribute where others do.
function getAttr(_object, _name) {
	var answer;
	if (_object && (typeof _object == 'object')) {
// 		if (_object.getAttribute) {
// 			answer = _object.getAttribute(_name);
		if (_object.attributes) {
			for (var i = 0; i < _object.attributes.length; i++) {
				if (_object.attributes[i].name == _name) {
					answer = _object.attributes[i].value;
				}
			}
		}
	}
	return answer;
}

function hasProperties(_object) {
	try { for (var k in _object) throw(null); throw('empty') }
    catch(e) { if (e) return false; }
    return true;
}

// Workaround for getElementsByClassName for IE8.
// Developed by Robert Nyman, http://www.robertnyman.com
// Code/licensing: http://code.google.com/p/getelementsbyclassname/
var getElementsByClassName = function (className, tag, elm){
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
};


// Sitemason Common Object Functions

function _smcommon_create(_className, _parentObject) {
	var element = document.createElement('div');
	if (_className) { element.setAttribute('class', _className); }
	if (_parentObject) { element.sm_parent = _parentObject; }
	return element;
}

function _smcommon_appendTo(_parentElement, _newElement, _parentObjectName) {
	if (_parentElement && _newElement) { _parentElement.appendChild(_newElement); }
	else { debug(_parentObjectName + '.appendTo() called without the required parameters', 'warn'); }
}

function _smcommon_replace(_originalElement, _newElement, _parentObjectName) {
	if (_originalElement && _newElement) { _originalElement.parentNode.replaceChild(_newElement, _originalElement); }
	else { debug(_parentObjectName + '.replace() called without the required parameters', 'warn'); }
}


// HTML5 Local Storage
function SMHash(_table) {
	var isSupported = _smStorage_isSupported();
	if (!isSupported || !_table) { return; }
	this.table = _table;
	this.getFieldName = _smHash_getFieldName;
	this.getTypeName = _smHash_getTypeName;
	this.get = _smHash_get;
	this.getAll = _smHash_getAll;
	this.getType = _smHash_getType;
	this.set = _smHash_set;
	this.remove = _smHash_remove;
	this.getCreatedTimestamp = _smHash_getCreatedTimestamp;
	this.getModifiedTimestamp = _smHash_getModifiedTimestamp;
	this.getTimestamp = _smHash_getTimestamp;
	this.setTimestamp = _smHash_setTimestamp;
	this.clear = _smHash_clear;
	var created = this.getTimestamp(true);
	if (!created) { this.setTimestamp(true); }
}

function _smHash_getFieldName(_key) {
	if (_key) {
		var regex = new RegExp('^smHash\\.' + this.table + '\\.');
		if (_key.match(regex)) { return _key; }
		else { return 'smHash.' + this.table + '.' + _key; }
	}
}

function _smHash_getTypeName(_key) {
	if (_key) {
		var regex = new RegExp('^smHash\\.' + this.table + '\\.');
		if (_key.match(regex)) { return _key + '.type'; }
		else { return 'smHash.' + this.table + '.' + _key + '.type'; }
	}
}

function _smHash_get(_key) {
	var name = this.getFieldName(_key);
	if (name) {
		var typeName = this.getTypeName(_key);
		var type = localStorage.getItem(typeName);
		var value = localStorage.getItem(name);
		if (type == 'boolean') {
			if (value == 'true') { return true; }
			else { return false; }
		}
		else if (type == 'number') { return Number(value); }
		else if (type == 'undefined') { return undefined; }
		else if (type == 'string') { return value; }
		else if (type == 'date') { return new Date(value); }
		else { return value; }
	}
}

function _smHash_getAll() {
	var object = {};
	for (var i = 0; i < localStorage.key().length; i++) {
		var fullKey = localStorage.key(i);
		if (fullKey) {
			var regex = new RegExp('^smHash\\.' + this.table + '\\.');
			if (fullKey.match(regex) && !fullKey.match(/\.type$/)) {
				var key = fullKey.replace(regex, '');
				var value = this.get(key);
				object[key] = value;
			}
		}
	}
	return object;
}

function _smHash_getType(_value) {
	var type = typeof _value;
	if (type.match(/^(?:boolean|number|string|undefined)$/)) { return type; }
	else if (type == 'object') {
		if (_value instanceof Date) { return 'date'; }
	}
	debug('Value sent to SMHash is an invalid type, "' + type + '"');
}

function _smHash_set(_key, _value) {
	var name = this.getFieldName(_key);
	var type = this.getType(_value);
	if (name && type) {
		var typeName = this.getTypeName(_key);
		var oldType = localStorage.getItem(typeName);
		if (oldType && (oldType != type)) {
			debug('Changing type of "' + name + '" in SMHash from "' + oldType + '" to "' + type + '"');
		}
		localStorage.setItem(name, _value);
		localStorage.setItem(typeName, type);
		this.setTimestamp();
	}
}

function _smHash_remove(_key) {
	var name = this.getFieldName(_key);
	if (name) {
		var typeName = this.getTypeName(_key);
		localStorage.removeItem(typeName);
		localStorage.removeItem(name);
	}
}

function _smHash_clear() {
	for (var i = 0; i < localStorage.key().length; i++) {
		var key = localStorage.key(i);
		if (key) {
			var regex = new RegExp('^smHash\\.' + this.table + '\\.');
			if (key.match(regex)) {
				localStorage.removeItem(key);
			}
		}
	}
}

function _smHash_getCreatedTimestamp() { return this.getTimestamp(true); }
function _smHash_getModifiedTimestamp() { return this.getTimestamp(); }

function _smHash_getTimestamp(_isCreated) {
	var name = 'smHash.' + this.table + '_smModified';
	if (_isCreated) { name = 'smHash.' + this.table + '_smCreated'; }
	var dateString = localStorage.getItem(name);
	if (dateString) { return new Date(dateString); }
}

function _smHash_setTimestamp(_isCreated) {
	var name = 'smHash.' + this.table + '_smModified';
	if (_isCreated) { name = 'smHash.' + this.table + '_smCreated'; }
	localStorage.setItem(name, new Date());
}

function _smStorage_isSupported() {
	try {
		return 'localStorage' in window && window['localStorage'] !== null;
	} catch (e) {
		return false;
	}
}




// Stylesheet Functions

function appendCSSRule(_stylesheet, _selector, _rule) {
	if (!_stylesheet) { debugWarn('appendCSSRule() called without the required stylesheet'); return; }
	if (!_selector) { debugWarn('appendCSSRule() called without the required selector'); return; }
	if (_stylesheet.cssRules) {
		return _stylesheet.insertRule(_selector + ' { ' + _rule + ' }', _stylesheet.cssRules.length);
	} else if (_stylesheet.rules) {
		return _stylesheet.addRule(_selector, _rule, _stylesheet.rules.length);
	}
}

function replaceCSSRule(_stylesheet, _selector, _rule) {
	if (!_stylesheet) { debugWarn('replaceCSSRule() called without the required stylesheet'); return; }
	if (!_selector) { debugWarn('replaceCSSRule() called without the required selector'); return; }
	deleteCSSRule(_stylesheet, _selector);
	return appendCSSRule(_stylesheet, _selector, _rule);
}

function deleteCSSRule(_stylesheet, _selector) {
	if (!_stylesheet) { debugWarn('deleteCSSRule() called without the required stylesheet'); return; }
	if (!_selector) { debugWarn('deleteCSSRule() called without the required selector'); return; }
	var cssRuleIndex = findCSSRuleIndex(_stylesheet, _selector);
	if (cssRuleIndex) {
		if (_stylesheet.deleteRule) {
			_stylesheet.deleteRule(cssRuleIndex);
		} else if (_stylesheet.removeRule) {
			_stylesheet.removeRule(cssRuleIndex);
		}
	}
}

function findCSSRuleIndex(_stylesheet, _selector) {
	if (!_stylesheet) { debugWarn('findCSSRuleIndex() called without the required stylesheet'); return; }
	if (!_selector) { debugWarn('findCSSRuleIndex() called without the required selector'); return; }
	var cssRuleIndex;
	if (_stylesheet.cssRules) {
		for (var c = 0; c < _stylesheet.cssRules.length; c++) {
			if (_stylesheet.cssRules[c].selectorText == _selector) {
				cssRuleIndex = c;
			}
		}
	} else if (_stylesheet.rules) {
		for (var c = 0; c < _stylesheet.rules.length; c++) {
			var rule = _stylesheet.rules[c];
			if (_stylesheet.rules[c].selectorText == _selector) {
				cssRuleIndex = c;
			}
		}
	}
	return cssRuleIndex;
}

function findStyleSheet(_styleSheetName) {
	if (document.styleSheets) {
		var stylesheet;
		for (var s = 0; s < document.styleSheets.length; s++) {
			if (document.styleSheets[s].href) {
				var tmpArray = document.styleSheets[s].href.match(/(\w+.css)$/);
				if (tmpArray && (tmpArray[1] == _styleSheetName)) {
					stylesheet = s;
				}
			}
		}
		return document.styleSheets[stylesheet];
	} else {
		alert('This browser does not support DOM stylesheets.');
	}
}


// Field Checking

function checkInt(e, _field, _param) {
	var event = e;
	if (!e) { event = window.event; }
	if (event) {
// 		var echar = String.fromCharCode(event.which);
// 		var value;
// 		if (event.keyCode == 38) {
// 			value = Number(value) + 1;
// 		} else if (event.keyCode == 40) {
// 			value = Number(value) - 1;
// 		} else if (event.keyCode == 33) {
// 			value = Number(value) + 10;
// 		} else if (event.keyCode == 34) {
// 			value = Number(value) - 10;
// 		} else if (event.keyCode == 36) {
// 			value = Number(value) + 100;
// 		} else if (event.keyCode == 35) {
// 			value = Number(value) - 100;
// 		} else {
// 			value = value + echar;
// 			value = _field.value.replace(/\D+/g, '');
// 		}
// 		if (_param) {
// 			if (_param.min && (Number(value) < _param.min)) { value = _param.min; }
// 			else if (_param.max && (Number(value) > _param.max)) { value = _param.max; }
// 		}
// 		if (_field.value != String(value)) {
// 			_field.value = value;
// 			event.cancelBubble = true;
// //			event.returnValue = false;
// 			return false;
// 		}
	}
}


// Subscription Manager

function testSubscription() {
	alert("got here");
	var source_url = document.window_form.source_url.value;
	alert(source_url);
}

