
var MySugars = new function()
{
	this.init = function()
	{
		dhtmlHistory.initialize(); 

		initCal("sugar_dt", "content_dt");
		InPlaceEdit.init();
		History.attachOnClicks();
		Events.registerAll();
		this.initialFocus();
	}

	this.initialFocus = function()
	{
		var rgEls = ['sugar_i', 'person_username_register', 'person_username_login', 's_title'];
		for (var ix = 0; ix < rgEls.length; ix++)
		{
			var o = $(rgEls[ix]);
			if (o)
			{
				safeFocus(o);
				break;
			}
		}
	}
}

var Preferences = new function()
{
	this.rg = [];
	var fInited = false;

	this.init = function()
	{
		if (fInited) return;
		this.rg.push($('id_span_new'));
		this.rg.push($('id_span_conf'));
		fInited = true;
	}

	this.togglePass = function()
	{
		this.init();
		var oBox = $('change_password');
		this.rg.foreach(function(_){
					if (oBox && oBox.checked) 
						_.show();
					else
						_.hide();
		});
		if (oBox && oBox.checked)
		{
			focusFirstInput(this.rg[0]);
		}
	}
}

var Info = new function()
{
	this.oInfo = null;
	this.oNoBr = null;
	
	this.init = function()
	{
		if (this.oInfo) return true;
		this.oInfo = $('idInfo');
		if (this.oInfo) this.oNoBr = this.oInfo.firstChild;
		return this.oNoBr;
	}

	this.show = function( s )
	{
		if (!this.init()) return;
		this.oNoBr.innerHTML = s;
		this.oNoBr.style.visibility = "visible";
	}

	this.hide = function()
	{
		if (!this.init()) return;
		this.oNoBr.innerHTML = "&nbsp;";
		this.oNoBr.style.visibility = "hidden";
	}
};

var Recorder = new function()
{
	var fInited = false;
	var fSubmitting = false;
	var fHistory = false;
	var oBtn = null;
	var oInput = null;
	var oDt = null;
	var oContent = null;

	this.init = function()
	{
		if (fInited) return;

		oInput = $("sugar_i");
		oContent = $("content_day");
		if (!oContent)
		{
			oContent = $("content_history");
			fHistory = true;
		}
		oDt = $("sugar_dt");

		fInited = true;
	}

	this.submit = function( oBtnInit )
	{
		this.init();

		if (fSubmitting) return;
		if (!isTagName(oBtnInit, "input")) return;

		oBtn = oBtnInit;

		var reId = /(btn_change_|btn_delete_)([\d]+)/i;
		var matchId = reId.exec(oBtn.id);
		var sSuffix = matchId ? ("_" + matchId[2]) : "";

		oInput = $("sugar_i" + sSuffix);
		oDt = $("sugar_dt" + sSuffix);

		if (!oInput || !oBtn || !oDt) return;

		fSubmitting = true;
		disableForms();
		
		var sInfo = "Recording";
		var sUrl = "/sugar/record";
		
		if (matchId)
		{
			if (matchId[1] == "btn_delete_")
			{
				sInfo = "Deleting";
				sUrl = "/sugar/delete";
			}
			else
			{
				sInfo = "Changing";
			}
		}

		Info.show(sInfo + "...");

		new Ajax.Request(
			sUrl + 	"?async=1&sugar[i]=" + encodeURIComponent(oInput.value) + 
						"&sugar[dt]=" + oDt.value + 
						(matchId ? ("&sugar[id]=" + matchId[2]) : "") + 
						(fHistory ? "&fHistory=1" : ""),
			{method : "get", onComplete : Recorder.resultSubmit});
	};

	this.resultSubmit = function( oAjax )
	{
		fSubmitting = false;
		enableForms();

		var oReturn = safeJSON(oAjax.responseText);
		if (!oReturn) return;

		if (!oReturn.sError)
		{
			oContent.innerHTML = oReturn.sHTML;
			History.attachOnClicks();
			Info.show(oReturn.sInfo);
			InPlaceEdit.init();
			oInput.value = "";
			safeFocus(oInput);
		}
		else
		{
			Info.show(oReturn.sError);
		}
	};

	this.genOnSubmit = function( fKeyPress )
	{
		return function(e) {
			var oSrc = srcElement(e);
			if (!oSrc) return;

			if (fKeyPress)
			{
				if (keyCode(e) != 13) return true;
				oSrc = $(oSrc.id.replace("sugar_i_", "btn_change_"));
			}
			Recorder.submit(oSrc); Event.stop(e); return false;
		};
	};
};

var History = new function()
{
	var rgSLinks = null;
	var oContent = null;
	var fInited = false;
	var sHrefLast = "";
	var stateOriginal = null;
	var cShown = 0;
	
	this.init = function()
	{
		if (fInited) return;

		oContent = $('content_history');
		if (!oContent) return;

		fInited = true;

		rgSLinks = [
		'link_history_0',
		'link_history_1',
		'link_history_2',
		'link_history_3',
		'link_history_4',
		'link_history_5',
		'link_history_sec_0',
		'link_history_sec_1',
		'link_history_sec_2'
		];

		dhtmlHistory.addListener(History.onBrowserHistory);
	}

	this.show = function(oLink)
	{
		this.init();
		if (!oContent) return;
		if (!oLink) return;

		// Record first innerHTML for original history
		//
		if (!stateOriginal) stateOriginal = this.getState();

		var sHref = oLink.href;
		sHrefLast = sHref;
		Info.show("Loading...");
		new Ajax.Request(sHref + "&async=1", {method : "get", onComplete : function(oAjax){History.resultShow(oAjax, sHref);}});
	}

	this.resultShow = function( oAjax, sHref )
	{
		if (!oContent || sHref != sHrefLast) return;

		// Insert new HTML
		//
		oContent.innerHTML = oAjax.responseText;

		// Push new innerHMTL state to the history stack
		//
		dhtmlHistory.add("hist_" + String(cShown++), this.getState());

		this.postShow();
	}

	this.postShow = function()
	{
		initGraphLines();
		History.attachOnClicks();
		InPlaceEdit.init();
		Info.hide();
	}

	this.genOnClick = function()
	{
		return function(e) {

			var oLink = this;
			if (!isTagName(oLink, "a")) oLink = srcElement(e);
			if (!isTagName(oLink, "a") && oLink) oLink = oLink.parentNode;
			if (!isTagName(oLink, "a")) return true;

			if (oLink.className != "disabold")
			{
				History.show(oLink); 
			}
			Event.stop(e); 
			return false;
		};
	};

	this.attachOnClicks = function()
	{
		this.init();
		if (!oContent) return;
		if (!rgSLinks) return;
		rgSLinks.foreach(function(_)
		{
			var oLink = $(_);
			if (oLink) Events.attach(oLink, "click", History.genOnClick());
		});

		var oTbl = $("id_tbl_history");
		if (!oTbl) return;
		var rgA = oTbl.getElementsByTagName("a");
		for (var ix = 0; ix < rgA.length; ix++)
		{
			if (!rgA[ix].fHistoryClick)
				Events.attach(rgA[ix], "click", History.genOnClick());
			rgA[ix].fHistoryClick = true;
		}
	};

	this.getState = function()
	{
		return { sHtml: oContent.innerHTML };
	};

	this.onBrowserHistory = function( sLoc, stateHistory )
	{
		if (!oContent) return;

		var state = stateHistory || stateOriginal;

		if (!state) return;

		oContent.innerHTML = state.sHtml;

		History.postShow();
	};
};

var TableEdit = new function()
{
	this.oRowEditing = null;

	this.init = function( oTable )
	{
		if (!isTagName(oTable, "table")) return;
		if (oTable.fTableEdit) return;

		var rg = oTable.rows;
		for (var ix = 0; ix < rg.length; ix++)
		{
			Events.attach(rg[ix], "click", TableEdit.genOnClick(rg[ix]));
		}

		oTable.fTableEdit = true;
	};

	this.hasStaticSpan = function( oCell )
	{
		return this.hasSpan(oCell, false);
	};

	this.hasEditSpan = function( oCell )
	{
		return this.hasSpan(oCell, true);
	};

	this.hasSpan = function( oCell, fEdit )
	{
		if (!oCell || !oCell.childNodes) return false;
		var rg = oCell.childNodes;
		for (var ix = 0; ix < rg.length; ix++)
		{
			if (isTagName(rg[ix], "span") && rg[ix].className == (fEdit ? "edit" : "static"))
				return true;
		}
		return false;
	};

	this.showStatic = function( oRow )
	{
		this.show(oRow, false);
	};

	this.showEdit = function( oRow )
	{
		this.show(oRow, true);
	};

	this.show = function( oRow, fEdit )
	{
		if (!oRow) return;

		var rgSpan = oRow.getElementsByTagName("span");
		for (var ixS = 0; ixS < rgSpan.length; ixS++)
		{
			var oSpan = rgSpan[ixS];
			if (oSpan.className == (fEdit ? "static" : "edit"))
			{
				oSpan.style.display = "none";

				if (fEdit)
				{
					var oTD = oSpan.parentNode;
					if (!TableEdit.hasEditSpan(oTD))
					{
						if (oTD.cellIndex > 0)
						{
							oTD = oTD.parentNode.cells[oTD.cellIndex-1]
							oTD.colSpan++;
							oTD.fGrew = true;
						}
					}
				}
			}
			else if (oSpan.className == (fEdit ? "edit" : "static"))
			{
				oSpan.style.display = "";

				if (!fEdit)
				{
					var oTD = oSpan.parentNode;
					if (!TableEdit.hasEditSpan(oTD))
					{
						if (oTD.cellIndex > 0)
						{
							oTD = oTD.parentNode.cells[oTD.cellIndex-1]
							if (oTD.fGrew)
								oTD.colSpan--;
						}
					}
				}
			}
		}

		TableEdit.oRowEditing = fEdit ? oRow : null;
		InPlaceEdit.setRowClassNames(oRow, fEdit);
	};

	this.hide = function()
	{
		TableEdit.showStatic(TableEdit.oRowEditing);
	};

	this.genOnClick = function( oRow )
	{
		return function(e)
		{
			if (oRow == TableEdit.oRowEditing) return;

			var rgInput = oRow.getElementsByTagName("input");
			var reBtn = /(btn_change_|btn_delete_)([\d]+)/i;
			var reText = /sugar_i_([\d]+)/i;
			var elFocus = null;
			for (var ixI = 0; ixI < rgInput.length; ixI++)
			{
				var el = rgInput[ixI];
				if (reBtn.test(el.id))
				{
					if (!el.fAttached)
					{
						var id = reBtn.exec(el.id)[2];
						initCal("sugar_dt_" + id, "content_dt_" + id);
						Events.attach(el, "click", Recorder.genOnSubmit());
					}
				}
				else if (reText.test(el.id))
				{
					if (!el.fAttached)
					{
						Events.attach(el, "keypress", Recorder.genOnSubmit(true));
					}
					elFocus = el;
				}

				el.fAttached = true;
			}

			InPlaceClickMask.on(	oRow, 
										function(){TableEdit.hide();}, 
										function(_){return (_ == oRow) || (window.calendar && (_ == window.calendar.element))});
			TableEdit.showEdit(oRow);

			safeFocus(elFocus);
			Event.stop(e);
		};
	};
};

var InPlaceEdit = new function()
{
	this.init = function()
	{
		document.getElementsByClassName("edit_in_place").foreach(function(_){InPlaceEdit.attach(_);});
	};

	this.attach = function( oElem )
	{
		if (!oElem) return;
		if (oElem.fInPlaceEdit) return;
		
		if (isTagName(oElem, "table"))
		{
			this.attachTable(oElem);
			TableEdit.init(oElem);
		}
		else
		{
			Events.attach(oElem, "mouseover", function()
								{
									oElem.addClassName("edit_in_place_active");
								});
			Events.attach(oElem, "mouseout", function(){oElem.removeClassName("edit_in_place_active");});
		}

		oElem.fInPlaceEdit = true;
	};

	this.attachTable = function( oTable )
	{
		if (!isTagName(oTable, "table")) return;

		toArray(oTable.rows).foreach(function(_)
			{
				if (isTagName(_.cells[0], "td"))
				{
					Events.attach(_, "mouseover", function()
					{
						InPlaceEdit.setRowClassNames(_, true);
					});
					Events.attach(_, "mouseout", function()
					{
						InPlaceEdit.setRowClassNames(_, false);
					});
				}
			});
	};

	this.setRowClassNames = function( oRow, fAdd )
	{
		if (!isTagName(oRow, "tr")) return;
		var rg = oRow.cells;

		if (oRow == TableEdit.oRowEditing) return;

		for (var ix = 0; ix < rg.length; ix++)
		{
			Element.extend(rg[ix]);
			var fxn = fAdd ? rg[ix].addClassName : rg[ix].removeClassName;

			fxn.apply(rg[ix], ["edit_in_place_active_td_center"]);

			if (ix == 0)
			{
				fxn.apply(rg[ix], ["edit_in_place_active_td_left"]);
				rg[ix].style.paddingRight = fAdd ? "21px" : "";
			}
			if (ix == rg.length - 1)
			{
				fxn.apply(rg[ix], ["edit_in_place_active_td_right"]);
			}
		}
	};
};

var Reply = new function()
{
	var fSubmitting = false;
	var hashReplyRefs = {};
	var oDivReplies = null;
	var fInited = false;

	this.init = function()
	{
		if (fInited) return;
		oDivReplies = $('idReplies');
		return;
	}

	this.show = function( oLink, idParent )
	{
		this.init();
		if (!oLink || null == idParent) return;

		if (!oLink.id) oLink.id = "reply_" + idParent;

		if (!hashReplyRefs[oLink.id])
		{
			var oText = DOM.textarea({'style' : 'width:50%;height:8em;'});
			var oPost = DOM.input({'class': 'btn', 'type': 'button', 'value': 'Post'});
			var oCancel = DOM.input({'class': 'btn', 'type': 'button', 'value': 'Cancel'});
			var oDiv = DOM.div({'class' : 'indent', 'style' : 'display:none;padding-top:10px;'});

			Events.attach(oCancel, "click", function(){Reply.toggle(oLink)});
			Events.attach(oPost, "click", function(){Reply.submit(oLink)});

			hashReplyRefs[oLink.id] = 
				{
				'idParent' : idParent,
				'oDiv': oDiv,
				'oText' : oText,
				'oPost' : oPost,
				'oCancel' : oCancel,
				'oSpan' : oLink.parentNode,
				'fInited' : false
				}
		}

		this.toggle(oLink);
	}

	this.toggle = function( oLink )
	{
		this.init();
		if (!oLink || !oLink.id) return;

		var o = hashReplyRefs[oLink.id];
		if (!o) return;

		if (!o.fInited)
		{
			o.oSpan.parentNode.insertBefore(o.oDiv, o.oSpan);
			o.oDiv.appendChild(o.oText);
			o.oDiv.appendChild(DOM.br());
			o.oDiv.appendChild(o.oPost);
			o.oDiv.appendChild(o.oCancel);
			o.fInited = true;
		}

		Element.toggle(o.oSpan);
		Element.toggle(o.oDiv);

		safeFocus(o.oText);
	}

	this.submit = function( oLink )
	{
		this.init();
		if (fSubmitting) return;
		if (!oLink || !oLink.id) return;

		var o = hashReplyRefs[oLink.id];
		if (!o) return;

		fSubmitting = true;

		Info.show("Submitting reply...");
		disableForms();

		new Ajax.Request(
			"/discuss/reply",
			{	method : "post", 
				onComplete : Reply.resultSubmit, 
				parameters : "async=1&id_parent=" + o.idParent + "&s_body=" + encodeURIComponent(o.oText.value)})
	}

	this.resultSubmit = function( oAjax )
	{
		fSubmitting = false;

		var oReturn = safeJSON(oAjax.responseText);
		if (oReturn.sError)
		{
			Info.show(oReturn.sError);
			enableForms();
		}
		else
		{
			Info.show(oReturn.sInfo);
			oDivReplies.innerHTML = oReturn.sHTML;
			hashReplyRefs = {};
		}
	};

};

function isLoaded(oImg)
{
	// From http://talideon.com/weblog/2005/02/detecting-broken-images-js.cfm
	// See above for explanation of img state detection
	//
	if (!oImg || !oImg.complete)
		return false;
	if (typeof oImg.naturalWidth != "undefined" && oImg.naturalWidth == 0)
		return false;
	return true;
}

function initGraphLines()
{
	if (initGraphLines.oGL1) initGraphLines.oGL1.hide();
	if (initGraphLines.oGL2) initGraphLines.oGL2.hide();

	var oImgHistory = $('id_img_history');
	var oImgHourly = $('id_img_hourly');

	if (!oImgHistory && !oImgHourly) return;
	while (!isLoaded(oImgHistory) && !isLoaded(oImgHourly))
	{
		setTimeout(initGraphLines, 100);
		return;
	}

	initGraphLines.oGL1 = oImgHistory ? new GraphLines($('id_tbl_history'), oImgHistory, true) : null;
	initGraphLines.oGL2 = oImgHourly ? new GraphLines($('id_tbl_hourly'), oImgHourly, false) : null;
}

function GraphLines( oTableInit, oGraphInit, fReverseInit )
{
	if (!isTagName(oTableInit, "table") || !isTagName(oGraphInit, "img")) return;

	var oTable = oTableInit;
	var oGraph = oGraphInit;
	var oBar = null;
	var fReverse = fReverseInit;

	var pxPadLeft = g_fMetric ? 60 : 48;
	var pxPadRight = 12;
	var nRows = oTable.rows.length;
	var cNonHeader = 0;
	var pxStep = 0;

	var posOffset = Position.cumulativeOffset(oGraph);
	var pxWidth = oGraph.offsetWidth;
	var pxHeight = oGraph.offsetHeight;

	var sColor = "#FFFF8C";
	var sColorContrast = "black";
	var sColorLine = "black";

	var oSlider = null;

	function init()
	{
		cNonHeader = 0;
		for (var ix = 0; ix < nRows; ix++)
		{
			var oRow = oTable.rows[ix];

			paintRow(oRow, "white");
			if (isTagName(oRow.cells[0], "td"))
			{
				Events.attach(oRow, "mouseover", genMouseOver(this, oRow, cNonHeader));
				Events.attach(oRow, "mouseout", genMouseOut(this, oRow));
				cNonHeader++;
			}
		}

		pxStep = (pxWidth - pxPadLeft - pxPadRight) / Math.max((cNonHeader-1), 1);

		oBar = DOM.div({
						'style' : 'width:1px;height:' + (pxHeight-1) +
						'px;background-color:' + sColorLine + ';overflow:hidden;z-index:5;position:absolute;display:none;'
						});

		document.body.appendChild(oBar);

		oSlider = DOM.span({
						'style' : 'position:absolute;z-index:6;background-color:white;display:none;'
						});

		document.body.appendChild(oSlider);
	};

	function genMouseOver( oSelf, oRow, ix )
	{
		return function(){ paintRow(oRow, sColor); if (!oRow.className) oRow.style.color = sColorContrast; oSelf.show(ix, oRow.cells[0]); };
	};

	function genMouseOut( oSelf, oRow )
	{
		return function(){ paintRow(oRow, "white"); oRow.style.color = ""; oSelf.hide(); };
	};

	this.show = function( ix, oCell )
	{
		var pxLeft = fReverse ? (posOffset[0] + pxWidth - pxPadRight - Math.floor(ix * pxStep)) : 
										(posOffset[0] + pxPadLeft + Math.floor(ix * pxStep));

		oBar.style.left = pxLeft + 'px';
		oBar.style.top = posOffset[1] + 'px';
		oBar.style.display = "";

		if (oCell)
		{
			if (isTagName(oCell.firstChild, "a"))
				oSlider.innerHTML = oCell.firstChild.innerHTML;
			else
				oSlider.innerHTML = oCell.innerHTML;

			oSlider.style.visibility = "hidden";
			oSlider.style.display = "";
			oSlider.style.left = (pxLeft - (oSlider.offsetWidth / 2)) + 'px';
			oSlider.style.top = (posOffset[1] + pxHeight - oSlider.offsetHeight - 1) + 'px';
			oSlider.style.visibility = "visible";
		}
	};

	this.hide = function()
	{
		oBar.style.display = "none";
		oSlider.style.display = "none";
	};

	init.apply(this);
};

var InPlaceClickMask = new function()
{
	this.fOn = false;
	this.fxnOff = null;
	this.fxnImmune = null;
	this.elSrc = null;

	this.fInited = false;

	this.init = function()
	{
		if (this.fInited) return;
		Events.attach(document, "click", InPlaceClickMask.click);
		this.fInited = true;
	};
	
	this.off = function()
	{
		if (!this.fOn) return;
		this.init();

		if (this.fxnOff) this.fxnOff.apply(this);
		this.fxnOff = null;
		this.fxnImmune = null;
		this.elSrc = null;
		this.fOn = false;
	};

	this.on = function(elSrc, fxnOff, fxnImmune)
	{
		this.init();

		if (this.fOn && this.elSrc == elSrc)
		{
			// If clickmask already on and came from 
			// same source element, ignore on request
			//
			return;
		}

		this.off();
		this.elSrc = elSrc;
		this.fxnImmune = fxnImmune;
		this.fxnOff = fxnOff;
		this.fOn = true;
	};

	this.click = function(e)
	{
		if (!InPlaceClickMask.fOn) return;
		var el = getTarget(e);
		while (el)
		{
			if (InPlaceClickMask.fxnImmune && InPlaceClickMask.fxnImmune(el))
			{
				return;
			}
			el = el.parentNode;
		}
		InPlaceClickMask.off();
	};
};

function initCal( sIdInput, sIdDisplay )
{
	if (!$(sIdInput) || !$(sIdDisplay)) return;
	Calendar.setup(
		{
			inputField: sIdInput,
			displayArea: sIdDisplay,
			ifFormat: "%I:%M %p %m/%d/%Y",
			daFormat: "%I:%M %p %b %d, %Y",
			button: sIdDisplay,
			eventName: "click",
			weekNumbers: false,
			showOthers: true,
			showsTime: true,
			timeFormat: "12",
			cache: true
		}
	);
};

function isTagName( oNode, sName )
{
	return oNode && oNode.nodeName && (oNode.nodeName.toLowerCase() == sName);
};

function matchesTagName( oNode, sPattern )
{
	var re = new RegExp(sPattern, "i");
	return oNode && re.test(oNode.nodeName);
};

function enableForms()
{
	setTimeout(function(){dodisableForms(false);}, 1);
};

function disableForms()
{
	setTimeout(function(){dodisableForms(true);}, 1);
};

function dodisableForms( fDisabled )
{
	forAll("input", "textarea", function(_){if (_.type != "hidden") _.disabled = fDisabled;});
};

function paintRow( oRow, sColor )
{
	if (!oRow || !oRow.cells) return;
	var rgCells = oRow.cells;
	for (var ix = 0; ix < rgCells.length; ix++)
	{
		rgCells[ix].style.backgroundColor = sColor;
	}
};

// forAll
//
// forAll( oParent, sNodeName1, sNodeName2, ..., sNodeNameN, fxn )
// forAll( sNodeName1, sNodeName2, ..., sNodeNameN, fxn ) (implies document.body parent)
//
function forAll()
{
	if (!arguments.length) return;

	var oParent = arguments[0];
	var ixArgNodeStart = 1;
	if (!oParent || !oParent.nodeType || oParent.nodeType != 1)
	{
		ixArgNodeStart = 0;	
		oParent = document.body;
	}

	var fxn = arguments[arguments.length - 1];

	for (var ix = ixArgNodeStart; ix < arguments.length - 1; ix++)
	{
		var rg = oParent.getElementsByTagName(arguments[ix]);
		for (var ixEl = 0; ixEl < rg.length; ixEl++)
		{
			fxn(rg[ixEl]);
		}
	}

};

function safeJSON( sJSON )
{
	try
	{
		eval(sJSON);
		return oReturnTemp;
	}
	catch(e){return null;}
};

function safeFocus( o )
{
	try{ o.focus() } catch(e) {};
};

function setOpacity(oElem, dFade)
{
	if (dFade == null)
	{
		oElem.style.opacity = "";
		oElem.style.filter = "";
	}
	else
	{
		oElem.style.opacity = dFade;
		oElem.style.filter = "alpha(opacity="+ (dFade*100) +")";
	}
}

function keyCode( e )
{
	if (!e) e = window.event;
	if (!e) return null;
	return (typeof(e.which) != "undefined") ? e.which : e.keyCode;
}

function srcElement( e )
{
	return e ? (e.target ? e.target : (e.srcElement ? e.srcElement : null)) : null;
}

function toArray( rg )
{
	if (!rg || !rg.length) return [];
	var rgReturn = [];
	for (var ix = 0; ix < rg.length; ix++)
	{
		rgReturn[rgReturn.length] = rg[ix];
	}
	return rgReturn;
}

function focusFirstInput( o )
{
	if (!o || !o.getElementsByTagName) return;
	var rg = o.getElementsByTagName("input");
	if (rg && rg.length) safeFocus(rg[0]);
}

function keydownDocument( e )
{
	if (getKeyCode(e) == 27) TableEdit.hide();
}

function clickDocument( e )
{
	InPlaceClickMask.click(e);
}

function getKeyCode( e )
{
	if (!e) e = window.event;
	if (!e) return -1;
	return e.keyCode || e.which;
}

function getTarget( e )
{
	if (!e) e = window.event;
	return e.target || e.srcElement;
}

function getAbove( el, sTag )
{
	while (el)
	{
		if (isTagName(el, sTag)) return el;
		el = el.parentNode;
	}
	return null;
}

// SL (show last node)
//
// Set visibility:visible on last node of type sNodeName
//
function SL( sNodeName )
{
	var rg = document.getElementsByTagName(sNodeName);
	if (rg && rg.length) rg[rg.length-1].style.visibility = "visible";
}

var Events = new function()
{
	this.rgEvents = [
		{el: document, 		type: 'click', fxn: clickDocument},
		{el: document, 		type: 'keydown', fxn: keydownDocument},
		{el: 'btn_record',	type: 'click', fxn: Recorder.genOnSubmit()},
		{el: 'sugar_i', 		type: 'keypress', fxn: Recorder.genOnSubmit(true)}
	];

	this.registerAll = function()
	{
		this.rgEvents.foreach(function(_)
			{
				Events.attach($(_.el), _.type, _.fxn);
			});
	}

	this.attach = function( o, sType, fxn)
	{
		if (!o) return;

		if (o.addEventListener)
			o.addEventListener(sType, fxn, false);
		else if (o.attachEvent)
			o.attachEvent("on" + sType, fxn);
		else
			o["on" + sType] = fxn;
	}
}

Array.prototype.foreach = function(f)
{
	for (var ix = 0; ix < this.length; ix++)
	{
		f(this[ix]);
	}
}

Array.prototype.match = function(f)
{
	for (var ix = 0; ix < this.length; ix++)
	{
		if (f(this[ix])) return true;
	}
	return false;
}

Array.prototype.firstMatch = function(f)
{
	for (var ix = 0; ix < this.length; ix++)
	{
		if (f(this[ix])) return this[ix];
	}
	return null;
}

Array.prototype.push = function(o)
{
	this[this.length] = o;
}
