/* requires getElementsByClassName() */

var DHTML_TOP_OFFSET = 50;					// px amount that the menu should float, from the bottom of the target (.dhtml_menu element)
var DHTML_RIGHT_OFFSET = 0;					// px amount that the menu should float, from the right of the target (.dhtml_menu element)
var DHTML_TIMER = 2000;						// amount in milliseconds to wait before checking to see if your mouse is still over a menu or target, before closing the menu, when you mouse off of a target or menu

var FIXED_TOP = null;						// overrides offsets
var FIXED_LEFT = null;						// overrides offsets
var SHOW_ANIMATE = null;					// function to call instead of displaying

var dhtml_targets = [];						// array of .dhtml_menu elements
var dhtml_menus = [];						// array of .dhtml_menu_content elements
var dhtml_offsets = [];						// array of offsets, parallel to targets and menus
var dhtml_menu = null;						// reference to visible menu
var dhtml_mouse_over = null;				// reference to menu if mouse is over the target or over the menu (target refers to the .dhtml_menu element firing the mouseover event)
var dhtml_timer = null;						// timer identifier
var dhtml_menu_execute = true;				// false to stop execution of open or close

var dhtml_listeners = {						// array of listener callbacks
	load:[] ,
	load_container:[] ,
	before_open:[] ,
	open:[] ,
	before_close:[] ,
	close:[] ,
	over:[] ,
	after_over:[] ,
	off:[] ,
	over_child:[] ,
	off_child:[] ,
	timer_check:[] ,
	clear_timer:[] ,
	mousedown:[]
};

var dhtml_menu_containers = [];				// array of container references, 2d array; first element is menu container, second is content container

function DHTML_Menu_Listener_Add( evt , callback )
{
	// callback should be a function reference
	// returns the index of new event callback
	
	if ( typeof dhtml_listeners[evt] == "undefined" )
		return;
	
	dhtml_listeners[ evt ].push( callback );
	
	return( dhtml_listeners[ evt ].length - 1 );
}

function DHTML_Menu_Listener_Remove( evt , index )
{
	if ( typeof dhtml_listeners[evt] != "undefined" || dhtml_listeners[evt].length <= index )
		return;
	
	dhtml_listeners[evt][ index ] = null;
}

function DHTML_Menu_Execute_Listeners( evt , arg )
{
	// execute listeners for evt
	
	if ( typeof dhtml_listeners[evt] == "undefined" )
		return( false );
	
	var func, len = dhtml_listeners[evt].length;
	
	for (i = 0; i < len; i++)
	{
		if ( typeof dhtml_listeners[evt][i] == "function" )
			func = dhtml_listeners[evt][i];
		else if ( dhtml_listeners[evt][i] != null && typeof window[ dhtml_listeners[evt][i] ] == "function" )
			func = window[ dhtml_listeners[evt][i] ];
		else
			func = null;
		
		if ( typeof func == "function" )
		{
			if ( arg ) func( arg );
			else func();
		}
	}
	
	return( true );
}

function DHTML_Menu_Container_Add( dhtml_menu_container , dhtml_menu_content_container , top_offset , right_offset , init )
{
	if ( typeof top_offset == "undefined" || top_offset === false || top_offset == null )
		top_offset = DHTML_TOP_OFFSET;
	
	if ( typeof right_offset == "undefined" || right_offset === false || right_offset == null )
		right_offset = DHTML_RIGHT_OFFSET;

	// pass as id values or element references
	dhtml_menu_containers.push( [ dhtml_menu_container , dhtml_menu_content_container ] );
	
	dhtml_offsets.push( [ top_offset , right_offset ] );
	
	if ( init )
		DHTML_Menu_Container_Init( dhtml_menu_container , dhtml_menu_content_container , top_offset , right_offset );
}

function DHTML_Menu_Init()
{
	var i, len;
	var x, container_len;
	var target_container, menu_container;
	
	if ( (container_len = dhtml_menu_containers.length) == 0 )
	{
		dhtml_menu_containers.push( [ document.body , document.body ] );
		container_len = 1;
	}
	
	for (x = 0; x < container_len; x++) {
		if ( dhtml_offsets[x] )
			DHTML_Menu_Container_Init( dhtml_menu_containers[x][0] , dhtml_menu_containers[x][1] , dhtml_offsets[x][0] , dhtml_offsets[x][1] );
	}
	
	DHTML_Menu_Execute_Listeners("load");
}

function DHTML_Menu_Container_Init( dhtml_menu_container , dhtml_menu_content_container , top_offset , right_offset )
{
	if ( typeof dhtml_menu_container == "string" )
		target_container = document.getElementById( dhtml_menu_container );
	else
		target_container = dhtml_menu_container;
	
	if ( typeof dhtml_menu_content_container == "string" )
		menu_container = document.getElementById( dhtml_menu_content_container );
	else
		menu_container = dhtml_menu_content_container;
	
	// ID should be on target parent element
	dhtml_targets = getElementsByClassName("dhtml_menu", target_container);
	dhtml_menus = getElementsByClassName("dhtml_menu_content", menu_container);
	
	len = dhtml_targets.length;
	for (i = 0; i < len; i++)
	{
		dhtml_targets[i].onmouseover = DHTML_Menu_MouseOver;
		dhtml_targets[i].onmouseout = DHTML_Menu_MouseOut;
	}

	len = dhtml_menus.length;
	for (i = 0; i < len; i++)
	{
		dhtml_menus[i].onmouseover = DHTML_Menu_MouseOverChild;
		dhtml_menus[i].onmouseout = DHTML_Menu_MouseOutChild;
		
		dhtml_menus[i].setAttribute("top_offset", top_offset);
		dhtml_menus[i].setAttribute("right_offset", right_offset);
	}
	
	DHTML_Menu_Execute_Listeners( "load_container" , [ dhtml_menu_container , dhtml_menu_content_container ] );
}

function DHTML_Menu_MouseOver(e)
{
	if ( dhtml_menu && dhtml_menu.getAttribute('id') == this.getAttribute('id') +'_menu' )
	{
		//DHTML_Menu_ClearTimer();
		return;
	} else if ( dhtml_menu )
		DHTML_Menu_Close( dhtml_menu , true );				// force a close, no timer check, cause we gotta open the new menu
	
	if ( !DHTML_Menu_GetChild( this ) )						// the dhtml_menu element has no child (menu) to display, so hide the current menu, when applicable, and exit
		return;

	dhtml_mouse_over = this;
	
	DHTML_Menu_Execute_Listeners("before_open", this);
	DHTML_Menu_Open( this );
	
	DHTML_Menu_Execute_Listeners("over", this);
	DHTML_Menu_Execute_Listeners("after_over", this);
}

function DHTML_Menu_MouseOut(e)
{
	if ( dhtml_mouse_over == this )
		dhtml_mouse_over = null;
	
	if ( DHTML_Menu_GetChild(this) == dhtml_menu )
		DHTML_Menu_Close( dhtml_menu );
	
	DHTML_Menu_Execute_Listeners("off");
}

function DHTML_Menu_MouseOverChild(e)
{
	dhtml_mouse_over = DHTML_Menu_Parent( this );
	
	DHTML_Menu_Execute_Listeners("over_child");
}

function DHTML_Menu_MouseOutChild(e)
{
	var target = DHTML_Menu_Parent( this );
	
	if ( target == dhtml_mouse_over )
		dhtml_mouse_over = null;
	
	DHTML_Menu_Execute_Listeners("off_child");
}

function DHTML_Menu_Open( target )
{
	if ( !dhtml_menu_execute )
	{
		dhtml_menu_execute = true;
		return;
	}
	
	var n_menu = DHTML_Menu_GetChild( target );

	if ( typeof SHOW_ANIMATE == "function" )
		SHOW_ANIMATE( n_menu );
	else
	{
		var target_info = getNodeInfo( target );
		var top_offset = parseInt( n_menu.getAttribute("top_offset") );
		var right_offset = parseInt( n_menu.getAttribute("right_offset") );

		if ( FIXED_LEFT != null )
			n_menu.style.left = FIXED_LEFT +"px";
		else
			n_menu.style.left = (target_info.x + target_info.w - right_offset) +"px";

		if ( FIXED_TOP != null )
			n_menu.style.top = FIXED_TOP +"px";
		else
			n_menu.style.top = (target_info.y + target_info.h + top_offset) +"px";
	
		n_menu.style.display = "block";
		n_menu.style.zIndex = 99;
	}
	
	dhtml_menu = n_menu;
	target.className = target.className.replace("dhtml_menu", "dhtml_menu_active");
	
	DHTML_Menu_Execute_Listeners("open");
}

function DHTML_Menu_Close( n , force )
{
	DHTML_Menu_ClearTimer();
	if ( !dhtml_menu_execute )
	{
		dhtml_menu_execute = true;
		return;
	}
	if ( force )
	{
		if ( n == dhtml_menu )
			dhtml_menu = null;
		
		n.style.display = "none";
		n.style.zIndex = '';
		
		var target = DHTML_Menu_Parent( n );
		target.className = target.className.replace("dhtml_menu_active", "dhtml_menu");
		
		DHTML_Menu_Execute_Listeners("close");
		
		return;
	} else if  ( dhtml_mouse_over != n )
		dhtml_timer = setTimeout(DHTML_Menu_CheckClose, DHTML_TIMER);
}

function DHTML_Menu_CheckClose()
{
	DHTML_Menu_ClearTimer();
	
	if ( dhtml_menu && ( !dhtml_mouse_over || dhtml_mouse_over != DHTML_Menu_Parent( dhtml_menu ) ) )
		DHTML_Menu_Close( dhtml_menu , true );
	else
		dhtml_timer = setTimeout(DHTML_Menu_CheckClose, DHTML_TIMER);
	
	DHTML_Menu_Execute_Listeners("timer_check");
}

function DHTML_Menu_Parent( n_child )
{
	var id = n_child.getAttribute("id").replace("_menu", "");
	return( document.getElementById(id) || null );
}

function DHTML_Menu_GetChild(n_parent)
{
	var id = n_parent.getAttribute("id");
	return( document.getElementById(id +"_menu") || null );
}

function DHTML_Menu_ClearTimer()
{
	if ( dhtml_timer )
	{
		clearTimeout(dhtml_timer);
		dhtml_timer = null;
		
		DHTML_Menu_Execute_Listeners("clear_timer");
	}
}

function DHTML_Doc_MouseDown(e)
{
	if ( dhtml_menu && !dhtml_mouse_over )
	{
		DHTML_Menu_Close( dhtml_menu , true );											// force a close, user clicked elsewhere in the document
		DHTML_Menu_Execute_Listeners("mousedown");
	}
}

if ( window.addEventListener )
{
	window.addEventListener("load", DHTML_Menu_Init, false);
	document.addEventListener("mousedown", DHTML_Doc_MouseDown, false);
} else {
	window.attachEvent("onload", DHTML_Menu_Init);
	document.attachEvent("onmousedown", DHTML_Doc_MouseDown);
}
