// created by: André Dietisheim (dietisheim@sphere.ch)
// created: 2002-04-22
// modified by: André Dietisheim (dietisheim@sphere.ch)
// modified: 2004-02-07
// version: 2.4.4

function Xmenu( sNavigationName, sNavigation, globals, styles, contents )
{
	if( !Xmenu.prototype.instances ) Xmenu.prototype.instances = new Array();
	Xmenu.prototype.instances[ Xmenu.prototype.instances.length ] = this; // store this instance in static Array

	this.index = Xmenu.prototype.instances.length - 1;

	this.sNavigationName = sNavigationName;
	this.sNavigation = sNavigation;
	this.iType = globals[ 0 ];
	this.iCloseDelay = globals[ 1 ] * 1000;
	this.bClick = globals[ 2 ];
	this.bMenuBelow = globals[ 3 ];
	this.bLeftAlign = globals[ 4 ];
	this.bKeepExpansionState = globals[ 5 ];
	this.bHighlightClickedNodes = globals[ 6 ];
	this.sSpacerUrl = globals[ 8 ];
	this.styles = styles;
	this.contents = contents;

	this.iContent = 0;
	this.tree = null;
	this.overNode = null;
	this.outNode = null;
	this.lastNode = null;
	this.absY = 0;
	this.timeout = null;
	this.bOpened = false;
	iParentLayerWidth = ( is.iemac5up )? 0 : globals[ 7 ][ 0 ]; // XparentLayer disturbs Xlayer-events on iemac5
	iParentLayerHeight = ( is.iemac5up )? 0 : globals[ 7 ][ 1 ];
	this.xlayerParent = new XlayerParent( "XlayerParent" + this.index, this.sSpacerUrl, null, iParentLayerWidth, iParentLayerHeight, null );

	this.tree = this.buildTree( 0, 0, false, null, "tree" );

	this.nodeFound = null;
	this.navigationNode = null;
	if ( this.findNode( this.sNavigation, this.tree ) )
	{ // node indicated in request found
		this.navigationNode = eval( "this." + this.nodeFound );
	}
}

Xmenu.prototype.VERTICAL = 0;
Xmenu.prototype.HORIZONTAL = 1;
Xmenu.prototype.COLLAPSING = 2;

Xmenu.prototype.buildTree = function( iAbsX, iAbsY, bSibling, sParent, sPath )
{	
		var node = this.buildNode( iAbsX, iAbsY, bSibling, sParent, sPath );
		this.iContent++;
		if ( this.iContent < this.contents.length && node.iLevel < this.contents[ this.iContent ][ 2 ] )
		{ // child
			node.child = this.buildTree(  node.absX, node.absY, false, "this." + node.sPath, node.sPath + ".child" );
		}
		if ( this.iContent < this.contents.length && node.iLevel == this.contents[ this.iContent ][ 2 ] )
		{ // sibling
			node.sibling = this.buildTree( node.absX, node.absY, true, node.sParent, node.sPath + ".sibling" );
		}
		node.xlayer = this.addXlayer( this.xlayerParent, node, this.styles )
		return node;
}

Xmenu.prototype.buildNode = function( iAbsX, iAbsY, bSibling, sParent, sPath )
{
	var node = new Object();
	node.child = null;
	node.sibling = null;
	node.sParent = sParent;
	node.sPath = sPath;

	node.sText = this.contents[ this.iContent ][ 0 ];
	node.target = this.contents[ this.iContent ][ 1 ];
	node.iLevel = this.contents[ this.iContent ][ 2 ];

	if ( this.iType == this.VERTICAL )
	{
		if ( !bSibling )
		{ // child
			if ( node.iLevel > 1 || ( node.iLevel == 1 && !this.bMenuBelow ) ) // level 1 && menu to the right || level 2,3, ...: add width + xOffset
				node.absX = iAbsX + this.styles[ node.iLevel + 1 ][ 2 ] + this.styles[ node.iLevel + 1 ][ 0 ];
			else // level 0, 1 || node 1 && menu below: add xOffset
				node.absX = iAbsX + this.styles[ node.iLevel + 1 ][ 0 ];

			if ( node.iLevel != 1 || ( node.iLevel == 1 && !this.bMenuBelow ) ) // level 0, 2, 3, ... : add yOffset
				node.absY = iAbsY + this.styles[ node.iLevel + 1 ][ 1 ];
			else // level 1: add height of last node + yOffset
				node.absY = iAbsY + this.styles[ node.iLevel + 1 ][ 1 ] + this.styles[ node.iLevel ][ 3 ];
		}
		else
		{ // sibling
			node.absX = iAbsX;
			node.absY = iAbsY + this.styles[ node.iLevel + 1 ][ 3 ];
		}
	}
	else if ( this.iType == this.HORIZONTAL )
	{
		if ( !bSibling )
		{ // child
			if ( node.iLevel > 1 || ( this.bMenuBelow && node.iLevel == 1 ) )
			{ // ( level 1 && menu below ), level 2, 3, 4, ...
				node.absY = iAbsY + this.styles[ node.iLevel + 1 ][ 1 ] + this.styles[ node.iLevel ][ 3 ];
				if ( !this.bLeftAlign ) // add height of last + yOffset, add xOffset
					node.absX = iAbsX + this.styles[ node.iLevel + 1 ][ 0 ];
				else
					node.absX = this.styles[ node.iLevel + 1 ][ 0 ] + this.cumulateOffsets( 0, node.iLevel ) + ( ( node.iLevel > 0 && !this.bMenuBelow )? this.styles[ 1 ][ 2 ] : 0 );
			}
			else
			{ // level 0, ( level 1 && menu on the right ) 
				node.absY = iAbsY + this.styles[ node.iLevel + 1 ][ 1 ];
				if ( !this.bLeftAlign ) // add yOffset, add width of last + xOffset
					node.absX = iAbsX + this.styles[ node.iLevel + 1 ][ 0 ] + ( ( node.iLevel > 0 )? this.styles[ node.iLevel + 1 ][ 2 ] : 0 );
				else
					node.absX = this.styles[ node.iLevel + 1 ][ 0 ] + this.cumulateOffsets( 0, node.iLevel ) + ( ( node.iLevel > 0 && !this.bMenuBelow )? this.styles[ 1 ][ 2 ] : 0 );
			}
		}
		else
		{ // sibling
			node.absY = iAbsY;
			node.absX = iAbsX + this.styles[ node.iLevel + 1 ][ 2 ];
		}
	}
	else if ( this.iType == this.COLLAPSING )
	{
		if ( !bSibling )
		{ // child
			node.absX = iAbsX + this.styles[ node.iLevel + 1 ][ 0 ];
			node.absY = iAbsY + this.styles[ node.iLevel + 1 ][ 1 ];
		}
		else
		{ // sibling
			node.absX = iAbsX;
			node.absY = iAbsY + this.styles[ node.iLevel + 1 ][ 3 ];
		}
	}

	return node;
}

Xmenu.prototype.cumulateOffsets = function( iStyleIndex, iMaxLevel )
{
	var iOffset = 0;
	for ( i = 0; i < iMaxLevel; i++ )
	{
		iOffset += this.styles[ i + 1 ][ iStyleIndex ];
	}
	return iOffset;
}

Xmenu.prototype.addXlayer = function( xparentLayer, node, styles )
{
	var parent =	null;
	var x =	"left";
	var y =	"top";
	var offsetX = node.absX;
	var offsetY = node.absY;
	var w =	styles[ node.iLevel + 1 ][ 2 ];
	var h = styles[ node.iLevel + 1 ][ 3 ];
	var clipTop = 0;
	var clipRight = w;
	var clipBottom = h;
	var clipLeft = 0;
	var zIndex =	node.iLevel;
	var visibility = false;
	var fading =	styles[ node.iLevel + 1 ][ 4 ];
	var events =	
	[ 
		Xlayer.prototype.MOUSEOVER, "Xmenu.prototype.instances[" + this.index + "].onmouseover( Xmenu.prototype.instances[" + this.index + "]." + node.sPath + ")",
		Xlayer.prototype.MOUSEOUT, "Xmenu.prototype.instances[" + this.index + "].onmouseout( Xmenu.prototype.instances[" + this.index + "]." + node.sPath + ")",
		Xlayer.prototype.CLICK, "Xmenu.prototype.instances[" + this.index + "].onclick( Xmenu.prototype.instances[" + this.index + "]." + node.sPath + ")"
	];						
	var sText =  node.sText;
	var bgcolor = styles[ node.iLevel + 1 ][ 5 ][ 0 ];
	var fgcolor =  styles[ node.iLevel + 1 ][ 5 ][ 1 ];
	var bgimage = styles[ node.iLevel + 1 ][ 5 ][ 15 ];
	var align =  styles[ node.iLevel + 1 ][ 5 ][ 2 ];
	var iTopTextBorder = styles[ node.iLevel + 1 ][ 5 ][ 3 ]
	var iRightTextBorder = styles[ node.iLevel + 1 ][ 5 ][ 4 ]
	var iBottomTextBorder = styles[ node.iLevel + 1 ][ 5 ][ 5 ]
	var iLeftTextBorder = styles[ node.iLevel + 1 ][ 5 ][ 6 ]
	var href = null;
	var bold =  styles[ node.iLevel + 1 ][ 5 ][ 7 ];
	var fontface =  styles[ node.iLevel + 1 ][ 5 ][ 8 ];
	var fontsize =  styles[ node.iLevel + 1 ][ 5 ][ 9 ];
	if ( styles[ node.iLevel + 1 ][ 5 ][ 11 ] )
	{	// icon defined
		var icon = ( node.child || styles[ node.iLevel + 1 ][ 5 ][ 10 ] )? styles[ node.iLevel + 1 ][ 5 ][ 11 ] : this.sSpacerUrl;
		var icon_w = styles[ node.iLevel + 1 ][ 5 ][ 12 ];
		var icon_h = styles[ node.iLevel + 1 ][ 5 ][ 13 ];
		var iconBorder = styles[ node.iLevel + 1 ][ 5 ][ 14 ];
	}
	else
	{	// icon not defined
		var icon = null;
		var icon_w = 0;
		var icon_h = 0;
		var iconBorder = 0;
	}
	var src = null; // iframe: src

	return new Xlayer( parent, xparentLayer, x, y, offsetX, offsetY, w, h, clipTop, clipRight, clipBottom, clipLeft, zIndex, visibility, bgcolor, fading, events, sText, bold, align, iTopTextBorder, iRightTextBorder, iBottomTextBorder, iLeftTextBorder, fgcolor, href, icon, icon_w, icon_h, iconBorder, fontface, fontsize, src, this.sSpacerUrl, bgimage );
}

Xmenu.prototype.create = function()
{
	this.createXlayers( null );
	this.setVisibSiblings( this.tree, true );
}

Xmenu.prototype.createXlayers = function( tree )
{
	if ( !tree ) 
	{ // call without param -> take root node
		tree = this.tree;
	}
	if ( tree.child )
	{
		this.createXlayers( tree.child );
	}
	if ( tree.sibling )
	{
		 this.createXlayers( tree.sibling );
	}

	tree.xlayer.create();
}

Xmenu.prototype.setOpenListener = function( openListener )
{
	this.openListener = openListener;
}

Xmenu.prototype.setCloseListener = function( closeListener )
{
	this.closeListener = closeListener;
}

Xmenu.prototype.setLinkClickListener = function( linkClickListener )
{
	this.linkClickListener = linkClickListener;
}

Xmenu.prototype.open = function()
{	
	if ( this.navigationNode != null )
	{
		this.openLastClicked();
	}
	else
	{
		this.setVisibSiblings( this.tree, true );
	}
	this.bOpened = true;
	this.openListener.onMenuOpen( this );
}

Xmenu.prototype.openLastClicked = function()
{
	node = this.navigationNode;
	this.lastNode = node;

	if ( node.child != null )
		this.setVisibSiblings( node.child, true );

	while ( node != null )
	{
		this.highlightClickedNode( node );
		if ( node.sParent != null )
		{
			this.setVisibSiblings( eval( node.sParent ).child, true );
			node = eval( node.sParent );
		}
		else
		{
			this.setVisibSiblings( this.tree, true );
			node = null;
		}
	}
}

Xmenu.prototype.findNode = function( sText, node )
{
	if ( this.nodeFound )
		return true;

	if ( node.child )
		this.findNode( sText, node.child );

	if ( node.sibling )
		this.findNode( sText, node.sibling );

	if ( sText == node.sText )
		this.nodeFound = node.sPath;

	if ( this.nodeFound ) 
		return true;
	else 
		return false;
}

Xmenu.prototype.close = function()
{
	if ( this.bOpened && !this.bKeepExpansionState )
	{
		this.setVisibChildren( this.tree, false );
		this.setVisibSiblings( this.tree, true );
		if ( this.iType == this.COLLAPSING )
			this.setCollapsePos( this.tree );
//		if ( this.bClick && this.lastNode )
//		{
			this.clearHighlightChildren( this.tree );
			this.lastNode = null;
//		}

		this.bOpened = false;
		this.closeListener.onMenuClose( this );
	}
}

Xmenu.prototype.onmouseover = function( node )
{
	this.overNode = node;
	if ( ( this.iType == this.VERTICAL || this.iType == this.HORIZONTAL ) && !this.bClick )
	{
		if ( !this.bOpened )
		{ // this menu will open
			this.bOpened = true;
			this.openListener.onMenuOpen( this );
		}
		if ( this.outNode )
			var outNode = this.outNode;
		else
			var outNode = this.tree;
		if ( outNode.iLevel > node.iLevel )
		{
			this.showBranch( node, this.outNode );
//			this.setVisibSiblings( eval( outNode.sParent + ".child" ), false );
//			this.setVisibSiblings( outNode.child, false );
		}
		else if ( outNode.iLevel == node.iLevel )
		{
			this.setVisibSiblings( outNode.child, false );
		}
		this.setVisibSiblings( node.child, true );
	}
	if ( this.checkClickPath( node ) )
	{ // current node is not the node that was clicked (or its parents)
		this.highlight( node, true );
	}
	
	return false;
}

Xmenu.prototype.onmouseout = function( node )
{
	if ( this.checkClickPath( node ) )
		this.highlight( node, false );

	if ( ( this.iType == this.VERTICAL || this.iType == this.HORIZONTAL ) && !this.bClick ) // close menu if no onmouseover until timeout
	{
		clearTimeout( this.timeout );
		this.timeout = setTimeout( "Xmenu.prototype.instances[" + this.index + "].checkOnmouseout()", this.iCloseDelay );
	}
	
	this.outNode = node;
	return false;
}

Xmenu.prototype.checkClickPath = function( node )
{
	if ( this.bHighlightClickedNodes )
	{
		lastNode = this.lastNode;
		while ( lastNode != null )
		{
			if ( lastNode == node ) // node clicked found
				return false;
			else // continue looking for it
				lastNode = eval( lastNode.sParent );
		}
		return true;
	}
	else
	{
		return true;
	}
}

Xmenu.prototype.checkOnmouseout = function()
{
	if ( this.overNode == this.outNode && !( this.bKeepExpansionState && this.bClick ) ) // onmouseover executed since delay?
		this.close();
}

Xmenu.prototype.onclick = function( node )
{	
	if ( node.target )
	{ // follow href
		node.target.open( node.sText, this.sNavigationName, this.sNavigation );
		this.sNavigation = node.sText;
		this.navigationNode = node; // store navigation node
		this.linkClickListener.onLinkClick( this ); // inform controller
	}
	else if (
		( ( this.iType == this.VERTICAL || this.iType == this.HORIZONTAL ) && this.bClick ) || 
		this.iType == this.COLLAPSING )
	{
		this.highlight( node, true );
		if ( !this.bOpened )
		{ // this menu will open
			this.bOpened = true;
			this.openListener.onMenuOpen( this );
		}
	
		if ( this.iType == this.COLLAPSING )
			this.collapse( node );
		else if ( ( this.iType == this.VERTICAL || this.iType == this.HORIZONTAL ) && this.bClick )
			this.showBranch( node, this.lastNode );
		this.lastNode = node;
	}
	return false;
}

Xmenu.prototype.showBranch = function( node, hideNode )
{
//	if ( this.bClick && hideNode == node && node.child && node.child.xlayer.isVisible() )
	if ( this.bClick && node.child && node.child.xlayer.isVisible() )
	{ // reclose branch
		this.setVisibChildren( node.child, false );
		this.clearHighlightChildren( node, false );
	}
	else
	{
		if ( hideNode )
		{ // hide old nodes
			this.setVisibChildren( this.tree, false );
			this.clearHighlightChildren( this.tree, false );
		}
		if ( node.child ) this.setVisibSiblings( node.child, true );
		while ( node )
		{ // show new nodes
			if ( this.bClick )
				this.highlightClickedNode( node, true );
			if ( node.sParent ) 
				this.setVisibSiblings( eval( node.sParent ).child, true );
			else
				this.setVisibSiblings( this.tree, true );
			node = eval( node.sParent );
		}
	}
}

Xmenu.prototype.clearHighlightChildren = function( node )
{
	if ( node )
	{
		if	( node.child )
			 this.clearHighlightChildren( node.child );
		if ( node.sibling )
			 this.clearHighlightChildren( node.sibling );
		this.highlight( node, false );
	}
}

Xmenu.prototype.collapse = function( node )
{
	this.showBranch( node, this.lastNode );
	this.setCollapsePos( this.tree );
}

Xmenu.prototype.setCollapsePos = function( node )
{
	if ( node == this.tree ) // start looping
		this.absY = this.tree.xlayer.y;
			
	if ( node.xlayer.isVisible() )
	{
		node.xlayer.setPos( node.xlayer.x, this.absY );
		this.absY += node.xlayer.h;
	}

	if ( node.child ) 
		this.setCollapsePos( node.child );
	if ( node.sibling ) 
		this.setCollapsePos( node.sibling );
}

Xmenu.prototype.highlight = function( node, bHighlight )
{
	if( bHighlight )	// style for mouseover 
	{
		node.xlayer.setBgColor( this.styles[ node.iLevel + 1 ][ 6 ][ 0 ] );
		// nn4 crashes, iemac stops rendering
		if ( !is.nn4up && !is.iemac5up ) 
			node.xlayer.setFgColor( this.styles[ node.iLevel + 1 ][ 6 ][ 1 ] );
	
		if( this.styles[ node.iLevel + 1 ][ 6 ][ 14 ] != null)
		{
			if ( is.nn4up )
				node.xlayer.setBgImage( this.styles[ node.iLevel + 1 ][ 6 ][ 14 ] );
			else if ( is.iewin5up || is.iemac5up || is.gk || is.sf || is.kq3up || is.op6up )
				node.xlayer.setBgImage( this.styles[ node.iLevel + 1 ][ 6 ][ 14 ] );
		}
	}
	else // style for mouseout
	{
		node.xlayer.setBgColor( this.styles[ node.iLevel + 1 ][ 5 ][ 0 ] );
		// nn4 crashes, iemac stops rendering
		if ( !is.nn4up && !is.iemac5up ) 
			node.xlayer.setFgColor( this.styles[ node.iLevel + 1 ][ 5 ][ 1 ] );
	
		if( this.styles[ node.iLevel + 1 ][ 5 ][ 14 ] != null)
		{
			if ( is.nn4up )
				node.xlayer.setBgImage( this.styles[ node.iLevel + 1 ][ 5 ][ 15 ] );
			else if ( is.iewin5up || is.iemac5up || is.gk || is.sf || is.kq3up || is.op6up )
				node.xlayer.setBgImage( this.styles[ node.iLevel + 1 ][ 5 ][ 15 ] );
		}
	}	

}

Xmenu.prototype.highlightClickedNode = function( node )
{
	if ( node && this.bHighlightClickedNodes )
	{
		node.xlayer.setBgColor( this.styles[ 0 ][ 0 ] );
		if ( !is.nn4up && !is.iemac5up ) 
			node.xlayer.setFgColor( this.styles[ 0 ][ 1 ] );
	}
}

Xmenu.prototype.setVisibSiblings = function( node, bVisibility )
{
	if ( node )
	{
		if ( node.sibling )
			 this.setVisibSiblings( node.sibling, bVisibility );
		node.xlayer.setVisibility( bVisibility );
	}
}

Xmenu.prototype.setVisibChildren = function( node, bVisibility )
{
	if ( node )
	{
		if	( node.child )
			 this.setVisibChildren( node.child, bVisibility );
		if	( node.sibling )
			 this.setVisibChildren( node.sibling, bVisibility );
		node.xlayer.setVisibility( bVisibility );
	}
}

Xmenu.prototype.isNavigationNodeFound = function()
{
	return this.navigationNode != null;
}
