/*
Snake navigation object, version 1.0
Created by jonas.bohlin@halogen.com
*/
function Snake(sObj,iLeft,iTop,iWidth,iHeight,iLevels){
	this.sPath = sObj
	this.obj = sObj
	this.x = iLeft
	this.y = iTop
	this.w = iWidth
	this.h = iHeight
	this.sectionW = iWidth/iLevels
	this.levels = new Array()
	this.iCurrentLevel = 0
	this.items = new Array()
	this.iCount = 0
	this.levelIndex = 0
	this.aSelectedPath = new Array()
	Snake_Item.prototype.master = this // not so good.
}
{
	p = Snake.prototype
	p.addLevel = Snake_addLevel
	p.closeLevel = Snake_closeLevel
	p.addItem = Snake_addItem
	p.render = Snake_render
	p.renderSection = Snake_renderSection
	p.renderItem = Snake_renderItem
	p.rollBack = Snake_rollBack
	p.buildPath = Snake_buildPath
	p.forceSelect = Snake_forceSelect
	p.delay = 500
	p.rendered = false
	p.containerBgColor = "transparent"
	p.itemHeight = 16
	p.itemLeftOffset = 15
	p.itemTopOffset = 5
	p.snakeRightWidth = 15
	p.snakeLeftOffset = 2
	p.baseUrl	= null
	p.target = null
	p.skipProcessURL = false
}

function Snake_addLevel(sLabel,sUrl){
	this.addItem(sLabel,sUrl)
	oItem = this.items
	for (i=0;i<this.iCurrentLevel;i++){
		oItem = oItem[oItem.length-1].items
	}
	this.iCurrentLevel++
	oItem[oItem.length-1].levelIndex = this.iCurrentLevel
	oItem[oItem.length-1].iCount = 0
	oItem[oItem.length-1].items = new Array()
}

function Snake_closeLevel(){
	this.iCurrentLevel--
}

function Snake_addItem(sLabel,sUrl,sTarget){
	oItem = this.items
	sPath = this.sPath
	for (i=0;i<this.iCurrentLevel;i++){
		sPath = oItem[oItem.length-1].sPath
		oItem = oItem[oItem.length-1].items
	}
	if (!sTarget) sTarget = this.target
	oItem[oItem.length] = new Snake_Item(sLabel,sUrl,sTarget,sPath,"items["+oItem.length+"]",this.iCurrentLevel)
}

function Snake_Item(sLabel,sUrl,sTarget,sParentPath,sPath,iLevel){
	this.sPath = sParentPath+"."+sPath
	this.label = sLabel
	this.url = sUrl
	this.oParent = eval(sParentPath)
	this.level = iLevel
	if (sTarget) this.target = sTarget
}
{
	p = Snake_Item.prototype
	p.process = Snake_Item_process
	p.setState = Snake_Item_setState
	p.setActive = Snake_Item_setActive
	p.setInActive = Snake_Item_setInActive
	p.showSection = Snake_Item_showSection
	p.hideSection = Snake_Item_hideSection
	p.tracePath = Snake_Item_tracePath
	p.setPathPositions = Snake_Item_setPathPositions
	p.positionDefaultPath = Snake_Item_positionDefaultPath
	p.setPathStyle = Snake_Item_setPathStyle
	p.classAnonymous = "snakeOff"
	p.classKnown = "snakeOver"
	p.classSelected = "snakeOn"
	p.classTrial = "snakeTrial"
	p.classAnonymousSelected = "AnonymousSelected"
	p.classPath = "Path"
	p.classPathSelected = "PathSelected"
	p.classSectionActive = "SectionActive"
	p.classSectionInActive = "SectionInActive"
	p.master = null
	p.target = "self"
	p.inside = false
}

function Snake_render(){
	// apa = new makeLayer(1000,this.x,this.y,this.w,this.h,this.containerBgColor,true,null)
	//alert(this.sPath+".container")

	apa = "snakeContainer"
	this.container = new wrapLayer(apa,this.sPath+".container")
	oLevel = this
	this.renderSection(this,true)	
	iItems = 0
	iSections = 0	
	aRenderLadder = new Array()
	do {
		do { 
			this.renderItem(oLevel.items[oLevel.iCount],oLevel.iCount,oLevel.section)
			iItems++
			if (oLevel.items[oLevel.iCount].items){
				iSections++
				this.renderSection(oLevel.items[oLevel.iCount])				
				aRenderLadder[aRenderLadder.length] = oLevel
				oLevel = oLevel.items[oLevel.iCount]
			} else {
				oLevel.iCount++ //it has a submenu, don't increment
			}
		} while (oLevel.iCount<oLevel.items.length && iItems<1000) //iItems is a safety
		do { //when closing several levels without having any items in between...
			oLevel = aRenderLadder.pop()
			if (oLevel) oLevel.items[oLevel.iCount].rendered = true
		} while (oLevel && !oLevel.items[oLevel.iCount+1])
		if (!oLevel || this.items[this.items.length-1].rendered){
			this.rendered=true;
		} else {
			oLevel.iCount++
		}
	} while (!this.rendered && iItems<1000)
}

function Snake_renderSection(oLevel,bFirst){
	iLevel = oLevel.items[0].level
	setLeft 	= (bFirst)?0:this.sectionW;
 	setWidth	= (oClient.ns6up)?this.sectionW-1:this.sectionW;
	setTop 		= (oClient.ns5up || bFirst)?0:0-oLevel.item.layer.style.pixelTop;
	oNest 		= (bFirst)?this.container:oLevel.item;
	bVis = (bFirst)?true:false;
	apa = new makeLayer(1000,setLeft,setTop,setWidth,this.h,null,bVis,false,oNest,"Section"+oLevel.sPath)
	apa.className = "SnakeLevel"+(iLevel+1)
	oLevel.section = new wrapLayer(apa,oLevel.sPath+".section")
}

function Snake_renderItem(oItem,iCount,oNest){
	//alert(oNest);
	setLeft = 0
 	setWidth = this.sectionW
	setHeight	= (oClient.ns5up)?this.itemHeight+(iCount*this.itemHeight):this.itemHeight;
	setTop = (oClient.ns5up)?0:this.itemTopOffset + iCount*this.itemHeight; //changed here...
	setRelTop = (oClient.ns5up)?this.itemTopOffset + setHeight-this.itemHeight:this.itemTopOffset + 0;
	setZ = (oClient.ns5up)?100-(10*iCount):10+iCount;
	if (!oItem) alert(oItem+","+iCount+","+oNest)
	//add = (oItem.items)?"&nbsp;&raquo;":"";

	// alert(oItem.label + " - " + oItem.level)

	add = (oItem.items)?"&nbsp;":"&nbsp;";
	if (oClient.ns5up) {
		cString = "<SPAN STYLE=\"position: relative; top: "+setRelTop+"px;\"  ID=\"ITEM_"+oItem.level+"_INLINE_"+oItem.sPath+"\">"+oItem.label+add+"</SPAN>"
	} else {
		cString = "<SPAN ID=\"ITEM_"+oItem.level+"_INLINE_"+oItem.sPath+"\">"+oItem.label+add+"</SPAN>"
	}
	apa = new makeLayer(setZ,setLeft,setTop,setWidth,setHeight,null,"inherit",cString,oNest,"ITEM_"+oItem.level+"_CONT_"+oItem.sPath)
	apa.className =  oItem.classAnonymous
	oItem.item = new wrapLayer(apa,oItem.sPath+".item")
	evFunc = new Function("e","e = e || event;"+oItem.sPath+".setState(e)")
	clickFunc = new Function("e","e = e || event;"+oItem.sPath+".process(e)")
	oItem.item.addEvent("onclick",clickFunc,false)
	if (oClient.ie5_5up && !oClient.mac){ //can't know if ms will implement these event handlers in future mac versions
		sEvent1 = "onmouseenter"
		sEvent2 = "onmouseleave"
	} else {
		sEvent1 = "onmouseover" 
		sEvent2 = "onmouseout"
	}
	oItem.item.addEvent(sEvent1,evFunc,false)
	oItem.item.addEvent(sEvent2,evFunc,false)
	if (!oItem.items) oItem.rendered = true
}

function Snake_Item_setState(e){	
	var overInside = (e.type=="mouseover" && this.inside)
	oItem = this.item.layer
	if (oClient.ie4up && !oClient.ie5_5up){
		var skipIt = (overInside || (oItem.contains(e.fromElement) && oItem.contains(e.toElement)))
	} else if (oClient.ns5up){
		var skipIt = (overInside || (oItem.contains(e.relatedTarget) && oItem.contains(e.target))) // this might be made better.
	} else skipIt = false 
	if (skipIt) { 
		if (oClient.ns5up) e.stopPropagation(); 
		else e.cancelBubble = true
		return false;
	} else {
	}
	if (e.type=="mouseover" || e.type=="mouseenter"){
		if (!this.isPath) this.setActive()
		else {
			this.inside = true
			var bRes = this.setPathPositions()
			if (bRes && oClient.ns6) forceRedraw(this.master.container.layer)
		}
	} else if (e.type=="mouseout" || e.type=="mouseleave"){
		if (!this.isPath) this.setInActive(false,e)
		else this.inside=false
	} else {
		alert(e.type)
	}
	if (oClient.ns7up){
		if (window.status==""){
			window.status = window.status+" "
		} else window.status = ""	
	}
}

function Snake_Item_setActive(bInternal){
		res = killTimeout("Hide_"+this.item.id)
		if (this.master.aSelectedPath[0]){	//is there a rollback to kill?
			if (this.section){
				killTimeout("rollBack","1")	
			} else {
				for (var i=0;i<this.oParent.items.length;i++){
					if (this.oParent.items[i].isPath && !this.oParent.items[i].section){
						killTimeout("rollBack","2")
						break;
		}	}	}	}
		if (!this.isPath) this.item.layer.className = this.classKnown
		var bRes = this.setPathPositions()
		if (bRes && oClient.ns6) forceRedraw(this.master.container.layer) //Ugly hack... but it works...	
		if (this.section){
			if (!res){ storeTimeout("Show_"+this.item.id,this.sPath+".showSection()")	}
		}
		this.inside = true
}


function Snake_Item_setInActive(bInternal,oEvent){
		res = killTimeout("Show_"+this.item.id)
		this.item.layer.className = this.classAnonymous
		if (this.section && !bInternal){
			if (!res) storeTimeout("Hide_"+this.item.id,this.sPath+".hideSection(false, \"from setinactive\")")
			if (this.master.aSelectedPath[0] && (this.levelIndex==1 || this.oParent.isPath)) storeTimeout("rollBack",this.master.sPath+".rollBack()",DELAY+5) //strange, with the delay add...
		}
		this.inside = false
		if (oClient.ie4up && (!oEvent.toElement || oEvent.toElement.id.indexOf("ITEM_"+this.level+"_")==-1)){
			this.positionDefaultPath()
		} else if (oClient.ns5up && (oEvent.relatedTarget && oEvent.relatedTarget.id && oEvent.relatedTarget.id.indexOf("ITEM_"+this.level+"_")==-1)){
			this.positionDefaultPath()
		}
}

function Snake_rollBack(){
	for (i=0;i<this.aSelectedPath.length;i++){
		if (this.aSelectedPath[i].section && this.aSelectedPath[i].section.layer.style.visibility=="hidden"){
			this.aSelectedPath[i].showSection(true)
}	}	}

function Snake_Item_showSection(bInternal){
	var aSelectedPath = this.master.aSelectedPath
	if (!bInternal && aSelectedPath[0]){
		aSearchIn = this.oParent.items
		for (var i=0;i<aSearchIn.length;i++){
			if (aSearchIn[i]!=this && aSearchIn[i].isPath && aSearchIn[i].section){
				for (sI=aSelectedPath.length-1;sI>=0;sI--){
					if (aSelectedPath[sI]!=aSearchIn[i]){
						aSelectedPath[sI].hideSection(true,"from showsetion(2)")
					}	else break;
				}
				aSearchIn[i].hideSection(true,"from showsection")
				break;
	}	}	}	
	if (!this.pathRendered){	//if this is first show, render tracepath
		this.items[0].tracePath()
	}
	this.items[0].positionDefaultPath()	
	this.section.layerVis("inherit")
}

function Snake_Item_hideSection(bInternal,sfrom){
	if (!this.section) return false
	this.section.layerVis(false)
	if (oClient.ns6) forceRedraw(this.master.container.layer)
}

function Snake_Item_positionDefaultPath(bAllow){
	var pathSet = false
	var bSet = false
	var oParent = this.oParent
	var oParentItems = oParent.items
	if (oParent.isPath || oParent == this.master){
		for (var i=0;i<oParentItems.length;i++){
			if (oParentItems[i].isPath){
				bRes = oParentItems[i].setPathPositions()
				pathSet = true
				break;
			}
		}
	} 
	if (!pathSet) bRes = oParentItems[0].setPathPositions()
	if (bRes && oClient.ns6) forceRedraw(this.master.container.layer)
}

function Snake_Item_tracePath(bRenderOnly){
	if (this.oParent==this.master){
		this.master.pathRendered = true
		return
	}
	// create path if it doesn't exist
	if (!this.oParent.pathRendered){
		var setWidth =  2
		var setHeight = 2
		var setLeft = 0
		var setTop = 0
		sContent = (oClient.ns5up)?"&nbsp;":"<IMG SRC=\"pixel.gif\" width=\"2\" HEIGHT=\"2\">";
		sContent2 = (oClient.ns5up)?"&nbsp;":"<IMG SRC=\"pixel.gif\" width=\"1\" HEIGHT=\"2\">";
		var oPath = new makeLayer(1,setLeft,setTop,setWidth,setHeight,null,"inherit",sContent,this.oParent.section)
		var oPath2 = new makeLayer(1,setLeft,setTop,setWidth,setHeight,null,"inherit",sContent,this.oParent.section)
		var oPath3 = new makeLayer(1,setLeft,setTop,setWidth,setHeight,null,"inherit",sContent,this.oParent.section)
		var oPath4 = new makeLayer(1,setLeft,setTop,setWidth,setHeight,null,"inherit",sContent2,this.oParent.section)
		oPath.className = "pathSearch"
		oPath2.className = "pathSearch"
		oPath3.className = "pathSearch"
		oPath4.className = "pathSearch"
		this.oParent.pathLeft = new wrapLayer(oPath,this.oParent.sPath+".pathLeft")
		this.oParent.pathVert = new wrapLayer(oPath2,this.oParent.sPath+".pathVert")
		this.oParent.pathRight = new wrapLayer(oPath3,this.oParent.sPath+".pathRight")		
		this.oParent.pathLine = new wrapLayer(oPath4,this.oParent.sPath+".pathLine")
		this.oParent.pathRendered = true
	}	
}

function Snake_Item_setPathPositions(bUselvObj){
		if (this.oParent==this.master) return		
		var objStart = this.oParent
		var objLayerStart = objStart.item.layer 
		var objLayerEnd = this.item.layer
		if (!objStart.startCalculated)	{
			var objLayer = (oClient.ie4)? objLayerStart.children[0] : objLayerStart.childNodes[0] ;
			objStart.startTop = (oClient.ns5up)?objLayer.offsetTop:objLayerStart.offsetTop;
			objStart.startLeft = (oClient.ie && oClient.mac)?objLayerStart.offsetLeft:objLayer.offsetLeft;
			objStart.startWidth = objLayer.offsetWidth
			objStart.startHeight = objLayer.offsetHeight
			objStart.startCalculated = true
		}
		if (!this.endCalculated){
			var objLayer = (oClient.ie4)? objLayerEnd.children[0] : objLayerEnd.childNodes[0] ;
			this.endTop = (oClient.ns5up)?objLayer.offsetTop:objLayerEnd.offsetTop;
			this.endLeft = (oClient.ns6up)?objLayerStart.offsetWidth-objStart.startLeft:objLayerStart.offsetWidth;
			this.endHeight = (!bUselvObj)? objLayer.offsetHeight : objEnd.parentElement.contentHeight ;
			this.endCalculated = true
		}
		var lObj = objStart.pathLeft.layer
		var rObj = objStart.pathRight.layer
		var vObj = objStart.pathVert.layer
		var lvObj = objStart.pathLine.layer
		if (!objStart.pathLeft.placed) {
			lObj.style.left = ( objStart.startLeft+objStart.startWidth ) - this.endLeft
			if (oClient.ie4) setWidth = -1*parseInt(lObj.style.left)- ( this.master.snakeRightWidth - (vObj.offsetWidth/2))//20 
			else setWidth = -1*lObj.offsetLeft- ( this.master.snakeRightWidth - (vObj.offsetWidth/2))//-this.master.snakeRightWidth //20;
			if (setWidth<0){
				 setWidth = 0 //avoid error in ie
			}
			lObj.style.width = setWidth
			lObj.style.top = objStart.startTop+(objStart.startHeight/2)
			objStart.pathLeft.placed = true
		}
		if (!objStart.pathRight.placed){		
			rObj.style.width = this.master.snakeRightWidth - (vObj.offsetWidth/2)
			if (oClient.ie4) setLeft = lObj.offsetLeft + parseInt(lObj.style.width)
			else setLeft = lObj.offsetLeft + lObj.offsetWidth
			rObj.style.left = setLeft
			objStart.pathRight.placed = true
		}
		rObj.style.top = this.endTop+(this.endHeight/2)
		objStart.pathRight.placedAt = this.sPath
		if (!objStart.pathVert.placed){
			if (oClient.ie4) setLeft = lObj.offsetLeft+parseInt(lObj.style.width)-(parseInt(vObj.style.width)/2)
			else setLeft = lObj.offsetLeft+lObj.offsetWidth-(vObj.offsetWidth/2)
			vObj.style.left = setLeft
			objStart.pathVert.placed = true
		}

		// find top position and bottom position
		if (oClient.ie4){
			var lTop = parseInt(lObj.style.top)
			var rTop = parseInt(rObj.style.top)
			var lHeight = parseInt(lObj.style.height)
			var rHeight =parseInt(rObj.style.height)
		} else {
			var lTop = lObj.offsetTop
			var rTop = rObj.offsetTop
			var lHeight = lObj.offsetHeight
			var rHeight = rObj.offsetHeight
		}
		var isTop = Math.max(lTop,rTop)
		var isBottom = Math.min(lTop+lHeight,rTop+rHeight)
		var setHeight = isTop-isBottom+4 
		var setTop = Math.min(rTop,lTop) 
		vObj.style.top = setTop
		vObj.style.height = setHeight
		if (lvObj && !this.oParent.pathLine.placed){
			if (oClient.ie4) lvObj.style.left = rObj.offsetLeft+parseInt(rObj.style.width)-1 
			else lvObj.style.left = rObj.offsetLeft+rObj.offsetWidth-1
			lvObj.style.width = 1
			lvObj.style.height = objStart.items.length*this.master.itemHeight
			lvObj.style.top = (oClient.ns5up) ? objLayerEnd.offsetTop +  this.master.itemTopOffset : objLayerEnd.offsetTop;
			this.oParent.pathLine.placed = true
		}	
		this.setPathStyle()
	return true
}
function Snake_Item_process(e){
	var oMaster	= this.master
	if (oClient.ns5up) e.stopPropagation()
	else e.cancelBubble = true
	res = killTimeout("Show_"+this.item.id)
	if (this.section) this.showSection()
	oMaster.buildPath(this,e)
	if (!oMaster.skipProcessURL){
		if (oMaster.baseUrl) this.url = oMaster.baseUrl + this.url
		if (!this.target || this.target=="self"){
			top.location = this.url
		} else if (this.target) {
			eval(this.target + ".location = "+this.url)
		}
	}
}

function Snake_buildPath(oItem,e){
	aSearchPath = new Array()
	aSearchPath[aSearchPath.length] = oItem
	pStr = oItem.sPath
	do {
		pStr = pStr.substring(0,pStr.lastIndexOf("."))
		bTest = (pStr.indexOf("items")!=-1)
		if (bTest)	aSearchPath[aSearchPath.length]=eval(pStr)
	} while (bTest)
	aSearchPath.reverse()
	//merge the searchPath with the selectPath...
	iStart = this.aSelectedPath.length-1
	for (var i=iStart;i>=0;i--){
		if (this.aSelectedPath[i]!=aSearchPath[i]){
			var oOldItem = this.aSelectedPath.pop()
			oOldItem.inside = false
			oOldItem.isPath = false
			oOldItem.item.layer.className = oOldItem.classAnonymous
			if (oOldItem.oParent==oItem) oItem.items[0].setPathPositions()
			oOldItem.hideSection(true)
		} else {
			break;
		}
	}
	for (var i=0;i<aSearchPath.length;i++){
		if (aSearchPath[i]!=this.aSelectedPath[i]){
			oSelItem = aSearchPath[i]
			oSelItem.inside = true			
			oSelItem.isPath = true
			if (i == 2) {
				oSelItem.item.layer.className = oItem.classSelected
			} else {
				oSelItem.item.layer.className = oItem.classTrial
			}
			if (oSelItem.oParent && oSelItem.oParent.pathLeft){
				oSelItem.setPathStyle()
			}
			this.aSelectedPath[i] = oSelItem
		}
	}
}

function Snake_Item_setPathStyle(bHide){
	oSection = this.oParent
	if (!bHide){
		sStyle = (this.isPath)?"pathSelected":"pathSearch";
	} else sStyle = "pathSearchInvisible"
	bChange = (sStyle!=oSection.pathLeft.layer.className)
	if (bChange){
		lObj = oSection.pathLeft.layer
		rObj = oSection.pathRight.layer
		vObj = oSection.pathVert.layer
		lvObj = oSection.pathLine.layer
		if (oClient.ns5up) { //Save for screen updating. bugfix.
			rTop = rObj.offsetTop
			vTop = vObj.offsetTop
		}
		lObj.className = sStyle
		rObj.className = sStyle
		vObj.className = sStyle
		lvObj.className = sStyle

		if (oClient.ns5up) {//Apply fix for screen updating
			rObj.style.top = 0
			vObj.style.top = 0
			rObj.style.top = rTop+"px;"
			vObj.style.top = vTop+"px;"
		}
	}
	
}

var fRedraws = 0
function forceRedraw(oToChange){
	var oStyle = oToChange.style
	var sOldColor = oStyle.backgroundColor
	var sSetColor = (sOldColor=="rgb(0,0,0)")?"#FFFFFF":"#000000";
	oStyle.backgroundColor = sSetColor
	oStyle.backgroundColor = sOldColor
}

function Snake_forceSelect(sIndex,aUrls){
	if (sIndex){
		iStopPos = sIndex.indexOf("_0")
		iReadTo = (iStopPos>-1)? iStopPos : sIndex.length ;
		aSelect = sIndex.substring(0,iReadTo).split("_")
		for (i=0;i<aSelect.length;i++){
			aSelect[i]--
		}
		oLevel = this
		for (i=0;i<aSelect.length-1;i++){
			oLevel = oLevel.items[aSelect[i]]
			oLevel.item.layer.className = oLevel.classKnown
			oLevel.setPathPositions()
			oLevel.showSection(true)
		}
		oLastItem = oLevel.items[aSelect[aSelect.length-1]]
		sClass=oLevel.classKnown || oLevel.items[0].classKnown
		oLastItem.item.layer.className = sClass
		oLastItem.setPathPositions()		
		if (oLastItem.section){ oLastItem.showSection(true)	}
		this.buildPath(oLastItem)

	} else if (aUrls) {
		alert("Forceselect - aUrls")

		var aItems = [0,0,0,0]
		if (typeof(aUrls)!="string"){
			oLevel = this.items
			for (var u=0;u<aUrls.length;u++){
				for (var i=0;i<oLevel.length;i++){
					if (oLevel[i].url == aUrls[u]){
						aItems[u]=i+1
						break;
					}
				}
				if (i<oLevel.length){
					oLevel = oLevel[i].items
				} else {
					aItems = null
					break;
				}
			}
			if (aItems){
					sPath = aItems.join("_")	
					this.forceSelect(sPath)
			} else alert("could not locate url "+aUrls[u]+"\nAbort forceSelect()")
		} else {
			alert("Not implemented. Find "+aUrls)		
		}
	}
}
