/*

The target element can use the following custom HTML attributes to customize the tooltip behavior:
	tooltipid = the HTML identifier for the element to display as a tooltip.  This attribute is required.
	tooltippositioningsignx = (1) to position the tooltip to the right of the mouse cursor (default), (0) to center the tooltip horizontally at the mouse cursor, or (-1) to position the tooltip to the left of the mouse cursor.  This can also be a decimal number between those values.  This attribute is optional.
	tooltippositioningsigny = (1) to position the tooltip below the mouse cursor (default), (0) to center the tooltip vertically at the mouse cursor, or (-1) to position the tooltip above the mouse cursor.  This can also be a decimal number between those values.  This attribute is optional.
	tooltippositioninglock = (1) to set the position of the tooltip based on 'tooltippositioningsignx' and 'tooltippositioningsigny' regardless of the visible space, (0) to automatically reposition the tooltip as visible space allows (default).  This attribute is optional.
	tooltippositioningnearmouse = (1) to set the position of the tooltip based on the mouse cursor (default), (0) to set the position based on the target element.  This attribute is optional.
	tooltipsetupduration = amount of time to wait before opening the tooltip (in milliseconds), defaulted to 500.  This attribute is optional.
	tooltipteardownduration = amount of time to wait before closing the tooltip (in milliseconds).  This attribute is optional.
	defaulttooltipid = the HTML identifier for an element to clone as the tooltipid, uses tooltipid as the cloned elements id (must still be specified).  This attribute is optional.
	tooltipajaxurl = the url to request to update the html of the tooltip, it is requested as soon as it attempts to show the html and updates the element for tooltipid.  It is a one time update, only the first load hits that url.  This attribute is optional.
	tooltippinnable = (1) to allow clicking the target element to keep the tooltip displayed, (0) to prevent pinning behavior (default).  The target element cannot have a traditional 'onclick' event already registered.  When pinned, the tooltip element receives an 'onclick' event.  To dismiss, click the target element again or call 'DismissPinnedInlineHTMLTooltip'.  This attribute is optional.
	tooltippinnedclass = the CSS class to overwrite the 'class' attribute when the tooltip is pinned.  This can be used to show a close button.  When dismissed, the original class is restored.  This attribute is optional.
	tooltipstat = url to make an ajax request to the first time a tooltip is loaded, cleared after request is made

The tooltip element can use the following traditional HTML events to customize the tooltip behavior:
	onfocus = fired when the tooltip is displayed.
	onblur = fired when the tooltip is hidden.
	onclick = fired when the tooltip is pinned.  For more information, see the 'tooltippinnable' HTML attribute.

The target element needs to be absolutely positioned.

Activate the tooltip functionality by calling ConnectInlineHTMLTooltipTargetEvents with the target element.

*/

/** Activates tooltip behavior for the specified link, button, or other HTML element.  Custom HTML attributes specify tooltip behavior; for details, see 'InlineHTMLTooltip.js'. */
function ConnectInlineHTMLTooltipTargetEvents(targetElement)
{
	if((!(targetElement.onmouseover)) && (!(targetElement.onmouseout)))
	{
		targetElement.onmouseover = InlineHTMLTooltipTarget_MouseOver;
		targetElement.onmouseout = InlineHTMLTooltipTarget_MouseOut;
	}
	if((!(targetElement.onfocus)) && (!(targetElement.onblur)))
	{
		targetElement.onfocus = InlineHTMLTooltipTarget_Focus;
		targetElement.onblur = InlineHTMLTooltipTarget_Blur;
	}
	if(!(targetElement.onclick))
	{
		targetElement.onclick = InlineHTMLTooltipTarget_Click;
	}
	var attribute = targetElement.attributes["tooltippinnable"];
	if((!!attribute) && (attribute.value === "1"))
	{
		var tooltipAttribute = targetElement.attributes["defaulttooltipid"] || targetElement.attributes["tooltipid"];
		var tooltipElement = window.document.getElementById(tooltipAttribute.value);
		targetElement.setAttribute("tooltipunpinnedclass", tooltipElement.className);
		if(!(targetElement.attributes["tooltippinnedclass"]))
		{
			targetElement.setAttribute("tooltippinnedclass", tooltipElement.className);
		}
	}
}

/** Deactivates tooltip behavior for the specified link, button, or other HTML element. */
function DisconnectInlineHTMLTooltipTargetEvents(targetElement)
{
	if((targetElement.onmouseover === InlineHTMLTooltipTarget_MouseOver) && (targetElement.onmouseout === InlineHTMLTooltipTarget_MouseOut))
	{
		targetElement.onmouseover = null;
		targetElement.onmouseout = null;
	}
	if((targetElement.onfocus === InlineHTMLTooltipTarget_Focus) && (targetElement.onblur === InlineHTMLTooltipTarget_Blur))
	{
		targetElement.onfocus = null;
		targetElement.onblur = null;
	}
	if(targetElement.onclick === InlineHTMLTooltipTarget_Click)
	{
		targetElement.onclick = null;
	}
}

/** [Clarification on the intended public use of this function would be appreciated.] */
function ConnectInlineHTMLTooltipEvents(targetElement)
{
	if((!(targetElement.onmouseover)) && (!(targetElement.onmouseout)))
	{
		targetElement.onmouseover = StopTearDownTimer;
		targetElement.onmouseout = InlineHTMLTooltipTarget_MouseOut;
	}
}

/* Closes a pinned tooltip.  This is intended for use by 'close' buttons. */
function DismissPinnedInlineHTMLTooltip()
{
	if(InlineHTMLTooltipPinned)
	{
		UnpinInlineHTMLTooltip();
		HideInlineHTMLTooltip();
	}
}

/** Closes the current tooltip.  This is intended for use by dialog-launching buttons or links in tooltips when 'tooltipteardownduration' is specified, allowing time to interact with the tooltip body. */
function DismissInlineHTMLTooltip()
{
	HideInlineHTMLTooltip();
}



/* Internal objects. */

var InlineHTMLTooltipCurrentTarget = null;
var InlineHTMLTooltipCurrentTooltip = null;
var InlineHTMLTooltipPositioningLock = false;
var InlineHTMLTooltipPositioningNearMouse = true;
var InlineHTMLTooltipPositioningFactorX = 0;
var InlineHTMLTooltipPositioningFactorY = 0;
var InlineHTMLTooltipPositioningSignX = 1;
var InlineHTMLTooltipPositioningSignY = 1;
var InlineHTMLTooltipSetupDuration = 500;
var InlineHTMLTooltipPinnable = false;
var InlineHTMLTooltipPinnedClass = null;
var InlineHTMLTooltipUnpinnedClass = null;

var InlineHTMLTooltipLoadTimer = NaN;
var InlineHTMLTooltipTargetMousePositionX = NaN;
var InlineHTMLTooltipTargetMousePositionY = NaN;
var InlineHTMLTooltipTeardownTimer = NaN;
/* Records the function to be called when InlineHTMLTooltipTeardownTimer expires.  This is used to accelerate the timeout if the current tooltip changes. */
var InlineHTMLTooltipTeardownTimerFunction = null;
var InlineHTMLTooltipPinned = false;

function SaveInlineHTMLTooltipContext(targetElement)
{
	if (!!targetElement.attributes['defaulttooltipid'] && !!targetElement.attributes['defaulttooltipid'].value)
	{
		CloneDefaultToolTip(targetElement);
	}
	InlineHTMLTooltipCurrentTarget = targetElement;
	InlineHTMLTooltipCurrentTooltip = window.document.getElementById(targetElement.attributes["tooltipid"].value);

	var attribute = targetElement.attributes["tooltippositioningsignx"];
	if(!!attribute)
	{
		InlineHTMLTooltipPositioningSignX = parseFloat(attribute.value, 10);
	}
	if(isNaN(InlineHTMLTooltipPositioningSignX))
	{
		InlineHTMLTooltipPositioningSignX = 1;
	}
	InlineHTMLTooltipPositioningFactorX = ((InlineHTMLTooltipPositioningSignX + 1) * 0.5) - 1;

	attribute = targetElement.attributes["tooltippositioningsigny"];
	if(!!attribute)
	{
		InlineHTMLTooltipPositioningSignY = parseFloat(attribute.value, 10);
	}
	if(isNaN(InlineHTMLTooltipPositioningSignY))
	{
		InlineHTMLTooltipPositioningSignY = 1;
	}
	InlineHTMLTooltipPositioningFactorY = ((InlineHTMLTooltipPositioningSignY + 1) * 0.5) - 1;

	attribute = targetElement.attributes["tooltipsetupduration"];
	if(!!attribute)
	{
		InlineHTMLTooltipSetupDuration = parseInt(attribute.value, 10);
	}
	else
	{
		InlineHTMLTooltipSetupDuration = 500;
	}

	attribute = targetElement.attributes["tooltippositioninglock"];
	if(!!attribute)
	{
		InlineHTMLTooltipPositioningLock = (attribute.value === "1");
	}
	else
	{
		InlineHTMLTooltipPositioningLock = false;
	}

	attribute = targetElement.attributes["tooltippositioningnearmouse"];
	if(!!attribute)
	{
		InlineHTMLTooltipPositioningNearMouse = (attribute.value === "1");
	}
	else
	{
		InlineHTMLTooltipPositioningNearMouse = true;
	}

	attribute = targetElement.attributes["tooltippinnable"];
	if(!!attribute)
	{
		InlineHTMLTooltipPinnable = (attribute.value === "1");
	}
	else
	{
		InlineHTMLTooltipPinnable = false;
	}

	if(InlineHTMLTooltipPinnable)
	{
		attribute = targetElement.attributes["tooltippinnedclass"];
		if(!!attribute)
		{
			InlineHTMLTooltipPinnedClass = attribute.value;
		}
		else
		{
			InlineHTMLTooltipPinnedClass = null;
		}

		attribute = targetElement.attributes["tooltipunpinnedclass"];
		if(!!attribute)
		{
			InlineHTMLTooltipUnpinnedClass = attribute.value;
		}
		else
		{
			InlineHTMLTooltipUnpinnedClass = null;
		}
	}
}

function InlineHTMLTooltipTarget_Click()
{
	var originalTarget = InlineHTMLTooltipCurrentTarget;
	var originalPinned = InlineHTMLTooltipPinned;
	if(originalTarget !== null)
	{
		if(originalPinned)
		{
			UnpinInlineHTMLTooltip();
			if(this !== originalTarget)
			{
				HideInlineHTMLTooltip();
			}
		}
	}
	SaveInlineHTMLTooltipContext(this);
	if(originalTarget !== InlineHTMLTooltipCurrentTarget)
	{
		ShowInlineHTMLTooltip();
		if(InlineHTMLTooltipPinnable)
		{
			PinInlineHTMLTooltip();
		}
	}
	else
	{
		if(!(originalPinned) && InlineHTMLTooltipPinnable)
		{
			PinInlineHTMLTooltip();
		}
	}
	return false;
}

function InlineHTMLTooltipTarget_MouseOver(eventDetails)
{
	if(InlineHTMLTooltipPinned)
	{
		return;
	}

	if(!(isNaN(window.InlineHTMLTooltipTeardownTimer)))
	{
		window.clearTimeout(window.InlineHTMLTooltipTeardownTimer);
		window.InlineHTMLTooltipTeardownTimer = NaN;
		window.InlineHTMLTooltipTeardownTimerFunction();
		window.InlineHTMLTooltipTeardownTimerFunction = null;
	}

	var timeout;
	eventDetails = eventDetails || window.event;
	var currentTipValue = InlineHTMLTooltipCurrentTooltip;
	SaveInlineHTMLTooltipContext(this);
	if ((!!InlineHTMLTooltipCurrentTarget) && (!!currentTipValue))
	{
		if(currentTipValue.id != InlineHTMLTooltipCurrentTooltip.id)
		{
			InlineHTMLTooltipCurrentTooltip = currentTipValue;
			HideInlineHTMLTooltip();
			SaveInlineHTMLTooltipContext(this);
		}
		else
		{
			if(!(isNaN(window.InlineHTMLTooltipTeardownTimer)))
			{
				window.clearTimeout(window.InlineHTMLTooltipTeardownTimer);
				window.InlineHTMLTooltipTeardownTimer = NaN;
				window.InlineHTMLTooltipTeardownTimerFunction();
				window.InlineHTMLTooltipTeardownTimerFunction = null;
			}
			attrib = InlineHTMLTooltipCurrentTarget.attributes["tooltipteardownduration"] || {};
			timeout = +( attrib.value ) || 0;
			window.InlineHTMLTooltipTeardownTimerFunction = ShowInlineHTMLTooltip;
			window.InlineHTMLTooltipTeardownTimer = window.setTimeout( ShowInlineHTMLTooltip, timeout );
		}
	}
	InlineHTMLTooltipCurrentTarget.onmousemove = InlineHTMLTooltipTarget_MouseMove;
	InlineHTMLTooltipTarget_MouseMove(eventDetails);
}

function InlineHTMLTooltipTarget_MouseMove(eventDetails)
{
	var scroll = GetScrollPos();
	eventDetails = eventDetails || window.event;
	InlineHTMLTooltipTargetMousePositionX = eventDetails.clientX + scroll.scrollLeft;
	InlineHTMLTooltipTargetMousePositionY = eventDetails.clientY + scroll.scrollTop;
	if(InlineHTMLTooltipPinned)
	{
		return;
	}
	if(!(isNaN(window.InlineHTMLTooltipLoadTimer)))
	{
		window.clearTimeout(window.InlineHTMLTooltipLoadTimer);
		window.InlineHTMLTooltipLoadTimer = NaN;
	}
	window.InlineHTMLTooltipLoadTimer = window.setTimeout(ShowInlineHTMLTooltip, InlineHTMLTooltipSetupDuration);
}

function InlineHTMLTooltipTarget_MouseOut()
{
	if(InlineHTMLTooltipPinned)
	{
		return;
	}
	var timeout, attrib;
	
	if( InlineHTMLTooltipCurrentTarget !== null && InlineHTMLTooltipCurrentTooltip.style.display !== "none" )
	{	
		if(!(isNaN(window.InlineHTMLTooltipTeardownTimer)))
		{
			window.clearTimeout(window.InlineHTMLTooltipTeardownTimer);
			window.InlineHTMLTooltipTeardownTimer = NaN;
			window.InlineHTMLTooltipTeardownTimerFunction();
			window.InlineHTMLTooltipTeardownTimerFunction = null;
		}
		
		attrib = InlineHTMLTooltipCurrentTarget.attributes["tooltipteardownduration"] || {};
		timeout = +( attrib.value ) || 0;
		window.InlineHTMLTooltipTeardownTimerFunction = HideInlineHTMLTooltip;
		window.InlineHTMLTooltipTeardownTimer = window.setTimeout( HideInlineHTMLTooltip, timeout );
	}
	else
	{
		HideInlineHTMLTooltip();
	}
}

function InlineHTMLTooltipTarget_Focus()
{
	if(InlineHTMLTooltipPinned)
	{
		return;
	}
	if(!(isNaN(window.InlineHTMLTooltipTeardownTimer)))
	{
		window.clearTimeout(window.InlineHTMLTooltipTeardownTimer);
		window.InlineHTMLTooltipTeardownTimer = NaN;
		window.InlineHTMLTooltipTeardownTimerFunction();
		window.InlineHTMLTooltipTeardownTimerFunction = null;
	}
	SaveInlineHTMLTooltipContext(this);
	ShowInlineHTMLTooltip();
}

function InlineHTMLTooltipTarget_Blur()
{
	if(InlineHTMLTooltipPinned)
	{
		return;
	}
	var timeout, attrib;
	
	if(  InlineHTMLTooltipCurrentTarget !== null && InlineHTMLTooltipCurrentTooltip.style.display !== "none" )
	{
		if(!(isNaN(window.InlineHTMLTooltipTeardownTimer)))
		{
			window.clearTimeout(window.InlineHTMLTooltipTeardownTimer);
			window.InlineHTMLTooltipTeardownTimer = NaN;
			window.InlineHTMLTooltipTeardownTimerFunction();
			window.InlineHTMLTooltipTeardownTimerFunction = null;
		}
		
		attrib = InlineHTMLTooltipCurrentTarget.attributes["tooltipteardownduration"] || {};
		timeout = +( attrib.value ) || 0;

		window.InlineHTMLTooltipTeardownTimerFunction = HideInlineHTMLTooltip;
		window.InlineHTMLTooltipTeardownTimer = window.setTimeout( HideInlineHTMLTooltip, timeout );
	}
	else
	{
		HideInlineHTMLTooltip();
	}
}

function ShowInlineHTMLTooltip()
{
	if(InlineHTMLTooltipCurrentTooltip !== null)
	{
		var scroll = GetScrollPos();
		if(!(isNaN(window.InlineHTMLTooltipLoadTimer)))
		{
			window.clearTimeout(window.InlineHTMLTooltipLoadTimer);
			window.InlineHTMLTooltipLoadTimer = NaN;
		}
		InlineHTMLTooltipCurrentTarget.onmousemove = null;
		InlineHTMLTooltipCurrentTooltip.style.left = "-999px";
		InlineHTMLTooltipCurrentTooltip.style.top = "-999px";
		InlineHTMLTooltipCurrentTooltip.style.display = "block";
		InlineHTMLTooltipCurrentTooltip.style.visibility = "hidden";
		if(isNaN(InlineHTMLTooltipTargetMousePositionX) || !(InlineHTMLTooltipPositioningNearMouse))
		{
			InlineHTMLTooltipTargetMousePositionX = InlineHTMLTooltipCurrentTarget.offsetWidth * (InlineHTMLTooltipPositioningFactorX + 1);
			InlineHTMLTooltipTargetMousePositionY = InlineHTMLTooltipCurrentTarget.offsetHeight * (InlineHTMLTooltipPositioningFactorY + 1);
			for(var cursor = InlineHTMLTooltipCurrentTarget;  cursor !== null;  cursor = cursor.offsetParent)
			{
				InlineHTMLTooltipTargetMousePositionX += cursor.offsetLeft;
				InlineHTMLTooltipTargetMousePositionY += cursor.offsetTop;
			}
		}
		InlineHTMLTooltipCurrentTooltip.style.left = (InlineHTMLTooltipTargetMousePositionX + (InlineHTMLTooltipCurrentTooltip.offsetWidth * InlineHTMLTooltipPositioningFactorX) + (10 * InlineHTMLTooltipPositioningSignX)).toString() + "px";
		InlineHTMLTooltipCurrentTooltip.style.top = (InlineHTMLTooltipTargetMousePositionY + (InlineHTMLTooltipCurrentTooltip.offsetHeight * InlineHTMLTooltipPositioningFactorY) + (10 * InlineHTMLTooltipPositioningSignY)).toString() + "px";
		if(!(InlineHTMLTooltipPositioningLock))
		{
			if (parseInt(InlineHTMLTooltipCurrentTooltip.style.top, 10) + InlineHTMLTooltipCurrentTooltip.offsetHeight > scroll.scrollTop + (window.innerHeight || document.documentElement.offsetHeight))
			{
				InlineHTMLTooltipCurrentTooltip.style.top = (InlineHTMLTooltipTargetMousePositionY + (InlineHTMLTooltipCurrentTooltip.offsetHeight * -1)).toString() + "px";
			}
		}
		InlineHTMLTooltipCurrentTooltip.style.visibility = "visible";
		if(!!InlineHTMLTooltipCurrentTooltip.onfocus)
		{
			InlineHTMLTooltipCurrentTooltip.onfocus();
		}
		if (!!InlineHTMLTooltipCurrentTarget.attributes['tooltipajaxurl'] && !!InlineHTMLTooltipCurrentTarget.attributes['tooltipajaxurl'].value)
		{
			AjaxInlineHTMLTooltip(InlineHTMLTooltipCurrentTarget);
		}
		if (!!InlineHTMLTooltipCurrentTarget.attributes['tooltipstat'] && !!InlineHTMLTooltipCurrentTarget.attributes['tooltipstat'].value)
		{
			AjaxStat(InlineHTMLTooltipCurrentTarget);
		}
	}
}

function PinInlineHTMLTooltip()
{
	InlineHTMLTooltipCurrentTooltip.className = InlineHTMLTooltipPinnedClass;
	InlineHTMLTooltipPinned = true;
	if(!!InlineHTMLTooltipCurrentTooltip.onclick)
	{
		InlineHTMLTooltipCurrentTooltip.onclick();
	}
}

function UnpinInlineHTMLTooltip()
{
	InlineHTMLTooltipCurrentTooltip.className = InlineHTMLTooltipUnpinnedClass;
	InlineHTMLTooltipPinned = false;
}

function HideInlineHTMLTooltip()
{
	if(InlineHTMLTooltipCurrentTooltip !== null)
	{
		InlineHTMLTooltipCurrentTooltip.style.display = "none";
		window.InlineHTMLTooltipTeardownTimer = window.InlineHTMLTooltipTeardownTimer || NaN;
		if(!(isNaN(window.InlineHTMLTooltipTeardownTimer)))
		{
			window.clearTimeout(window.InlineHTMLTooltipTeardownTimer);
			window.InlineHTMLTooltipTeardownTimer = NaN;
			window.InlineHTMLTooltipTeardownTimerFunction();
			window.InlineHTMLTooltipTeardownTimerFunction = null;
		}
		InlineHTMLTooltipCurrentTarget.onmousemove = null;
		InlineHTMLTooltipTargetMousePositionX = NaN;
		InlineHTMLTooltipTargetMousePositionY = NaN;
		if(!!InlineHTMLTooltipCurrentTooltip.onblur)
		{
			InlineHTMLTooltipCurrentTooltip.onblur();
		}
		InlineHTMLTooltipCurrentTarget = null;
		InlineHTMLTooltipCurrentTooltip = null;
		InlineHTMLTooltipSetupDuration = 500;
		InlineHTMLTooltipPositioningLock = false;
		InlineHTMLTooltipPinned = false;
		InlineHTMLTooltipPinnable = false;
		InlineHTMLTooltipPinnedClass = null;
		InlineHTMLTooltipUnpinnedClass = null;
	}
}

function AjaxInlineHTMLTooltip(targetElement)
{
	var toolTip = document.getElementById(targetElement.attributes['tooltipid'].value);
	if (!toolTip.attributes['loaded'] || !toolTip.attributes['loaded'].value)
	{
		new Ajax.Updater(targetElement.attributes['tooltipid'].value,
						targetElement.attributes['tooltipajaxurl'].value,
						{
							method:'get',
							onSuccess : function(){
								targetElement.attributes['tooltipajaxurl'].value = '';
								toolTip.setAttribute('loaded', true);
								if (toolTip == InlineHTMLTooltipCurrentTooltip)
								{
									setTimeout(ShowInlineHTMLTooltip,0);
								}
							}
						});
	}
}

function AjaxStat(targetElement)
{
	new Ajax.Request(targetElement.attributes['tooltipstat'].value,
					{ method:'post' });
	targetElement.attributes['tooltipstat'].value = '';
}

function CloneDefaultToolTip(targetElement)
{
	if (!document.getElementById(targetElement.attributes['tooltipid'].value))
	{
		var toolTip = document.getElementById(targetElement.attributes['defaulttooltipid'].value);
		toolTip = toolTip.cloneNode(true);
		toolTip.id = targetElement.attributes['tooltipid'].value;
		document.body.appendChild(toolTip);
		ConnectInlineHTMLTooltipEvents(toolTip);
	}
	targetElement.attributes['defaulttooltipid'].value = '';
}

function StopTearDownTimer()
{
	window.InlineHTMLTooltipTeardownTimer = window.InlineHTMLTooltipTeardownTimer || NaN;
	if(!(isNaN(window.InlineHTMLTooltipTeardownTimer)))
	{
		window.clearTimeout(window.InlineHTMLTooltipTeardownTimer);
		window.InlineHTMLTooltipTeardownTimer = NaN;
		/* UNDONE:  It's unclear what this function is intended for.  Should the callback function run, or is it supposed to be canceled? */
		window.InlineHTMLTooltipTeardownTimerFunction = null;
	}
}

function GetScrollPos()
{
	if (typeof(pageYOffset) != 'undefined')
	{
		return { scrollTop : pageYOffset, scrollLeft : pageXOffset };
	}
	else
	{
		var docElement = document.documentElement;

		return { scrollTop : docElement.scrollTop, scrollLeft : docElement.scrollLeft };
	}
}

