/******************************************************************************
 * BONUGLI.com family tree JavaScript copyright (c) Paul K. Bonugli 2007      *
 *                                                                            *
 * JavaScript to provide the functionality to enable users to "grab" the tree *
 * to scroll around the page. Also provides an alternative to position:fixed  *
 * to position the top header bar for users of IE 6 or lower.                 *
 ******************************************************************************/

var FamilyTree =
{
	/* normal "grab hand" cursors to try */
	cursorNormal : ["url('/familytree/style/grab.cur'), move", "-moz-grab", "grab", "move"],

	/* dragging "grabbing hand" cursors to try */
	cursorDrag : ["url('/familytree/style/grabbing.cur'), move", "-moz-grabbing", "grabbing", "move"],

	/* reference to the treeViewer (set when init is called) */
	treeViewer : null,

	/* co-ordinates of the page at the point "grab to drag" starts */
	x : 0,
	y : 0,

	/* reference to the header bar style (set when init is called for IE only) */
	headerBarStyle : null,

	/* scroll offsets of the header bar the last time we checked */
	headerBarOldTop : 0,
	headerBarOldLeft : 0,

	/*
	 * Function called to setup the family tree scrolling effects
	 */
	init : function()
	{
		// before we go on, check it's a vaguely modern browser!
		if (!document.body || !document.getElementById) return;

		// find the tree viewer (and give up if we can't)
		FamilyTree.treeViewer = document.getElementById("treeViewer");
		if (!FamilyTree.treeViewer) return;

		// nb: detecting document.onmousedown sucks since
		// it sometimes triggers even if you click the scrollbars!
		// instead we just detect clicks over the tree pane
		FamilyTree.treeViewer.onmousedown = FamilyTree.mousedown;
		FamilyTree.setCursor(FamilyTree.cursorNormal);

		// ideally we'd let the header bar be positioned with CSS
		// but IE < 7 doesn't support position:fixed so we'll code a
		// workaround here. Technically this might be suitable for
		// other browsers that don't support position:fixed, but
		// since I've been unable to test it on any, graceful degredation
		// of a non-moving position:absolute seems safer!
		// nb: isIE6orLess is set in conditionally included detectIE.js
		if (typeof isIE6orLess != "undefined")
		{
			var hb = document.getElementById("headerBar");
			if (hb && hb.style)
			{
				// store a reference to the header bar style
				FamilyTree.headerBarStyle = hb.style;

				// if the window scroll's we want to hide the header bar
				// otherwise it will flicker OR remain in the old location (either is bad!)
				window.onscroll = function() { FamilyTree.headerBarStyle.visibility = "hidden"; };

				// reposition the header bar
				FamilyTree.moveHeaderBar();
			}
		}
	},


	/*
	 * Function called repeatedly for IE < 6 to re-position the top header bar
	 */
	moveHeaderBar : function()
	{
		// determine the current scroll position
		// nb: this is a bit naughty since it could be document.documentElement.scrollTop:
		// we can only do this with certainity since we *know* it will only be called from
		// IE < 7 and that IE 6 will be in quirks mode. Otherwise we'd *have* to check
		var top = document.body.scrollTop;
		var left = document.body.scrollLeft;

		// to prevent too much flickering, we'll wait until we've seen the same values twice
		// (otherwise we'll assume they're currently scrolling too quickly to bother!)
		if (FamilyTree.headerBarOldTop == top && FamilyTree.headerBarOldLeft == left)
		{
			FamilyTree.headerBarStyle.top = top;
			FamilyTree.headerBarStyle.left = left;
			FamilyTree.headerBarStyle.visibility = "visible";
		}

		// cache the current position
		FamilyTree.headerBarOldTop = top;
		FamilyTree.headerBarOldLeft = left;

		// do this all again in 300ms...
		window.setTimeout(FamilyTree.moveHeaderBar, 300);
	},



	/*
	 * Function called when the mouse is clicked down to setup
	 * scrolling effects
	 */
	mousedown : function(e)
	{
		var e = e || window.event; // support for IE < 7

		// set the cursor
		FamilyTree.setCursor(FamilyTree.cursorDrag);

		// determine the current position
		// nb: all browsers have a documentElement so we *must* check for scrollLeft too
		if (document.documentElement && document.documentElement.scrollLeft)
		{
			// Mozilla / IE7 / IE6 standards mode
			FamilyTree.x = document.documentElement.scrollLeft+e.clientX;
			FamilyTree.y = document.documentElement.scrollTop+e.clientY;
		}
		else if (document.body)
		{
			// IE 6 quirks mode / IE < 5
			FamilyTree.x = document.body.scrollLeft + e.clientX;
			FamilyTree.y = document.body.scrollTop + e.clientY;	
		}
		else
		{
			// some old versions of netscape
			return;
		}

		// setup event handlers
		document.onmousemove = FamilyTree.mousemove;
		document.onmouseup = FamilyTree.mouseup;
		document.onmouseout = FamilyTree.mouseout;

		// in IE, we must manually trigger onscroll to ensure the header bar is hidden
		if (typeof isIE6orLess != "undefined" && window.onscroll)
		{
			window.onscroll();
		}

		return false;
	},


	/*
	 * Function called when the mouse is moved (whilst dragging is
	 * deemed to be in effect)
	 */
	mousemove : function(e)
	{
		var e = e || window.event; // support for IE < 7

		// scroll the page (to keep up with the mouse)
		scrollTo(FamilyTree.x - e.clientX, FamilyTree.y - e.clientY);

		return false;
	},
	
	
	/*
	 * Function called when the mouse is moved up, to trigger
	 * that drag to scroll effects are no longer in effect
	 */
	mouseup : function(e)
	{
		// set the cursor
		FamilyTree.setCursor(FamilyTree.cursorNormal);

		// cancel event handlers
		document.onmousemove = null;
		document.onmouseup = null
		document.onmouseout = null;

		return false;
	},


	/*
	 * Function called when the mouse leaves the document,
	 * whilst drag to scroll effects are ongoing. Mouseup
	 * events won't / shouldn't trigger out there, so we
	 * need to disable the effects regardless.
	 */
	mouseout : function(e)
	{
		var e = e || window.event; // support for IE < 7

		// some browsers (Firefox in particular)
		// seem to sporadically trigger a document
		// mouseout in favour of a mousein on the page
		// image. r represents what we've gone over -
		// only if it is nothing have we left the page!
		if (!(e.relatedTarget || e.toElement))
		{
			FamilyTree.mouseup();
		}
	},


	/*
	 * Function to set the cursor displayed over the tree viewer.
	 * This takes a list of possibilites, trying each until it finds
	 * one supported by the current browser. This was inspired by WindowManager
	 * (c) 2005 MetaCarta and released under the BSD license
	 */
	setCursor : function(cursor)
	{
		if (!FamilyTree.treeViewer) return;

		if (cursor && cursor.length && typeof cursor == 'object')
		{
			for (var i = 0; i < cursor.length; i++)
			{
				try
				{
					FamilyTree.treeViewer.style.cursor = cursor[i];
					if (FamilyTree.treeViewer.style.cursor == cursor[i])
					{
						return;
					}
				}
				catch(ex)
				{
					// ignore problems (we're still testing possibilites after all)
				}
			}
		}

		// if we got this far the cursor wasn't set for some reason, so let's try this
		try
		{
			FamilyTree.treeViewer.style.cursor = "auto";
		}
		catch(ex)
		{
			// ignore further problems
		}

	}

}


/*
 * Function called on page load to init the family tree "grab to drag" functionality
 */
function initFamilyTree()
{
	FamilyTree.init();
}
window.onload = initFamilyTree;
