
function JsMenu(f_var_name, f_wrapper_id)
{
	// Private properties
	this._var_name = false;
	this._wrapper_id = false;
	this._wrapper_element = false;
	this._timer = false;
	this._loaded = null;

	this._layers = new Array();





	// Public properties
	this.timer_delay = 500; // Delay before closing menu for 'onmouseout'.
	this.layer_zindex = 800; // Initial z-index for first layer
	this.layer_max = 10; // The maximum layer depth





	// Private methods
	this._init = function(f_var_name, f_wrapper_id)
	{
		if(document.getElementById(f_wrapper_id))
		{
			this._var_name = f_var_name;
			this._wrapper_id = f_wrapper_id;
			this._wrapper_element = document.getElementById(f_wrapper_id);


			// Create layer tweaking settings
			for(var i = 0; i < this.layer_max; i++)
			{
				var o = new Object();
				o.top = 0;
				o.left = 0;
				o.width = 0;
				o.height = 0;

				this._layers[i] = o;
			}
		}
		else
		{
			alert('Cannot locate wrapper #' + f_wrapper_id + ' for JsMenu.');
		}
	}

	// Parse inner <li> of main <ul>
	this._loadMain = function(f_div_element, f_ul_element)
	{
		var iIndex = 0;

		for(var i = 0; i < f_ul_element.childNodes.length; i++)
		{
			if((f_ul_element.childNodes[i].nodeType == 1) && (f_ul_element.childNodes[i].tagName.toLowerCase() == 'li'))
			{
				this._loadItem(f_div_element, f_ul_element.childNodes[i], 0, iIndex, 'jsmenu_' + this._wrapper_id + '_' + iIndex);
				iIndex++;
			}
		}
	}

	// Parse inner <ul>
	this._loadSub = function(f_ul_element, f_layer, f_index, f_prefix)
	{
		// Create <div> to replace <ul>
		var oDIV = document.createElement('div');

		oDIV.id = f_prefix;
		oDIV.className = 'jsmenu_sub jsmenu_sub_' + this._wrapper_id;

		if(eval('this._layers[' + f_layer + '].width > 0'))
		{
			eval('oDIV.style.width = this._layers[' + f_layer + '].width + \'px\'');
		}

		oDIV.style.overflow = 'hidden';
		oDIV.style.zIndex = this.layer_zindex + f_layer;

		eval('oDIV.setAttribute(\'__TOP\', this._layers[' + f_layer + '].top)');
		eval('oDIV.setAttribute(\'__LEFT\', this._layers[' + (f_layer - 1) + '].width + this._layers[' + f_layer + '].left)');


		// Parse inner <li>
		var iIndex = 0;

		for(var i = 0; i < f_ul_element.childNodes.length; i++)
		{
			if((f_ul_element.childNodes[i].nodeType == 1) && (f_ul_element.childNodes[i].tagName.toLowerCase() == 'li'))
			{
				this._loadItem(oDIV, f_ul_element.childNodes[i], f_layer, iIndex, f_prefix + '_' + iIndex);
				iIndex++;
			}
		}

		document.body.appendChild(oDIV);
	}

	// Parse inner <li>
	this._loadItem = function(f_div_element, f_li_element, f_layer, f_index, f_prefix)
	{
		// Create <div> to replace <li>
		var oDIV = document.createElement('div');
		oDIV.className = 'jsmenu_item' + (f_li_element.className ? ' ' + f_li_element.className : ''); 

		eval('oDIV.onmouseover = function() { ' + this._var_name + '._show(this, \'' + f_prefix + '\'); }');
		eval('oDIV.onmouseout = function() { ' + this._var_name + '._hide(true); }');

		// Parse inner <a>
		var a = f_li_element.getElementsByTagName('a');

		if(a.length)
		{
			if(eval('this._layers[' + f_layer + '].height > 0'))
			{
				eval('a[0].style.height = this._layers[' + f_layer + '].height + \'px\'');
				eval('a[0].style.lineHeight = this._layers[' + f_layer + '].height + \'px\'');
			}

			// Transfer <a> from <li> to <div>
			oDIV.appendChild(a[0]);
			f_div_element.appendChild(oDIV);


			// See if <li> contains <ul>
			var a = f_li_element.getElementsByTagName('ul');

			if(a.length)
			{
				// Load sublayer
				this._loadSub(a[0], f_layer + 1, f_index, f_prefix);
			}
		}
	}

	// ONMOUSEOUT-event to hide sublayers
	this._hide = function(f_delay)
	{
		this._resetTimer();

		if(f_delay) // Close all menu's with delay
		{
			this._timer = setTimeout(this._var_name + '._hide()', this.timer_delay);
		}
		else // Hide ALL div.jsmenu_sub (even other instances)
		{
			var a = document.getElementsByTagName('div');

			for(var i = 0; i < a.length; i++)
			{
				if(a[i].className.substr(0, 10) == 'jsmenu_sub')
				{
					a[i].style.display = 'none';
				}
			}
		}
	}

	// ONMOUSEOVER-event to show sublayer
	this._show = function(f_element, f_prefix)
	{
		this._resetTimer();

		var a = document.getElementsByTagName('div');

		for(var i = 0; i < a.length; i++)
		{
			if(a[i].className.substr(0, 10) == 'jsmenu_sub')
			{
				if(f_prefix == a[i].id) // Self
				{
					if(f_element)
					{
						a[i].style.left = (this._getOffsetLeft(f_element) + parseInt(a[i].getAttribute('__LEFT'))) + 'px'; 
						a[i].style.top = (this._getOffsetTop(f_element) + parseInt(a[i].getAttribute('__TOP'))) + 'px';
					}

					a[i].style.display = 'block';
				}
				else if(a[i].id == f_prefix.substr(0, a[i].id.length)) // Show ancestors
				{
					a[i].style.display = 'block';
				}
				else
				{
					a[i].style.display = 'none';
				}
			}
		}
	}

	// Reset timer
	this._resetTimer = function()
	{
		if(this._timer)
		{
			clearTimeout(this._timer);
		}
	}

	// Get real element offset
	this._getOffsetLeft = function(f_element)
	{
		var left = 0;

		do
		{
			left += f_element.offsetLeft;
		} 
		while(f_element = f_element.offsetParent);

		return left;
	}

	// Get real element offset
	this._getOffsetTop = function(f_element)
	{
		var top = 0;

		do
		{
			top += f_element.offsetTop;
		} 
		while(f_element = f_element.offsetParent);

		return top;
	}





	// Public methods
	this.isValid = function()
	{
		return (this._var_name && this._wrapper_id && this._wrapper_element && ((this.loaded == null ? true : this.loaded)));
	}

	// Load <ul>|<li> structure to <div>|<div> structure
	this.load = function()
	{
		if(this.isValid() && (this._loaded == null))
		{
			this._loaded = false;


			// Find inner UL
			var a = this._wrapper_element.getElementsByTagName('ul');

			if(a.length > 0)
			{
				// Add div.droprightmenu_main
				var oDIV = document.createElement('div');
				oDIV.className = 'jsmenu_main jsmenu_main_' + this._wrapper_id;
				oDIV.style.zIndex = this.layer_zindex;

				this._wrapper_element.appendChild(oDIV);

				this._loadMain(oDIV, a[0]);

				// Remove main UL from wrapper
				this._wrapper_element.removeChild(a[0]);

				this._loaded = true;
			}
			else
			{
				alert('Cannot locate UL within #' + this._wrapper_id + ' for JsMenu.');
			}
		}
	}


	// Tweak layer positioning
	this.setTop = function(f_top, f_start_layer, f_limit)
	{
		if(f_start_layer == undefined)
		{
			f_start_layer = 0;
		}

		if(f_limit == undefined)
		{
			f_limit = this._layers.length;
		}
		else
		{
			f_limit += f_start_layer;
		}

		for(var i = f_start_layer; i < f_limit; i++)
		{
			this._layers[i].top = f_top;
		}
	}

	this.setLeft = function(f_left, f_start_layer, f_limit)
	{
		if(f_start_layer == undefined)
		{
			f_start_layer = 0;
		}

		if(f_limit == undefined)
		{
			f_limit = this._layers.length;
		}
		else
		{
			f_limit += f_start_layer;
		}

		for(var i = f_start_layer; i < f_limit; i++)
		{
			this._layers[i].left = f_left;
		}
	}

	this.setHeight = function(f_height, f_start_layer, f_limit)
	{
		if(f_start_layer == undefined)
		{
			f_start_layer = 0;
		}

		if(f_limit == undefined)
		{
			f_limit = this._layers.length;
		}
		else
		{
			f_limit += f_start_layer;
		}

		for(var i = f_start_layer; i < f_limit; i++)
		{
			this._layers[i].height = f_height;
		}
	}

	this.setWidth = function(f_width, f_start_layer, f_limit)
	{
		if(f_start_layer == undefined)
		{
			f_start_layer = 0;
		}

		if(f_limit == undefined)
		{
			f_limit = this._layers.length;
		}
		else
		{
			f_limit += f_start_layer;
		}

		for(var i = f_start_layer; i < f_limit; i++)
		{
			this._layers[i].width = f_width;
		}
	}





	// Initialize
	this._init(f_var_name, f_wrapper_id);
}

