//////////////                              ChainLink                       //////////////////

//////////////                        menu and tooltip system               //////////////////
//////////////                            copyright 2005                    //////////////////
//////////////                          by Rick Sutcliffe                   //////////////////
//////////////                           Arjay Enterprises                  //////////////////
//////////////                        http://www.arjay.bc.ca                //////////////////

//////////////           Ideas from all over the net and many books here    //////////////////
//////////////                Unlike others, this code is re-entrant        //////////////////
//////////////     has horizontal and vertical growth options, push downs,  //////////////////
//////////////              chains indefinitely, and is very versatile      //////////////////

//////////////                           version history                    //////////////////
// version 1.0 2005 12 15 deployed on arjaybooks.com as a test 
// version 1.1 2007 01 12 added drop menus. Note that the child of a drop menu has to be a drop menu
// version 1.2 2007 01 28 moved the url material to the locus module
// version 1.3 2007 03 07 fix missing cr in error section at end
// version 1.4 2007 05 03 attach onclick handler options to lowest level trigger and menu bodies, not the links themselves
// version 1.5 2007 06 22 shows and hides moved to utils, which is now necessary
			//////////////                  user changeable variables in this section
			
	// variables affecting internal performance
var shortHideDelay = 100			// menu disappear speed onMouseout (in milliseconds) Probably should be 100 < x < 250
var longHideDelay = 2000			// as above, but for positioning in boxes away from the object. Need time to get there suggest about 2000
var anchorLinkActive = true			// Enable or disable the anchor link when clicked on
var hideChainOnAnchorClick = true	// hide chain when user clicks anchor? Uses the parent of the anchor at lowest level
var hideChainOnMenuClick = true		// hide chain when user clicks within menu?
var defaultRelHOverlap = 0.2		// fraction by which an overlapped submenu overlaps the previous one horizontally
var defaultRelVOverlap = 0.2		// fraction by which an overlapped submenu overlaps the previous one vertically
var defaultAbsHPad = 0				// abs amount in pixels by which a submenu positioned to grow left or right is separated from previous one
var defaultFlushPad = 0				// abs amount in pixels by which a submenu positioned flush is set in from the border (i.e. not quite so flush)
var defaultVertPadWhenUnder = 0		// 0 < y < 2 is good
var defaultHPadBesideAnchor	= 8		// amount to add to anchor width on level 1 or horiz menus when menu positioned beside; doubled if Safari
var minEdgeClear = 8				// amount to leave clear at edge when considering flipping menu over				
	// next three are used only when no position is specified
var defaultFirstGrowDirectionIsDown = true // this tells the program what to assume about the first menu in a chain if no instruction is given in the parameters
var defaultUpDownPos = "downc" 		// default is hung under and centered
var defaultLeftRightPos = "overlapc"// default is beside, overlapping by percent above and centrered on previous level of link menu
var horizThreshhold = 39			// A menu whose height is less than this (assume min 20 pixels per cell) is assumed to be horizontal, that is to be only one cell high

			////////////				program variables and setup -- not much point in messing with these	/////////////

   // identification variables
		// general compatibility
var ie5 = document.all
var ns6 = document.getElementById&&!document.all
	// can we even use dynamic menus?
if (ie5||ns6) // yes, so
	{
		// we load the stylesheet here so this need not be done in the html. We can load more than one sheet.
		// if we do, each subsequent one could override the previous one
		// this particular stylesheet should have only styles directly associated with the menus
	document.write("<link Rel='stylesheet' href='" + baseURL + pathToChainLinkFolder + nameOfDefaultCSSFile +"' type='text/css' />");
	}
		// assumption here is that the old site has its own determination of relative addressing, not something we do for them if they can't use us anyway
		// note that you can get into trouble with base addressing if you hit a 404 page, for it references things from the alternate site
				// if the latter is a subfolder.
			// no dynamic menus avail, so see if alternate site or alert to error otherwise
else document.write("<script type='text/javascript'> tryTransferToAltSite () </script>")


		// specific browsers
var agentStr = navigator.userAgent.toLowerCase()
var isOp = window.opera
var isSafEng = agentStr.indexOf ("applewebkit") !=-1
var isIcab = agentStr.indexOf ('icab') != -1 // not currently compatible with icab for menus under a horizontal one
var isOmni = agentStr.indexOf ('omniweb') != - 1
var iePos = agentStr.indexOf ('msie')
var isIE = (iePos != -1 && !this.isOp && (agentStr.indexOf('webtv') == -1))
if (isIE)
	{
		var appVer = navigator.appVersion.toLowerCase()
		var is_minor = parseFloat (appVer.substring(iePos + 5, appVer.indexOf(';',iePos)))
		var is_major = parseInt(is_minor)
	}
var is_ie6up = (isIE&&is_minor >= 6)
var isMac = agentStr.indexOf ('mac') != -1

	// program global variables
var level = 0						// keeps track of how deeply nested the menus are
var prevMenuLevel = 0				// sometimes we need to know the last one used when deciding how many to close
var defRootID = "rootOfChainLinks"	// the id of the root or anchor, if not supplied
var lastID = defRootID				// last id used
var delayhidechain = null			// starts at null, gets set when a delay hide is placed on a chain; happens on mouseouts
var chainLinks = new Array()		// the array containing the menu data for each link in the chain
var hidepending = false				// set if a delayed hide has been established; cleared when the hide is completed
var longhide = false				// the longer hide delay is used when a specidic ID'd element is used to anchor the chain.
	// As this could be some distance away on the screen, we may need some extra time to mouse over there. This variable merely tells us if this optiuon is currently set.
var defaultFirstGrowDirection = defaultFirstGrowDirectionIsDown? defaultUpDownPos : defaultLeftRightPos 	// If no direction is given, use these defaults for first and subsequent menus in a chain.

	// following are for adjusting the ie positions, which appear to need an absolute shift on the Mac
	// if ie6 is ever released on the Mac, this test will have to be more discriminating
var ieVertPadAdjustFirstDn  = isIE&&isMac? 16 : 0
var ieHorizPadAdjustFirstAc = isIE&&isMac? 10 : 0


			////////////////			load and transfer functions		////////////

function testForTransferToAltSite ()
	{if (!(ie5||ns6)) tryTransferToAltSite () }

function tryTransferToAltSite ()
{
	if (tryAltSiteIfOldBrowser) {location = pathToAltNonDynamicSite}
	else {error ("old browser")}
}

			////////////////			info functions		////////////

function theDoc()
	{return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body}

			////////////////		position computations		//////////////

function HorizPosOffset (entity)
{ 
	var totaloffset = entity.offsetLeft 
	var parentEl = entity.offsetParent;
	while (parentEl != null)
		{
			totaloffset = totaloffset + parentEl.offsetLeft
			parentEl = parentEl.offsetParent;
		}
	return totaloffset;
}

function VertPosOffset (entity)
{
var totaloffset = entity.offsetTop 
	var parentEl = entity.offsetParent;
	while (parentEl != null)
		{
			totaloffset = totaloffset + parentEl.offsetTop
			parentEl = parentEl.offsetParent;
		}
	return totaloffset;
}

function BottomEdgeOffset (obj, menu)
	{
		var offset = 0
		var topedge = isIE? theDoc().scrollTop : window.pageYOffset
		var windowedge = isIE? theDoc().scrollTop+theDoc().clientHeight-minEdgeClear : window.pageYOffset+window.innerHeight-(minEdgeClear+3)
		if (windowedge-menu.y < menu.offsetHeight)
			{ //need to switch from down to up?
				offset = menu.offsetHeight-windowedge+menu.y
				if ((menu.y - topedge) < menu.offsetHeight) //up no good either?
					offset = menu.y - topedge  // then change offset calc
			}
		return offset
	}

	
function RightEdgeOffsetForPosHoriz (obj, menu)
	{
		var offset = 0
		var windowRedge = isIE? theDoc().scrollLeft + theDoc().clientWidth - minEdgeClear : window.pageXOffset + window.innerWidth - minEdgeClear
		if (windowRedge - menu.x < menu.offsetWidth)
			offset = menu.offsetWidth
		return offset
	}

function RightEdgeOffsetForPosVert (obj, menu)
	{
		var offset = 0
		var windowRedge=isIE? theDoc().scrollLeft+theDoc().clientWidth-minEdgeClear : window.pageXOffset+window.innerWidth-minEdgeClear
		if (windowRedge - menu.x < menu.offsetWidth)
			offset = menu.offsetWidth - windowRedge + menu.x
		return offset
	}

			////////////////		Functions for placing Menus into position		////////////////

function PositionToGrowLeftRight (menu)
{
		// collect needed info from the menu
	var anchor = menu.anchorObj
				// horizontal position coordinate calculation
	var absHPad = menu.flush? 0 : defaultAbsHPad
		// get the actual offsets to the object around which we ar putting the menuu
		// this is either the trigger link or a box whose ID has been passed
	var xOffsetObj = HorizPosOffset(anchor)
	var xOffsetObjParent = HorizPosOffset(menu.parentMenu)
		// following computation finds the adjustment for borders not being counted in the anchor
			// compute it here based on actual display rather than trying to pass numbers to two places
			// or attempting the difficult task of reading the style sheet
			// note that Safari needs both the top border of the menu and that of the individual cell
			// and in some browsers we still might be off by a pixel or two
	var hAnchFineAdj = (menu.hFineAdj != null)? -menu.hFineAdj : (level > 1 && !menu.isBoxed)? Math.floor((anchor.parentNode.offsetWidth % anchor.offsetWidth)/2) : 0
		// following computation finds the pad in ie; would do borders in others; all others count the pad with the anchor
	var hAnchPadAdj = (level > 1 && isIE && !menu.isBoxed)? ((xOffsetObj - xOffsetObjParent) % anchor.offsetWidth) : 0
		// if flush is set on a right, grow right, that is from left outside thence internally of previous one and vice versa
	var hPadBesideAnchor = ((level == 1 || menu.isHoriz) && menu.isBoxed && !isIcab) * defaultHPadBesideAnchor
	var anchorWidth = menu.flush? - hAnchFineAdj * (isSafEng? 2:1) - hAnchPadAdj + defaultFlushPad  : anchor.offsetWidth - hAnchFineAdj + hPadBesideAnchor// don't or do offset by object width; if flush go right to edge
	menu.x = xOffsetObj + anchorWidth + (isIE&&level==1? ieHorizPadAdjustFirstAc : 0) // only ie needs this absolute pad
		//no go see if there is room to go right
	
	rightinset = RightEdgeOffsetForPosHoriz(anchor, menu)
	if (rightinset > 0 || menu.menuPosition == "left")  // flip over to position growing left of anchor edge
		{ // but we will assume if they say left they mean it, and we won't look at the margin there
			if (menu.flush) {menu.x = menu.x + anchor.offsetWidth + 2 * hAnchFineAdj - 2 * defaultFlushPad - menu.offsetWidth}
			else {menu.x = menu.x - anchor.offsetWidth - menu.offsetWidth - absHPad - 2 * hPadBesideAnchor}				
		}
	else   //the default is position on right side of anchor
		 {menu.x += absHPad}	
		
	if (level == 1) {menu.style.left = menu.x + "px"} // first one handled differently from the rest
	else {menu.style.left = menu.x - xOffsetObjParent+ "px"}

				//vertical position coordinate calculation
	var vcentre = menu.centre
	var yOffsetObj = VertPosOffset (anchor)// parent won't work as it may be a list presented vertically, would take very top
	var yOffsetParent = VertPosOffset (menu.parentMenu)
	var vAnchFineAdj = (menu.vFineAdj != null)? -menu.vFineAdj : (level > 1 && !menu.isBoxed)? (anchor.parentNode.offsetHeight % anchor.offsetHeight) : 0
		// following computation finds the pad in ie; would do borders in others
	var vAnchPadAdj = (level > 1 && isIE)? ((yOffsetObj - yOffsetParent) % anchor.offsetHeight) : 0
		//note special absolute pad for ie below 6
	menu.y = yOffsetObj - vAnchPadAdj - vAnchFineAdj * (isSafEng&&!menu.isBoxed? 2:1)  + (isIE&&level==1? ieVertPadAdjustFirstDn : 0)//cant go from last menu.y because could be partway down a vertical menu
	var shifty = (vcentre? Math.floor (0.5 * (anchor.offsetHeight - menu.offsetHeight)) : 0)// centre vertical calc if vcentre set
	menu.y = Math.max (menu.y + shifty, minEdgeClear) //don't allow to exceed top in any case
	
	bottominset = BottomEdgeOffset(anchor, menu)
	if (bottominset > 0) menu.y = menu.y - menu.offsetHeight + anchor.offsetHeight + vAnchFineAdj//flip down to up

    if (level == 1) {menu.style.top = menu.y +"px"} 
	else {menu.style.top = menu.y - yOffsetParent + "px"}


}

function PositionOverlap (menu)
{	// covers overlap (that is, hung from anchor--right direction first if possible) left, right and centred variations of all three
	// overlap ignores flush but may use centre for vertical centering, plural for overlap both ways
		// collect needed info from the menu
		// comments on calculations are thinner here; see the one above for more detail
	var anchor = menu.anchorObj
	
				// horizontal position coordinate calculation
		// get the actual offsets to the object around which we ar putting the menuu
		// this is either the trigger link or a box whose ID has been passed
	var xOffsetObj = HorizPosOffset(anchor)
	var xOffsetObjParent = HorizPosOffset(menu.parentMenu)
	var anchorWidth = anchor.offsetWidth

		// horizontal position coordinate calculation
	menu.x = xOffsetObj + Math.floor((1 - defaultRelHOverlap) * anchorWidth)
	rightinset = RightEdgeOffsetForPosHoriz(anchor, menu)
	
	if (rightinset > 0) //in this case position to grow left side if there is room there, else stay growing right
		{menu.x = menu.x - (Math.floor((1 - 2 * defaultRelHOverlap)*anchorWidth) + menu.offsetWidth)} // flip over left
	if (level == 1) {menu.style.left = menu.x + "px"} // first one handled differently from the rest
	else {menu.style.left = menu.x - xOffsetObjParent + "px"}

		//vertical position coordinate calculation
	var yOffsetObj = VertPosOffset(anchor)// parent won't work as it may be a list presented vertically, would take very top
	var yOffsetParent = VertPosOffset(menu.parentMenu) //captures to top of menu
	var vcentre = menu.centre
	var vflush = menu.flush
	var vAnchFineAdj = (menu.vFineAdj != null)? -menu.vFineAdj : (level > 1 && !menu.isBoxed)? (anchor.parentNode.offsetHeight % anchor.offsetHeight) : 0
	var vAnchPadAdj = (level > 1 && isIE)? ((yOffsetObj - yOffsetParent) % anchor.offsetHeight) : 0
	
	menu.y = yOffsetObj - vAnchPadAdj - vAnchFineAdj * (isSafEng&&!menu.isBoxed? 2:1)  + (isIE&&level == 1? ieVertPadAdjustFirstDn : 0)//cant go from last menu.y because could be partway down a vertical menu
	var shifty = 0  // default is flush with object edge
	if (vcentre) shifty += Math.floor (0.5 * (anchor.offsetHeight - menu.offsetHeight))	// centre vertical calc if vcentre set
	else if (!vflush)  // note that tooltip takes no modifiers
		{
		if (menu.menuPosition == "tooltip")
			{shifty = shifty + Math.floor(defaultRelVOverlap*anchor.offsetHeight) - menu.offsetHeight + vAnchFineAdj}
		else
			shifty += Math.floor((1-defaultRelVOverlap)*anchor.offsetHeight)
		}
	menu.y += shifty
	menu.y = Math.max (menu.y, minEdgeClear) //dont allow to exceed top
	bottominset = BottomEdgeOffset(anchor, menu)
	
	if (bottominset > 0 && yOffsetObj > bottominset) //then position to grow up if there is room there, else stay down
		menu.y -= bottominset
		
    if (level == 1) {menu.style.top = menu.y +"px"} 
	else {menu.style.top = menu.y - yOffsetParent + "px"} 

}

function PositionAmid (menu)
{	// centres on target object both ways
		// collect needed info from the menu
		// we do less pixel positioning with this style as it wouldn't be too visible
	var anchor = menu.anchorObj
	var xOffsetObj = HorizPosOffset(anchor)
	var xOffsetObjParent = HorizPosOffset(menu.parentMenu)
	var yOffsetObj = VertPosOffset(anchor)// parent won't work as it may be a list presented vertically, would take very top
	var yOffsetParent = VertPosOffset(menu.parentMenu) //captures to top of menu

		// horizontal position coordinate calculation
	menu.x = xOffsetObj
	var shiftx =  Math.floor (0.5 * (anchor.offsetWidth - menu.offsetWidth))
	menu.x = Math.max (menu.x + shiftx, minEdgeClear) //dont allow to exceed left margin in any case
	rightinset = RightEdgeOffsetForPosHoriz(anchor, menu)
	
	if (rightinset > 0 && menu.x - rightinset > minEdgeClear) //if insufficient room on right and enough on left
		menu.x -= rightinset 	// then pull in by inset amount			
		
	if (level == 1) {menu.style.left = menu.x + "px"} // first one handled differently from the rest
	else {menu.style.left = menu.x - xOffsetObjParent + "px"}

		//vertical position coordinate calculation
	menu.y = yOffsetObj + (isIE&&level == 1? ieVertPadAdjustFirstDn : 0)
	var shifty = Math.floor (0.5*(anchor.offsetHeight - menu.offsetHeight))// centre vertical calc 
	menu.y = Math.max (menu.y + shifty, minEdgeClear) //dont allow to exceed top in any case
	bottominset = BottomEdgeOffset(anchor, menu)
	
	if (bottominset > 0 && menu.y - bottominset > minEdgeClear) //if insufficient room on right and enough on left
		menu.y -= menu.offsetHeight  // then pull in by inset amount	

    if (level == 1) {menu.style.top = menu.y +"px"} 
	else {menu.style.top = menu.y - yOffsetParent + "px"} 

}

function PositionToGrowUpDown (menu)
{		// covers up and down growth directions and centred versions of these
	var anchor = menu.anchorObj
	
	
		// horizontal position coordinate calculation
	var hcentre = menu.centre // not doing vcentre this way -- see the overlap one for that
	var xOffsetObj = HorizPosOffset(anchor)
	var xOffsetObjParent = HorizPosOffset(menu.parentMenu)
	menu.x = xOffsetObj + (isIE&&level==1? ieHorizPadAdjustFirstAc : 0)
	var shift = hcentre? Math.floor (0.5*(anchor.offsetWidth - menu.offsetWidth)) : 0// centre horiz?
	menu.x = Math.max (menu.x + shift, minEdgeClear)

	rightinset = RightEdgeOffsetForPosVert(anchor, menu)
	menu.x -= rightinset
	if (level == 1) {menu.style.left = menu.x + "px"} //first level in is absolute
	else {menu.style.left = menu.x - xOffsetObjParent + "px"} // but then it's relative. 

		// vertical position coordinate calculation
	var padWhenUnder = menu.flush? 0 : defaultVertPadWhenUnder
	var yOffsetObj = VertPosOffset(anchor)// parent won't work as it may be a list presented vertically, would take very top
	var yOffsetParent = VertPosOffset(menu.parentMenu) //captures to top of menu
	var vAnchFineAdj = (menu.vFineAdj != null)? -menu.vFineAdj : (level > 1)? (menu.parentMenu.offsetHeight % anchor.offsetHeight) : 0
		// following computation finds the pad in ie; would do borders in others
	var vAnchPadAdj = (level > 1 && (isIE||isOp))? Math.floor(((yOffsetObj - yOffsetParent) % anchor.offsetHeight)/2) : 0
	var anchorHeight = menu.flush? - vAnchFineAdj * (isSafEng&&!menu.isBoxed? 2:1) - vAnchPadAdj + padWhenUnder : menu.parentMenu.isHoriz? menu.parentMenu.offsetHeight - vAnchPadAdj - vAnchFineAdj : anchor.offsetHeight
	menu.y = (menu.parentMenu.isHoriz? yOffsetParent : yOffsetObj) + anchorHeight + (isIE&&level == 1? ieVertPadAdjustFirstDn : 0)
	
	bottominset = BottomEdgeOffset(anchor, menu)
	if ((bottominset > 0 || menu.menuPosition == "up") && yOffsetObj > menu.offsetHeight + 8) menu.y -= (menu.offsetHeight + anchorHeight + vAnchPadAdj+ 2 * padWhenUnder) // flip bottom to top 
	if (level == 1) {menu.style.top = menu.y + "px"} //measured from top of screen
	else {menu.style.top = menu.y - yOffsetParent + "px"} // measured from top of main div
}


			////////////////		shows and hides		/////////

function HideThisLevel (lev) // hides passed level and does nothing else
{
	if (chainLinks[lev].drop) chainLinks[lev].style.display="none"
	else chainLinks[lev].style.visibility = 'hidden'
}

function HideAllMenus (menu) // hides from level of menu passed down to and including level one -- the whole chain
{
	for (var count = menu.levnum; count > 0; count--)
		{HideThisLevel (count)}
	level = 0
	prevMenuLevel = 0
	hidepending = false
}

function HideAllLevelsDown (lev) // from this level back to and including level one -- the whole chain
{
	for (var count = lev; count > 0; count--)
		{HideThisLevel (count)}
	level = 0
	prevMenuLevel = 0
	hidepending = false
}

function DelayHideAbovelastID () // attach a delayed hide to everything above the last ID
{
	ClearHide () // in case someone else hid them first
	delayhidechain = setTimeout ("HideAbovelastID()", shortHideDelay)
	hidepending = true  // set a flag so we know if this state exists

}

function HideAbovelastID ()
{
	while (level > 0 && chainLinks[level].myMenuID != lastID)
	{
		Hide (chainLinks[level])
		level--
	}
	hidepending = false // only after the actual hide executes
	prevMenuLevel = level
}

function DelayHideAllMenusDown (menu)  //prepare to hide from here back to one with a delay
{
	ClearHide ()
	var lev = menu.levnum
	if (longhide)
		delayhidechain=setTimeout("HideAllLevelsDown("+lev+")",longHideDelay)
	else
		delayhidechain=setTimeout("HideAllLevelsDown("+lev+")",shortHideDelay)
	hidepending = true
}

function ClearHide ()
{ 
	if (delayhidechain)
		{
			clearTimeout (delayhidechain)
			delayhidechain = null
			level = prevMenuLevel
		}
}

							// setupChainmenu
	// can be used in an external .js file so as not to clutter up the html
	// Pre: triggerID must be present or nothing happens
			// if pMenuBody ends in a +, does a forced immediate call to chainmenu to display the item
	// note that this one takes a single ID, so if you want to set up the same menu on two IDs you must call this twice.
	// obviously you can't do that with drops however, as their position is fixed once visible.
	// if the pLevel is negative, we trigger on a click rather than on a hover.

function setupChainmenu (triggerID, pMenuBodyID, pLevel, pGrowPos, pBoxID, pHFineAdj, pVFineAdj)
{	
	var triggerObj= document.getElementById(triggerID);
	if (triggerObj) // must be present or do nothing
		{
			show = (pMenuBodyID.charAt (pMenuBodyID.length-1) == "+"); // does memu body ID end in a "+"
			if (show) // then force initial show of menubody
				{
					pMenuBodyID = pMenuBodyID.slice (0,-1); // slice it off					
					chainmenu(triggerObj, event, pMenuBodyID, pLevel, pGrowPos, pBoxID, pHFineAdj, pVFineAdj); // and actually show the item
				}
			if (pLevel >= 0) //negative ==> show on click; else ==> show on rollover
				triggerObj.onmouseover = function(event) {chainmenu(triggerObj, event, pMenuBodyID, pLevel, pGrowPos, pBoxID, pHFineAdj, pVFineAdj)}
			else
				triggerObj.onclick = function(event) {chainmenu(triggerObj, event, pMenuBodyID, pLevel, pGrowPos, pBoxID, pHFineAdj, pVFineAdj)}
		}
}

////////////////		Main Menu Proc		chainmenu      //////////////

function chainmenu (pTriggerObj, pEvent, pMenuBodyID, pLevel, pGrowPos, pBoxID, pHFineAdj, pVFineAdj)
{
	var menuBody = document.getElementById(pMenuBodyID);
	if (!menuBody) return // do nothing if menu body not actually there
	if (window.event) event.cancelBubble = true
	else if (pEvent.stopPropagation) pEvent.stopPropagation()
	if (ie5||ns6)
		{//debug("here1"+pTriggerObj.Id)
			if (hidepending) ClearHide ()
			if (pLevel == null) pLevel = level++	// can get away with no level for first one, but after that must supply. Incrementing will only sorta work
			if (Math.abs(pLevel) == 1)  // starting a new chain
			{ 
				ClearHide () 				// take out any pending hide
				HideAllLevelsDown (level) 	// and do an immediate hide of any showing menu for starting over
			}
				
			if (level == 0)	//i.e. the current level is zero, before anything happens on this chain	
					// start a new chain where the default anchor level 0 is just the anchor, not a true menu in this system
					// that is, the initial anchor is always independent, can have any formatting or page arrangement
							// we are not currently using most of this stuff, so it may be killable.
				{ 
					chainLinks[0] = pTriggerObj
					chainLinks[0].parentMenu = null
					chainLinks[0].levnum = 0
					chainLinks[0].myMenuID = pTriggerObj.ID != null? pTriggerObj.ID : defRootID // store the anchor's ID if it has one; this not used yet, but might need
					chainLinks[0].anchorObj = pTriggerObj
					//chainLinks[0].y = VertPosOffset(pTriggerObj)
					//chainLinks[0].x = HorizPosOffset(pTriggerObj)
						// next item in use
					if (hideChainOnAnchorClick) chainLinks[0].parentNode.onclick = function() { HideAllMenus(chainLinks[level])}
				}  
					
			else  // cover off the case of coming into a menu trigger from its own body at any level
			{
				if (pMenuBodyID == chainLinks[level].myMenuID) {return true}
			}
			
			level = Math.abs(parseInt (pLevel, 10)) // ok ready to set up for current level
					// hide all higher level menus on  the chain in case we dropped into a lower one
					// must hide same level too as could be going into another of same level
			for (prevMenuLevel; prevMenuLevel >= level; prevMenuLevel--)
			  {Hide (chainLinks[prevMenuLevel])}
					
			prevMenuLevel = level;
			chainLinks[level] = menuBody
			chainLinks[level].levnum = level
			chainLinks[level].myMenuID = pMenuBodyID
			chainLinks[level].triggerObj = pTriggerObj
			chainLinks[level].parentMenu = chainLinks[level-1]
			chainLinks[level].isBoxed = (pBoxID != null && pBoxID !='')
			chainLinks[level].drop = (pGrowPos.slice (0,4) == "drop") // don't use modifiers in this case
			
			longhide = (chainLinks[level].drop || chainLinks[level].isBoxed)
			
			if (!chainLinks[level].isBoxed) // no box passed to be the  menuanchor
				{
					chainLinks[level].anchorObj = pTriggerObj // if no box position passed, use the anchor object
					
				}
			else 		// but if one is, use it, and treat it like part of the menu body
				{
					chainLinks[level].anchorObj = document.getElementById(pBoxID)
					chainLinks[level].triggerObj.onmouseout = function(){DelayHideAllMenusDown(chainLinks[level])} // attach to trigger passed
				}
			chainLinks[level].anchorObj.onmouseout = function(){DelayHideAllMenusDown(chainLinks[level])} // attach to anchor
			if (hideChainOnMenuClick) menuBody.onclick = function() {HideAllMenus (chainLinks[level])}
			chainLinks[level].onmouseover = function(event) {rollOnMenuBody (event, pMenuBodyID)}
			chainLinks[level].onmouseout = function() {DelayHideAllMenusDown(chainLinks[level])}
			Show (chainLinks[level])
			
				//now, parse the GrowPos parameter
					// if null use the defaults set in the variable section
			if (pGrowPos == null) {pGrowPos = (level == 1? defaultFirstGrowDirection : defaultLeftRightPos)}					 
			else
				{
					// special case; kill any tooltip modifiers; don't use them
				if (pGrowPos.slice (0,7) == "tooltip") pGrowPos = "tooltip" 
				
						// now pull off all the modifiers and set program flags accordingly 
					var centre = flush = isHoriz = false // assume neither before parsing off modifiers; can be in any order
					do
						{
							var lastCh = pGrowPos.charAt (pGrowPos.length-1).toLowerCase()
							centre = centre || (lastCh == "c") 		// used by all styles to centre on the other dimension of the anchor
							flush = flush || (lastCh == "f") 		// flush is used by all but the overlap style, covers up the anchor
							isHoriz = isHoriz || (lastCh == "h") 	// this is a helper flag to tell the script the menu is horizontal, that is, one cell high
							
							if (lastCh == "c" || lastCh == "f") pGrowPos = pGrowPos.slice (0,-1)
						}
					while (lastCh == "c" || lastCh == "f")
				}				
				chainLinks[level].centre = centre
				chainLinks[level].flush = flush
					// if they don't tell us it's horizontal, try to compute whether it is
				chainLinks[level].isHoriz = isHoriz || (chainLinks[level].offsetHeight  < horizThreshhold)
	
				chainLinks[level].menuPosition = pGrowPos
					// initialize the fine adj to zero to start with; then see if they supplied anything for us
				chainLinks[level].vFineAdj = chainLinks[level].hFineAdj = 0
					// if they give only one parameter for fine adjustments, use it both horizontal and vertical
					// using parseInt also allows them to use a string instead of an integer
				if (pHFineAdj != null) chainLinks[level].vFineAdj = (chainLinks[level].hFineAdj = parseInt (pHFineAdj, 10))
					// but if there is a second, use it vertical
				if (pVFineAdj != null) chainLinks[level].vFineAdj = parseInt (pVFineAdj, 10)

				if (chainLinks[level].drop) return
				//debug("here")
				if (pGrowPos == "down" || pGrowPos == "up")
					{ PositionToGrowUpDown (chainLinks[level]) }
				else if (pGrowPos == "amid")
					{ PositionAmid (chainLinks[level]) }
					else if (pGrowPos == "overlap" || pGrowPos == "tooltip")
						{ PositionOverlap (chainLinks[level]) }
						else // note that all others fall here, and right is preferred over left, so "beside" or "gormph" equal right
							{ PositionToGrowLeftRight (chainLinks[level]) }
	
		}
	else testForTransferToAltSite ()	// actually this should be caught above before they try to use the menus, but...
}

			////////////////		enter body proc			////////////////
			
function rollOnMenuBody (pEvent, bodyID)
{
	if (window.event) event.cancelBubble = true
	else if (pEvent.stopPropagation) pEvent.stopPropagation()
	longhide = false
	if (hidepending) {ClearHide ()}
	else return true 

	lastID = bodyID
	DelayHideAbovelastID ()
}


			////////////////		look after errors, etc			////////////////


var errors = new Array()
	// this error only issued if old browser and no alt site defined
errors ["old browser"] = "You are trying to view this site with a browser that is too old to use the dymnamic features of ChainMenu. Please upgrade to a modern browser"



function error (pmessage)
{ window.alert (errors [pmessage]) }



		////////////////		debug code			////////////////

function debug (message)
{	if (level >=0) window.alert (message+"  level="+level)
}


	///////////////		references		/////////////

// sniffer code http://www.webreference.com/tools/browser/sniffer2.js
