/*******************************************************************************
 * This file is a part of the software:
 * 
 * enugene 0.9.9.6-beta (c) Copyright 2007-2010 by Bogdan Vojska package:
 * enugene 0.9.9.6-beta-enhanced
 * 
 * developed for Joomla! 1.5
 * 
 * www.bogdan-vojska.eu enugene@bogdan-vojska.eu
 * 
 * LICENCE: Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software using it subject to the following
 * conditions:
 * 
 * The enuGene software version 0.9.1-beta is for free use to any webdesigner or
 * other creative working people using it as part of a web site, controling a
 * web site's menus. The web site may be as well commercial as private. For
 * realizing this usage the software may be copied and distributed free of
 * charge.
 * 
 * The programs code is not free for any changing without another special
 * license or agreement with the above noticed developer. The program or its
 * parts are not free for any kind of commercial or noncommercial reselling, or
 * anykind of use as codepart inside other programs without a otherwise
 * expressly by the developer agreed licence.
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * NOTICE:
 * 
 * There is no guaratee for any compatibility to browsers below the IE 5.5 age.
 * Targeted browsers are full W3C standard compatible browsers.
 */

// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////AJAX TRANSFER CLASS/////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////

function clsMgenAsyncTrans () {
	this.task = 'mgenAjax',
	this.command = '';
	this.format = 'ajax';
	this.method = 'POST';
	this.async = true;
	this.url = '';
	this.taskOptions = '';
	this.connection = '';
	this.onLoaded = '';
	this.arrLocHref = document.location.href.split( '?' );
	this.submitURL = this.arrLocHref[0];
	this.isIeReq = function(){
		var ie = (window.ActiveXObject) ?  true : false; return ie
	};
	
	this.getConnection = function () {
		var connection = '';
		if (this.isIeReq()) {
			try {connection = new ActiveXObject("Msxml2.XMLHTTP");} catch(e){connection = new ActiveXObject("Microsoft.XMLHTTP");};
		} else {
			connection = new XMLHttpRequest();
		}
		if (connection.overrideMimeType) connection.overrideMimeType('text/xml');
		return connection;
	};

	/**
	 * Requesting global variables without changing the cursor icon
	 */
	this.get_usermenu = function () {
		var template = '';
		var arrMetas = document.getElementsByTagName( 'meta' );
		for (var x=0; x<arrMetas.length; ++x) {
			if (arrMetas[x].name == 'template') {
				template = arrMetas[x].content;
				break;
			}
		}
		if (template) {
			this.taskOptions = '&template=' + template;
		}
        this.command = 'get_usermenu';
        this.url = './index.php';
        this.onLoaded = 'enugene.asyncTrans.parse_usermenu';
        this.async = false;
        this.send();
	};
	
	this.get_itemContent = function (itemId) {
        this.command = 'get_itemContent';
        this.taskOptions = '&itemId=' + itemId.substring( 6 );
        this.url = './index.php';
        this.onLoaded = 'enugene.asyncTrans.parse_itemContent';
        this.async = true;
        this.send();
	};

	/**
	 * Requesting data with changing the cursor icon
	 */
    this.requestData = function(url, func, command, wait) {
		var arrCom = '';
		if (wait) document.body.style.cursor = "wait";
		if ((arrCom = command.split( "." )).length > 1) {
			this.task = arrCom[0];
			command = arrCom[1];

		}
        this.command = command;
        this.url = url;
        this.onLoaded = func;
        this.send();  
    };
    
    this.receive = function (httpRequest, strFunction) {
	    if (httpRequest.readyState == 4) {
	        if (httpRequest.status == 200) {
	            if (strFunction && strFunction !== undefined) this.onLoaded = eval( strFunction + '(httpRequest.responseText);'); // process
	        }
	    }
		return null;
    };

    this.send = function() {
		var strSend = '';
        var httpRequest = this.getConnection();
        if (!httpRequest) {
            alert('asyncTrans: No XMLHTTP connection.');
            return false;
        }
		if (!this.command || !this.task) return false;
        strSend += 'mgenTask=' + this.task + '.' + this.command;
        if (this.taskOptions)
        	strSend += this.taskOptions;
        httpRequest.open( this.method, this.url, this.async );
		httpRequest.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;charset=utf-8' );
		if (this.async) {
			httpRequest.onreadystatechange = function( ) { enugene.asyncTrans.receive( httpRequest, enugene.asyncTrans.onLoaded ); };
			httpRequest.send( strSend );
		} else {
			httpRequest.send( strSend );
			if (httpRequest.readyState == 4)
				eval( enugene.asyncTrans.onLoaded + '(httpRequest.responseText);');
		}
        return true;
    };
    
    this.parse_usermenu = function (response) {
/*
document.open();
document.write(response);
document.open(close);
*/

//var t1result = Date.now() - document.t1;
//document.strTime += "\n\t" + 'Client Request Usermenu : ' + ( t1result);

    	eval(response);
    	var usermenu = enugene.menus.usermenu;
		var x = 0;
		var target = '_self';
		if (!usermenu) return '';
		for (x in usermenu) {
			if (!enugene.menus.elements['mgenIt' + x]) {
				continue;
			}
			enugene.menus.elements['mgenIt' + x].link = usermenu[x].link;
			if (usermenu[x].browserNav == true) target = '_blank';
			enugene.menus.elements['mgenIt' + x].target = target;
			// if textype is 'text' leave the text which was written to 
			// the elements unchanged - else get the #__menu table text.
			// BE AWARE - 'text' typed text is not treated by any translator 
			// like Joomfish.
			if (enugene.menus.elements['mgenIt' + x].texttype != 'text') {
				enugene.menus.elements['mgenIt' + x].elemT = usermenu[x].name;
			}
			enugene.menus.elements['mgenIt' + x].userAuth = '1';
			// Only published items come back from the database. 
			// 'published' needs to be set for allowing setMenuProperties()
			// to process the object
			enugene.menus.elements['mgenIt' + x].published = true;
		}
    };
    
    this.parse_itemContent = function (response) {
    	var arrResponse = response.split('-::-');
    	var itemId = arrResponse[0];
    	var content = arrResponse[1];
    	var obj = enugene.DOM.util.getObject('mgenIt' + itemId + 'T');
    	if (obj){
    		obj.innerHTML = content;
    	}
    };
}; // end class mgen_objAsyncTrans

function clsEnugeneDOM (parent) {
	this.parent = '';
	this.util = {
		/**
		 * gets a dom-object by id
		 * 
		 * @param string
		 * @return object
		 */
		getObject : function (id) {
			var obj = null;
			if (document.all)
				obj = document.all[id];
			if (document.getElementById (id))
				obj = document.getElementById (id);
			return obj;
		},
		
		isIe : function () {
			if (document.all) 
				return true; 
			else 
				return false;
		},
		
		set_Property : function (obj, name, value, attr) {
			if (this.isIe( )) {
				if (attr == 'important') attr = ' !important';
				obj.style.setAttribute( 'cssText', name + ':' + value + attr + ';', 0);
			} else {
				obj.style.setProperty( name, value, attr);
			}
		},

		
		/**
		 * @param obj: DOM object reference
		 * @return integer width of the DOM object or that of his firstChild or
		 *         zero
		 */
		getWidth : function (obj) {
			if (enugene.menus.elements[obj.id])
				var width = enugene.menus.elements[obj.id].width;
			if (isNaN( width )) 
				obj = enugene.DOM.util.getObject( obj.id );
			else
				if (width) return width;
			width = obj.offsetWidth
			if (width) return width;
			if (!obj.firstChild || obj.firstChild.offsetWidth === undefined)
				return 0;
			return obj.lastChild.offsetLeft - obj.firstChild.offsetLeft + enugene.DOM.util.getWidth (obj.lastChild);
		},
		
		/**
		 * @param obj: DOM object reference
		 * @return integer height of the DOM object or that of his firstChild or
		 *         zero
		 */
		getHeight : function (obj) {
			if (enugene.menus.elements[obj.id])
				var height = enugene.menus.elements[obj.id].height;
			if (isNaN( height )) 
				obj = enugene.DOM.util.getObject( obj.id );
			else
				if (height) return height;
			height = obj.offsetHeight
			if (height) return height;
			if (!obj.firstChild || obj.firstChild.offsetHeight === undefined)
				return 0;
			return obj.firstChild.offsetHeight;
		},
		
		/**
		 * functions that obtain the coordinates of an HTML element
		 * 
		 * @param object  obj: DOM object reference
		 * @return integer X position to the most upper object (mostcase: <body>)
		 */
		getX : function (obj) {
			var x = 0;
			var n = obj;
			do {
				x += n.offsetLeft;
				n = n.offsetParent;
			}
			while ( n && n.tagName.toLowerCase() != 'body');
			return x;
		},
		
		/**
		 * @param object obj DOM object reference
		 * @return integer
		 */
		getY : function (obj) {
			var y = 0;
			var n = obj;
			do {
				y += n.offsetTop;
				n = n.offsetParent;
			}
			while ( n && n.tagName.toLowerCase() != 'body');
			return y;
		},
		
		get_computedStyle : function (element) {
		   if (window.getComputedStyle) { 
		      return window.getComputedStyle(element, null);
		   } else if (element.currentStyle) { // Ie
		      return element.currentStyle;
		   }
}
		
	}; // end enugene.DOM.util
	
	this.constructor =  {
		name : 'constructor',
		parent : '',
		wEL : 0,
		hEL : 0,
		wER : 0,
		hER : 0,
		objBlockFrame : null,
		
		util : {
		
			/**
			 * Running dynamic mode the target frame for the menu is the
			 * blockFrame, else the menus are positioned absolute into free
			 * floating frames.
			 * 
			 * @return object target frame
			 */
			getMainFrame : function (targetObject, id, theme, positMode) {
				var blockHeight = '';
				var blockWidth = '';
				var returnFrame = null;
				var objBlockFrame = enugene.DOM.constructor.objBlockFrame;
				
				if (positMode == 'dynamic' || positMode == 'accordion') {
					// No blockFrame created by throwMenu? - module not published!
					if (objBlockFrame !== null) {
						blockHeight = enugene.menus.elements[id].blockHeight;
						blockWidth = enugene.menus.elements[id].blockWidth;
						if (parseInt( blockHeight )) {
							objBlockFrame.style.height = blockHeight + 'px';
						} else {
							blockHeight == 'auto' ? objBlockFrame.style.height = 'auto' : objBlockFrame.style.height = '0px';
						}
						if (parseInt( blockWidth )) {
							objBlockFrame.style.width = blockWidth + 'px';
						} else {
							blockWidth == 'auto' ? objBlockFrame.style.width = 'auto' : objBlockFrame.style.width = '0px';
						}
						returnFrame = objBlockFrame;
					}
				} else {
					var floatingFrame = document.createElement('div');
					floatingFrame.id = id + '_mainFrame';
					floatingFrame.style.position = 'absolute';
					floatingFrame.style.width = '0px';
					floatingFrame.style.height = '0px';
					floatingFrame.style.zIndex = 100;
					if (positMode == 'horizontal') {
						floatingFrame.style.top = '0px';
						floatingFrame.style.left = enugene.DOM.util.getX( objBlockFrame ) + 'px';
					}
					if (positMode == 'vertical') {
						floatingFrame.style.top = enugene.DOM.util.getY( objBlockFrame ) + 'px';
						floatingFrame.style.left = '0px';
					}
					if (positMode == 'preset') {
						floatingFrame.style.top = '0px';
						floatingFrame.style.left = '0px';
					}
					returnFrame = floatingFrame;
				}
				// the created or selected frame will be the
				// target for the menus
				return returnFrame;
			},
			
			getSubFrame : function (targetObject, id, positMode) {
				if (enugene.DOM.constructor.objBlockFrame === null) return null;
				var returnFrame = document.createElement('div');
				returnFrame.id = id + '_subFrame';
				if (positMode == 'accordion') {
					returnFrame.style.position = 'relative';
					returnFrame.style.height = '0px';
				} else {
					returnFrame.style.position = 'absolute';
					returnFrame.style.overflow = 'visible';
				}
				returnFrame.style.visibility = 'hidden';
				returnFrame.style.top = '0px';
				returnFrame.style.left = '0px';
				targetObject.appendChild( returnFrame );
				return returnFrame;
			}
		}, // end constructor.util
		
		menu : {
			name : 'menu',
			parent : '',
			getBox : function (id) {
				var cssSelector = '';
				var theme = enugene.menus.elements[id].theme;
				var type = enugene.menus.elements[id].type;
				var bgImg = enugene.menus.elements[id].backgroundImage;
				
				var newObj = document.createElement('div');
				newObj.id = id;
				newObj.className = theme + 'Menu';
				newObj.theme = theme;
				newObj.currentItem = '';
				newObj.topMenuId = enugene.menus.elements[id].topMenuId;
				newObj.parentMenuId = enugene.menus.elements[id].parentMenuId;
				newObj.style.clear = 'both';
				if (type == 'main') {
					newObj.style.position = 'relative';
				} else {
					newObj.style.position = 'absolute';
					newObj.style.visibility = 'hidden';
					newObj.style.zIndex = 100;
				}
				if (bgImg) {
					newObj.load_backgroundImage = 'url(' + bgImg + ')';
					newObj.style.backgroundImage = 'url(' + bgImg + ')';
				}
				return newObj;
			},
			
			setEvents : function (objTar, id) {
				var theme = enugene.menus.elements[id].theme;
				var type = enugene.menus.elements[id].type;
				switch (type) {
					default :
						if (enugene.DOM.util.isIe()) {
							objTar.style.cursor = 'hand';
							objTar.onmouseover = new Function( "enugene.DOM.eventHandler.mouse.menus.overMenu( this )" );
							objTar.onmouseout = new Function( "enugene.DOM.eventHandler.mouse.menus.menuOut( this )" );
						} else {
							objTar.style.cursor = 'pointer';
							objTar.onmouseover = function(){ enugene.DOM.eventHandler.mouse.menus.overMenu( this ); };
							objTar.onmouseout = function(){ enugene.DOM.eventHandler.mouse.menus.menuOut( this ); };
						}
					break;
				}
			},
			
			create : function(id) {
				var menu = this.getBox(id);
				this.setEvents( menu, id );
				return menu;
			},
			
			/**
			 * return the block or main frame for mainmenus or the sub frame for
			 * submenus
			 */
			getMenuFrame : function ( targetObject, id, positMode ) {
				var type = enugene.menus.elements[id].type;
				var theme = enugene.menus.elements[id].theme;
				if (type == 'main') {
					var menuFrame = enugene.DOM.constructor.util.getMainFrame( targetObject, id, theme, positMode );
				} else {
					var menuFrame = enugene.DOM.constructor.util.getSubFrame( targetObject, id, positMode );
				}
				return menuFrame;
			},
			
			/**
			 * Appends a new menu to the positioning menuFrame. Returns the created menu object
			 * to be filled with items.
			 */
			append : function (targetObject, id) {
				var modId = enugene.menus.elements[id].moduleId;
				var positMode = enugene.menus.menutypes[modId].positMode;
				// Menu frame is either the blockFrame or the free
				// floating mainFrame. They were appended to DOM by
				// their getters (throwMenu).
				var menuFrame = this.getMenuFrame( targetObject, id, positMode );
				// Hook the generated menu into the outer frame
				if (menuFrame) {
					var newObj = this.create( id );
					enugene.menus.elements[id].domObject = newObj;
					// To dynamic mode positioned menus menuFrame comes back as 
					// the menu block frame. - Else it is the extra 'floatingFrame' 
					// which again needs to be appended to the document. The 
					// blockFrame is part of the document since construction by PhP.
					if (menuFrame.id.split('_')[1] == 'blockFrame') {
						menuFrame.appendChild( newObj );
					} else {
						menuFrame.appendChild( newObj );
						targetObject.appendChild( menuFrame );
					}
				} else {
					var newObj = null;
				}
				return newObj;
			}
		},

		item : {
			name : 'item',
			parent : '',
			id : '',
			type : '',
			theme : '',
			orient : '',
			setImportant : '',
			positMode : '',
			// Create all items box including the className and background image
			getBox : function (id,theme) {
				var cssSelector = '';
				var type = enugene.menus.elements[id].type;
				var orient = enugene.themes[theme].menuOrientation;
				var bgImg = enugene.menus.elements[id].backgroundImage;
				
				// css className
				switch (type) {
					case 'separator' :
						// Since version 0.9.8.7 enugene has a content
						// management
						// for the images. With this manager triggered on, no
						// separator background image from jos_menus is taken
						// any more!
						if (enugene.globals.mgen_arrExtensions.ModContent && enugene.menus.elements[id].jos_menu_image) {
							var bgImg = enugene.menus.elements[id].jos_menu_image;
						}
						cssSelector = theme + 'Separator';
						this.wEL = enugene.themes[theme].iELwidth;
						this.hEL = enugene.themes[theme].iELheight;
					break;
					default :
						cssSelector = theme + 'MenuItem';
						// Get the inner Elem sizes - by set to zero they won't
						// be generated.
						// before 0.9.8.7 Separator had no such elems.
						this.wEL = enugene.themes[theme].iELwidth;
						this.hEL = enugene.themes[theme].iELheight;
						this.wER = enugene.themes[theme].iERwidth;
						this.hER = enugene.themes[theme].iERheight;
					break;
				}
				
				// Basic button container
				var newObj = document.createElement('div');
				newObj.id = id;
				newObj.className = cssSelector;
				newObj.theme = theme;
				newObj.topMenuId = enugene.menus.elements[id].topMenuId;
				newObj.myMenuId = enugene.menus.elements[id].myMenuId;
				if (this.positMode != 'accordion' && orient.charAt(0) == 'h') {
					enugene.DOM.util.set_Property(newObj, "float", "left", this.setImportant);
				} else { 
					enugene.DOM.util.set_Property(newObj, "float", "none", this.setImportant);
				}
				if (bgImg) {
					newObj.style.backgroundImage = 'url(' + bgImg + ')';
				}
				return newObj;
			},
			
			setElemL : function(targetObj, type, itemId) {
				if ((this.hEL + this.wEL) === 0) return '';
				var theme = enugene.menus.elements[itemId].theme;
				var newObj = document.createElement('div');
				newObj.id = itemId + 'L';
				newObj.className = theme + 'MenuItemL';
				newObj.theme = theme;
				newObj.parentId = enugene.menus.elements[itemId].id;
				targetObj.appendChild(newObj);
				return newObj;
			},
			
			setElemT : function(targetObj, type, itemId) {
				var theme = enugene.menus.elements[itemId].theme;
				var newObj = document.createElement('div');
				newObj.id = itemId + 'T';
				newObj.className = theme + 'MenuItemT';
				newObj.theme = theme;
				newObj.parentId = enugene.menus.elements[itemId].id;
				targetObj.appendChild(newObj);
				return newObj;
			},
			
			setElemR : function(targetObj, type, itemId) {
				if ((this.hER + this.wER) === 0) return '';
				var theme = enugene.menus.elements[itemId].theme;
				var newObj = document.createElement('div');
				newObj.id = itemId + 'R';
				newObj.className = theme + 'MenuItemR';
				newObj.theme = theme;
				newObj.parentId = enugene.menus.elements[itemId].id;
				targetObj.appendChild(newObj);
				return newObj;
			},

			setEvents : function (objTar, type, id) {
				var topMenuId = enugene.menus.elements[id].topMenuId;
				var myMenuId = enugene.menus.elements[id].myMenuId;
				var theme = enugene.menus.elements[id].theme;
				if (!enugene) return;
				switch (type) {
					case 'separator' :
						if (enugene.DOM.util.isIe()) {
							objTar.style.cursor = 'hand';
							objTar.onmouseover = new Function( "enugene.DOM.eventHandler.mouse.menus.overItem( this,'" + theme + "','" + topMenuId + "')" );
						} else {
							objTar.style.cursor = 'pointer';
							objTar.onmouseover = function(){ enugene.DOM.eventHandler.mouse.menus.overItem ( this, theme, topMenuId ); };
						}
					break;
					default :
						if (enugene.DOM.util.isIe()) {
							objTar.style.cursor = 'hand';
							objTar.onmouseover = new Function( "enugene.DOM.eventHandler.mouse.menus.overItem( this,'" + theme + "','" + topMenuId + "' )" );
							objTar.onmousedown = new Function( "enugene.DOM.eventHandler.mouse.menus.mouseDown( this,'" + theme + "','" + myMenuId + "' )" );
							objTar.onmouseup = new Function( "enugene.DOM.eventHandler.mouse.menus.mouseUpItem( this )" );
						} else {
							objTar.style.cursor = 'pointer';
							objTar.onmouseover = function(){ enugene.DOM.eventHandler.mouse.menus.overItem( this, theme, topMenuId ); };
							objTar.onmousedown = function(){ enugene.DOM.eventHandler.mouse.menus.mouseDown( this, theme, myMenuId ); };
							objTar.onmouseup = function(){ enugene.DOM.eventHandler.mouse.menus.mouseUpItem( this ); };
						}
					break;
				}
			},
			
			wrap_accordionFrame : function (newObj) {
				objAccordionFrame = document.createElement( 'div' );
				objAccordionFrame.id = this.id + '_accordionFrame';
				objAccordionFrame.appendChild( newObj );
				if (this.orient.charAt(0) == 'h') {
					enugene.DOM.util.set_Property( objAccordionFrame, "float", "left", this.setImportant );
				}
				return objAccordionFrame;
			},
			
			// create item
			create : function(id, type, theme) {
				var objItem = this.getBox( id, theme );
				this.setEvents( objItem, type, id );
				this.setElemL( objItem, type, id );
				this.setElemT( objItem, type, id );
				if (type != 'separator') {
					this.setElemR( objItem, type, id );
				}
				return objItem;
			},
			
			// append item
			append : function (targetObj, id, positMode) {
				this.positMode = positMode;
				this.id = id;
				this.type = enugene.menus.elements[id].type;
				this.theme = enugene.menus.elements[id].theme;
				this.orient = enugene.themes[this.theme].menuOrientation;
				this.setImportant = enugene.themes[this.theme].setImportant || '';
				
				var objAccordionFrame = null;
				var newObj = this.create( id, this.type, this.theme );
				
				newObj.myMenuId = targetObj.id;
				// Wrap the item into a accordion frame
				if (this.type != 'separator' && this.positMode == 'accordion') {
//					objAccordionFrame = this.wrap_accordionFrame( newObj );
					newObj = this.wrap_accordionFrame( newObj );
				}
				// set the first item as current
				if (!targetObj.currentItem) targetObj.currentItem = id;
				enugene.menus.elements[id].domObject = newObj;
				// Append the collected item to the menu
targetObj.appendChild( newObj );return;
				if (objAccordionFrame !== null)
					targetObj.appendChild( objAccordionFrame );
				else
					targetObj.appendChild( newObj );
			}
		},
		
		setBlockFrame : function (objMenutype) {
			var objBlockFrame = null;
			var id = objMenutype.mainMenuId;
			// In dynamic mode blockFrame is the target frame for the mainmenu;
			// else blockFrame only is neccessary to get or set the placeholder sizes.
			if (id) objBlockFrame = enugene.DOM.util.getObject( id + '_blockFrame' );
			// Assure the local objBlockFrame var is recent or empty. 
			if (objBlockFrame !== null) {
				this.objBlockFrame = objBlockFrame;
			} else {
				this.objBlockFrame = null;
			}
		},
		
		/**
		 * Create mainmenu (menutype) and the associated submenus.
		 * 
		 * The blockFrame:
		 * 
		 * The block frame is the general signal for the menu module is published or not!
		 * 
		 * Each menutype (mainmenu of the menu module) gets a block frame container. It 
		 * is sizeable by user set parameters.
		 * 
		 * Only if the module is published, the PHP injector throwMenu() replaces the 
		 * insertion mark for the menu with the JS starter command.
		 * 
		 * With this insertion, first the module mainmenu blockFrame is written.
		 * 
		 * In case the menus are positioned with the 'dynamic mode' the JS constructor 
		 * appends the menu objects into this fixed frame. The dynamic mode means that 
		 * all basic menu container positions are calculated by machine automatically. 
		 * 
		 * If the menus are positioned using user position preferences, the block frame 
		 * is not filled, but it is anyway created. To this case it may be used to create 
		 * some space at the document position where the mainmenu would be inserted.
		 * 
		 * The menu Frame:
		 * 
		 * In not 'dynamic positioning modes' the menu gets an additional frame by the 
		 * JS menu constructor. This frame is neccessary to set an independent CSS position 
		 * value to each menu (main and sub). This way it is shure to get a frame, which is 
		 * calculated to an 'absolute' document position.
		 */
		create : function (targetObj) {
			var objMenus = enugene.menus;
			var authItemsCount = 0;
			var mty = '';
			var mnu = '';
			var menu = '';
			var itemId = '';
			if (!targetObj) targetObj = document.body;
			
			for (mty in objMenus.menutypes) {
				enugene.DOM.constructor.setBlockFrame( objMenus.menutypes[mty] );
				if (!this.objBlockFrame) {
					continue;
				}
				
				objMenus.menutypes[mty]['published'] = true;
				for (mnu in objMenus.menutypes[mty].menus) {
					menu = objMenus.menutypes[mty].menus[mnu];
					menu.published = true;
					if (!menu) {
						continue;
					}
					var newMenu = this.menu.append( targetObj, menu.id );
					if (newMenu !== null) {
						authItemsCount = 0;
						for (itemId in menu.items) {
							// Only published items come back from the database - 
							// generally get_usermenu() does import the published flag.
							// But under certain circumstances the constructor may reach 
							// the setDomProperties() before the ajax get_usermenu() is 
							// finished. In such cases those wouldn't be processed and 
							// displayed. To assure displaying all published items this 
							// flag is set once again here.
							menu.items[itemId].published = true;
							if (enugene.menus.elements[itemId].userAuth) {
								++authItemsCount;
								this.item.append( newMenu, itemId, objMenus.menutypes[mty].positMode );
							}
						}
						// no item with a an authorized link for this menu?
						// - remove menu and its blockFrame from doc
						if (authItemsCount === 0) {
							var bF = enugene.DOM.util.getObject(menu.id + '_blockFrame');
							if (bF) {
								bF.parentNode.removeChild( bF );
							}
						}
					}
				}
			}
			this.init();
		},
		
		/**
		 * init menus after construction
		 */
		init : function () {
			var menuItem = '';
			var topMenuItem = '';
			var arrMnu = enugene.startup.menutypes;
			// user given topLevelItemId does not exist in elements?
			// menu not active - set the first menu from arrMnu active
			if (!enugene.menus.elements[enugene.menus.topLevelItemId]) {
				enugene.menus.topLevelMenuId = enugene.menus.menutypes[arrMnu[0]].mainMenuId;
				enugene.menus.topLevelItemId = enugene.menus.menutypes[arrMnu[0]].topItemId;
			}
			// registrate the loaded menutypes (mainmenus)
			for (var x = 0; x < arrMnu.length; x++) {
				// It may happen the arrMnu has an empty menutype. - skip it!
				// This case comes up if a new menu module was published and 
				// saved by the enu Preferences - but the frontend files were 
				// not updated. If this menutype is accounted here all program 
				// trough errors will appear.
				if (enugene.menus.menutypes[arrMnu[x]]) {
					enugene.menus.loadedMenus[x] = enugene.menus.menutypes[arrMnu[x]].mainMenuId;
				}
			}
			// when the document is loaded by a frontsite request
			// set the active menu item, or leave the startItem empty
			// if the document is loaded first time
			if (enugene.startup.startItemId) {
				// Start by Joomla default startItem '1' ? - replace it with the
				// enugene set one.
				if (enugene.startup.startItemId == 'mgenIt1') {
					// if item 1 does exist then take it anycase as startitem
					// else, if item 1 is pressed, enuGene would take the
					// toplevel
					// item even if it is not the the site first start.
					if (enugene.menus.elements['mgenIt1']) enugene.menus.topLevelItemId = 'mgenIt1';
					enugene.menus.activeItemId = enugene.menus.topLevelItemId;
					enugene.startup.startItemId = enugene.menus.topLevelItemId;
				} else {
					enugene.menus.activeItemId = enugene.startup.startItemId;
				}
			} else {
				enugene.menus.activeItemId = enugene.menus.topLevelItemId;
				enugene.startup.startItemId = enugene.menus.topLevelItemId;
			}
			// the document was required by enugene - get the mainmenu caller id
			var topItemId = enugene.menus.util.get_caller_ItemId( enugene.menus.activeItemId, 0 );
			// topItemId empty ? No menu with the activeItemId is active
			topItemId ? topMenuItem = enugene.menus.elements[topItemId] : topMenuItem = enugene.menus.elements[enugene.menus.activeItemId];
			if (topMenuItem) {
				// tell him which item to activate
				enugene.menus.activateMenuId = topMenuItem.topMenuId;
				enugene.menus.activateItemId = topItemId;
			} else {
				enugene.menus.activateMenuId = enugene.menus.topLevelMenuId;
				enugene.menus.activateItemId = enugene.menus.topLevelItemId;
				enugene.menus.activeItemId = enugene.menus.topLevelItemId;
			}
			enugene.menus.util.setItemCurrent(enugene.menus.activateMenuId, enugene.menus.activateItemId, '', '');
			enugene.DOM.properties.setDOMProperties( enugene.menus.elements, false );
		}
	};
	
	this.eventHandler = {
			
		mouse : {
		
		
			in_itemId : '',
			out_itemId : '',
			onMouseItemChange : '',
			
			/**
			 * This is the only reliable mouse event fork, noticing a mouse
			 * button change.
			 * 
			 * Because the mouseOverItem always fires if the mouse moves into
			 * and out of an item element, the mouseOverItem event happens many
			 * times, even if the mouse didn't leave the button container.
			 * 
			 * This function traces all mouseOverItem events, and only if the
			 * item id changes, it fires the onMouseItemChange event.
			 * 
			 * NOTICE: The menus.currentItem state is not the proper value for
			 * tracing the mouse button move, because the menus.currentItem is
			 * also set by the menu performer functions on hide or else.
			 */
			item_changed : function (overItem) {
				// If the recently touched button has changed
				// fire the loaded event function.
				if (this.in_itemId != overItem.id || this.in_itemId != enugene.menus.currentItem.id) {
					this.out_itemId = this.in_itemId;
					this.in_itemId = overItem.id;
					if (this.onMouseItemChange) {
						this.onMouseItemChange();
					}
					return true;
				}
				return false;
			},
		
		
			setInfo : function (obj, objType) {
				if (enugene.menus.elements[obj.id]) {
					var type = enugene.menus.elements[obj.id].type;
					var theme = enugene.menus.elements[obj.id].theme;
				} else {
					var type = null;
					var theme = null;
				}
				if (objType == 'item') {
					enugene.menus.info.item  = {
						'id' : obj.id,
						'width' : obj.offsetWidth,
						'height' : obj.offsetHeight,
						'theme' : theme,
						'type' : type
					};
				}
				if (objType == 'menu') {
					enugene.menus.info.menu  = {
						'id' : obj.id,
						'width' : obj.offsetWidth,
						'height' : obj.offsetHeight,
						'theme' : theme,
						'type' : type,
						'module' : enugene.menus.elements[obj.id].moduleId
					};
				}
			},
			menus : {
				/**
				 * @params string id
				 * @params object obj
				 * @return void
				 */
				mouseUpItem : function (obj) {
					var item = enugene.menus.elements[obj.id];
					var link = ''; 
					var target = '_self';
					
					var theme = enugene.menus.elements[obj.id].theme;
					if (!enugene.themes[theme].clickOpen) {
						link = item.link;
						target = item.target;
						if (link) {
							window.open (link, target);
						}
					}
				},

				/**
				 * This function is taken for mouse button down events upon a menu
				 * item
				 * 
				 * @param object obj
				 * @param string theme
				 * @return void
				 */
				mouseDown : function (obj, theme, menuId) {
					var item = enugene.menus.elements[obj.id];
					var hasSub = enugene.menus.elements[obj.id].child;
					var theme = enugene.menus.elements[obj.id].theme;
					var objActItem = enugene.menus.elements[obj.id];
					var actItemMenu = objActItem.getParentMenuObject();
					if (objActItem.child && enugene.themes[theme].clickOpen) {
						enugene.menus.perform.hide.childs( enugene.menus.currentMenu.menuObject );
						enugene.menus.perform.show.menu( obj, objActItem.child );
						enugene.DOM.properties.setDOMProperties( enugene.menus.updateList, false );
					}
					enugene.menus.activeItemId = obj.id
					// on clickOpen the link is executed onmousedown else onmouseup
					if (!hasSub && enugene.themes[theme].clickOpen) {
						link = item.link;
						target = item.target;
						if (link) {
							window.open (link, target);
						}
					}
				},

				/**
				 * This function is called when the mouse moves out of a menu
				 * 
				 * @param object obj
				 * @param integer delayTime
				 * @return void
				 */
				menuOut : function (obj) {
					var theme = enugene.menus.elements[obj.id].theme;
					var modId = enugene.menus.elements[obj.id].moduleId;
					if (enugene.menus.menutypes[modId].positMode == 'accordion') return false;
					var delayTime = enugene.themes[theme].delayMenuClose;
					enugene.globals.menuTimeout = window.setTimeout( "enugene.menus.perform.hide.timeout()", delayTime );
				},

				/**
				 * This function is called when the mouse moves out of a menu
				 * item
				 * 
				 * @return void
				 */
				overMenu : function (obj) {
					window.clearTimeout( enugene.globals.menuTimeout );
				},
				
				/**
				 * @param obj: the pressed menuitem
				 * @param theme: the global css selector theme
				 * @param orient: menu's orientation
				 * @return void
				 */
				overItem : function (obj, theme, topMenuId) {
					
					if (obj.parentNode.mgenEffects && obj.parentNode.mgenEffects.sliding)
						if (obj.parentNode.mgenEffects.sliding.active === true) return;
					
					enugene.DOM.eventHandler.mouse.setInfo( obj, 'item' );
					window.clearTimeout( enugene.globals.menuTimeout );
					
					// if no action item - leave after timeout
					if (enugene.menus.util.getAction(obj.id) != 'normal') return;

					var modId = '';
					var menuItem = enugene.menus.elements[obj.id];
					modId = menuItem.getParentMenuObject().moduleId;
					var menuObject = menuItem.getParentMenuObject();
					if (!menuObject) return;
					
					if(!enugene.DOM.eventHandler.mouse.item_changed( obj )) {
						// open menu if it has
						if (menuItem.child && !enugene.themes[menuItem.theme].clickOpen) {
							var objChild = enugene.DOM.util.getObject(menuItem.child );
							if (objChild && objChild.style.visibility == 'visible') return;
							enugene.menus.perform.show.menu ( obj, menuItem.child );
							// Execute to DOM - but currentItem stays the same
							enugene.DOM.properties.setDOMProperties( enugene.menus.updateList, true );
						}
						return;
					}
				
					var objMyMenu = enugene.menus.elements[obj.myMenuId];
					var noMenuChange = (obj.myMenuId == enugene.menus.currentMenu.id);
					
					// move within the same menu? - don't hide!
					if (noMenuChange) {
						if (!enugene.themes[menuItem.theme].clickOpen) {
							enugene.menus.perform.hide.childs(objMyMenu);
							if (menuItem.child) enugene.menus.perform.show.menu (obj, menuItem.child );
						}
					} else {
						if (modId && enugene.menus.menutypes[modId].positMode != 'accordion') {
							if (enugene.menus.currentItem.id && enugene.menus.util.isInMenuChain( enugene.menus.currentItem.id, obj.id )) {
								if (enugene.menus.currentMenu.id != menuItem.child) {
									enugene.menus.perform.hide.subs.levelDown(objMyMenu.topMenuId, objMyMenu.sublevel);
								}
							} else {
								enugene.menus.perform.hide.subs.all( );
							}
						}
					}
					// open menu if it has
					if (menuItem.child && !enugene.themes[menuItem.theme].clickOpen) {
						enugene.menus.perform.show.menu ( obj, menuItem.child );
					}
					
					enugene.menus.util.setItemCurrent(menuObject.id, obj.id, obj.className, '');
					enugene.DOM.properties.setDOMProperties( enugene.menus.updateList, true );
				}
			}
		}
	};
	this.constructor.parent = this;
	this.constructor.menu.parent = this.constructor;
	this.constructor.item.parent = this.constructor;
	this.parent = enugene;
} // end clsEnugeneDOM

// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////

function clsEnugeneKernel () {

	this.objects = {
		clsGlobals : function () {
			this.menuTimeout = null;
		},
		
		clsCurrentItem : function () {
			this.id = '';
			this.objtype = 'currentItem';
			this.theme = '';
			this.category = '';
			this.className = '';
			this.menuId = '';
			this.child = '';
			this.objChild = new Object();
			this.domObject = new Object();
		},
		
		clsSavedItem : function () {
			this.id = '';
			this.className = '';
			this.theme = '';
		},

		clsCurrentMenu : function () {
			this.id = '';
			this.menuObject = '';
			this.domObject = '';
		}
	};
	
	this.clsEnugeneUtil = function () {
		
		this.getAction = function (id) {
			var itemtype = enugene.menus.elements[id].itemtype
			switch (itemtype) {
				case 'component' :
					return 'normal';
				break;
				case 'separator' :
					return 'normal';
				break;
				default:
					return 'normal';
			}
		};
		
		/**
		 * @param string
		 *            menuId Id of the menu which item are to reset.
		 * @return void
		 */
		this.resetItemStyles = function (objMenu) {
			if (!objMenu) return;
			var menuItems = objMenu.items;
			if (objMenu.itemCount > 0) {
				var x;
				for (x in menuItems) {
					menuItems[x].domObject.className = menuItems[x].className;
				}
			}
		};
		
		this.setMenuCurrent = function (menuItem) {
			enugene.menus.currentMenu.id = menuItem.myMenuId;
			enugene.menus.currentMenu.menuObject = enugene.menus.elements[menuItem.myMenuId];
			enugene.menus.currentMenu.domObject = enugene.menus.elements[menuItem.myMenuId].domObject;
			enugene.DOM.eventHandler.mouse.setInfo( enugene.menus.elements[menuItem.myMenuId], 'menu' );
		};
		
		/**
		 * @param string 	menuId menu of the item to activate
		 * @param string 	itemId item which is to activate
		 * @param string 	className the style which is used when recovering the menuitem
		 * @param string 	hoverClassName is the css-style-classname which is used 
		 * 					when displaying the menuitem.
		 * @return void
		 */
		this.setItemCurrent = function (menuId, itemId, className, hoverClassName) {
			var menuItem = enugene.menus.elements[itemId];
			var menuObject = enugene.menus.elements[menuId];
			if (enugene.menus.currentItem.id) var currentItemId = enugene.menus.currentItem.id;
			else var currentItemId = itemId;
			var currentItem = enugene.menus.elements[currentItemId];
			var theme = menuObject.theme;

			if (!hoverClassName) hoverClassName = theme + 'MenuItem_Hover';
			if (!className) className = theme + 'MenuItem' ;
			
			// Reset item: menus not used before? Or not the same theme? - no
			// reset to previous.
			if (enugene.menus.savedItem.id) {
				if (enugene.menus.savedItem.theme == menuObject.theme) {
					enugene.menus.currentItem.menuObject.style.className = enugene.menus.savedItem.className;
					enugene.menus.updateList[enugene.menus.currentItem.id] = enugene.menus.elements[enugene.menus.currentItem.id];
				} else {
					// but reset to saved item's theme normal className
					enugene.menus.currentItem.menuObject.style.className = enugene.menus.savedItem.theme + 'MenuItem' ;
					enugene.menus.updateList[enugene.menus.savedItem.id] = enugene.menus.elements[enugene.menus.savedItem.id];
				}
			}

			// set item
			if (menuItem) {
				// separators are not activated - but their menu.
				if (menuItem.itemtype == 'separator') {
//					if (menuObject) this.setMenuCurrent( menuObject );
					if (menuObject) this.setMenuCurrent( menuItem );
					return;
				}
				
				enugene.menus.savedItem.id = menuItem.id;
				enugene.menus.savedItem.className = menuItem.className;
				enugene.menus.savedItem.theme = menuItem.theme;
		
				// Change the item objects class name and put it on execution
				// stack
				// to update the DOM element.
				menuItem.style.className = hoverClassName;
				enugene.menus.updateList[menuItem.id] = enugene.menus.elements[menuItem.id];

				// set the recent item as current one
				enugene.menus.currentItem.id = itemId;
				enugene.menus.currentItem.theme = theme;
				enugene.menus.currentItem.className = menuItem.className;
				enugene.menus.currentItem.menuId = menuObject.id;
				enugene.menus.currentItem.child = menuItem.child;
				enugene.menus.currentItem.objChild = enugene.menus.elements[menuItem.child];
				enugene.menus.currentItem.domObject = menuItem.domObject;
				enugene.menus.currentItem.menuObject = enugene.menus.elements[itemId];
			}
		
			if (menuObject) {
//				this.setMenuCurrent(menuObject);
				this.setMenuCurrent( menuItem );
			}
		};
		
		/**
		 * @param string
		 *            menuId: id of the current menu
		 * @return string
		 */
		this.get_caller_ItemId = function (itemId, sublevel) {
			var parentItemId = '';
			// find the caller item
			if (enugene.menus.elements[itemId])
				var menuObject = enugene.menus.elements[enugene.menus.elements[itemId].myMenuId];
			else
				return '';
			do {
				parentItemId = enugene.menus.elements[itemId].parentItemId;
				if (parentItemId == "mgenIt" + '0') return enugene.menus.elements[itemId].id;
				itemId = parentItemId;
			} while (menuObject.parentItemId != "mgenIt" + '0' || menuObject.sublevel <= sublevel);
			return itemId;
		};
		
		/**
		 * lastItemId
		 * @param actItemId string the id of the pressed menuitem
		 * @param lastItemId string the id of the just left menuitem
		 * @return boolean if the given itemId is in chain true else false
		 */
		this.isInMenuChain = function (currentItemId, actItemId) {
			var callerId = false;
			var inChain = false;
			var lastItem = enugene.menus.elements[currentItemId];
			var actItem = enugene.menus.elements[actItemId];
			if (lastItem.getTopItemId() == actItem.getTopItemId()) return true;
			return false;
		};
		
		/**
		 * Returns the id level menu item which leads the chain to the current
		 * menu
		 * 
		 * @param string
		 *            itemId
		 * @return string
		 */
		this.getItem_inChain = function (itemId, level) {
			var item = '';
			var menu = '';
			var topItemId = '';
			if (itemId && itemId !== 0) {
				item = enugene.menus.elements[itemId];
				menu = enugene.menus.elements[item.myMenuId];
				if (menu.sublevel === 0) return item.id;
				if (menu.starterChain) { 
					topItemId = menu.starterChain.split(';')[level];
				} else {
					topItemId = item.getTopItemId();
				}
			} else {
				topItemId = 0;
			}
			return topItemId;
		};
		
	}; // clsEnugeneUtil
	
	this.clsEnugenePerformer = function (parent) {
		this.parent = parent;
		this.show = {
			/**
			 * @param object obj the menu item DOM object that opens up the subMenu
			 * @param string idSub the id of the sub menu to be shown
			 * @return object
			 */
			menu : function (obj, idSub) {
				var objSubMenu = enugene.menus.elements[idSub];
				if (objSubMenu.domObject.style.visibility == 'visible') return;
				objSubMenu.starterChain = objSubMenu.starterChain + obj.id + ';';
				objSubMenu.visibility = 'visible';
				enugene.menus.updateList[idSub] = enugene.menus.elements[idSub];
				return objSubMenu;
			}
		};
		
		this.hide = {
			parent : '',
			/**
			 * Hides all submenus on menuOut event if timeout is reached. For
			 * instant closure mouseOverItem() is responsible.
			 * 
			 * @return void
			 */
			timeout : function () {
				var currentMenu;
				currentMenu = enugene.menus.currentMenu.menuObject;
				var objTopMenu = enugene.menus.elements[currentMenu.topMenuId];
				enugene.menus.activateMenuId = objTopMenu.id;
				var parentItemId = currentMenu.parentItemId;
				var topCallerId = enugene.menus.util.getItem_inChain(enugene.menus.currentItem.id, 0 );
				this.subs.all( );
				var menuId = enugene.menus.elements[enugene.menus.activeItemId].myMenuId;
				this.parent.parent.util.resetItemStyles( objTopMenu );
				if (objTopMenu.items[enugene.menus.activeItemId]) {
					// button pressed - set anycase
					enugene.menus.activateItemId = enugene.menus.activeItemId;
					enugene.menus.activateMenuId = menuId;
				} else {
					// REDIRECTION to topmenu - only once
					if (!enugene.menus.activateItemId) enugene.menus.activateItemId = topCallerId;
					enugene.menus.activateMenuId = enugene.menus.elements[enugene.menus.activateItemId].myMenuId;
				}
				enugene.menus.util.setItemCurrent(enugene.menus.activateMenuId, enugene.menus.activateItemId, '', '');
				enugene.DOM.properties.setDOMProperties( enugene.menus.updateList, false );
			},
			
			/**
			 * Hides a single menu. objMenu is the enugene.menus object of the
			 * menu to be hidden
			 * 
			 * @param object
			 *            objMenu
			 * @return void
			 */
			menu : function (objMenu) {
				// is mainmenu?
				if (objMenu.topMenuId == objMenu.id) 
					return;
				// Don't close the toplevel menu
				if (objMenu.sublevel === 0) 
					return;
				objMenu.visibility = 'hidden';
				this.childs( objMenu );
				objMenu.starterChain = '';
				if (objMenu.domObject.style && objMenu.domObject.style.visibility == 'visible') {
					this.parent.parent.util.resetItemStyles( objMenu );
					enugene.menus.updateList[objMenu.id] = enugene.menus.elements[objMenu.id];
				}
			},
			
			/**
			 * Hide all my child menus
			 * 
			 * @param object
			 *            objMenu
			 * @return void
			 */
			childs : function (objMenu) {
				var x;
				var id = '';
				for (x in objMenu.items) {
					if (objMenu.items[x].child) {
						id = objMenu.items[x].child;
						this.menu(enugene.menus.elements[id]);
					}
				}
			},
			
			subs : {
				parent : '',
				/**
				 * Hide all submenus
				 * 
				 * @param string all
				 * @return void
				 */			
				all : function () {
					var id;
					var isMenu = false;
					var isSub = false;
					for (id in enugene.menus.elements) {
						isMenu = (enugene.menus.elements[id].objtype == 'menu');
						isSub = (enugene.menus.elements[id].type == 'sub');
						if (isMenu && isSub) {
							this.parent.menu( enugene.menus.elements[id] );
						}
					}
				},
				
				/**
				 * Hide all menu with a higher sublevel number
				 * 
				 * @param string
				 *            mainmenuId
				 * @param integer
				 *            sublevel
				 * @return void
				 */
				levelDown : function (mainmenuId, sublevel) {
					var x;
					var id = '';
					for (x in enugene.menus.elements) {
						sbl = enugene.menus.elements[x].sublevel;
						id = enugene.menus.elements[x].topMenuId;
						if (id == mainmenuId && sbl > sublevel) {
							this.parent.menu( enugene.menus.elements[x] );
						}
					}
				}
			}, // subs
			
			items : {
				set_transparent : function (menuItems, arg) {
					switch (arg) {
					case 'box' :
						for (var x in menuItems) {
							var setImportant = enugene.themes[menuItems[x].theme].setImportant || 'important';
							enugene.DOM.util.set_Property(menuItems[x].domObject, "background-color", "transparent", setImportant);
							enugene.DOM.util.set_Property(menuItems[x].domObject, "border-color", "transparent", setImportant);
						}
						break;
					case 'background' :
						for (var x in menuItems) {
							var setImportant = enugene.themes[menuItems[x].theme].setImportant || 'important';
							enugene.DOM.util.set_Property(menuItems[x].domObject, "background-color", "transparent", setImportant);
						}
						break;
					case 'all' : 
						for (var x in menuItems) {
							var setImportant = enugene.themes[menuItems[x].theme].setImportant || 'important';
							enugene.DOM.util.set_Property(menuItems[x].domObject, "visibility", "hidden", setImportant);
						}
						break;
					default :
					}
				}
			}
		}; // hide
		this.hide.subs.parent = this.hide;
		this.hide.parent = this;
	}; // clsEnugenePerformer
} // clsEnugeneKernel



// //////////////////////////////////////////////////////////////////////////////////////////////
// ///////////////////////FRONTEND RULER AND OBJECT IDENTIFICATION
// TOOL//////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////

/**
 * the mouse ruler class
 */
function clsMgenRuler () {
	this.drag = {
		posX : 0,
		posY : 0,
		startX : 0,
		startY : 0,
		mm_event : null,
		object : null
	};
	
	/**
	 * The event handler for mouse position registration. If set, the mouse
	 * sensitive info element starts working. (Set by Preferences form)
	 * 
	 * @return void
	 */
	this.startMouseMoveHandler = function () {
		switch (enugene.globals.mgen_showCursorPosition) {
		case 'no' :
			document.onmousemove = '';
			break;
		case 'administrator' :
			if (enugene.startup.usertype.toLowerCase().search( 'admin' ) != -1) {
				this.infoFrame.create();
				document.onmousemove = this.get_mousePosition;
			}
			break;
		case 'all' :
			this.infoFrame.create();
			document.onmousemove = this.get_mousePosition;
			break;
		default :
			document.onmousemove = '';
		}
	};
	
	/**
	 * - Calculates the mouse cursor position and writes it to the info
	 * container. - Calls the menu details infos and writes them to the info
	 * container. - Feeds the cursor position coordinates to the ruler .
	 * 
	 * @return void
	 */
	this.get_mousePosition = function (mm_event) {
		var innerHTML = '';
		var me = enugene.tools.ruler;
		var objCursorInfoFrame = enugene.DOM.util.getObject('mousePos_frame');
		if (!objCursorInfoFrame) return;
	
		me.drag.mm_event = mm_event;
		me.drag.posX = document.all ? window.event.clientX + document.documentElement.scrollLeft : mm_event.pageX;
		me.drag.posY = document.all ? window.event.clientY + document.documentElement.scrollTop : mm_event.pageY;
		
		if (me.drag.object) {
		    me.drag.object.style.left = (me.drag.posX - me.drag.startX) + "px";
	    	me.drag.object.style.top = (me.drag.posY - me.drag.startY) + "px";
	    }
	
		// set ruler position
		me.ruler.set_position( me );
		
		// display the cursor position in the infoFrame
		objCursorInfoFrame.style.textAlign = 'left';
		innerHTML += '<div style="background-color:#aaa;font-size:12px;padding:0px 3px 0px 3px;margin-bottom:3px;">' + me.drag.posX + ',' + me.drag.posY + '</div>';
		innerHTML += me.infoFrame.displayExtended( objCursorInfoFrame );
		objCursorInfoFrame.innerHTML = innerHTML;
	};
	
	this.ruler = {
		// Interface for controlling the ruler actions and state
		parent : '',
		objRulerH : '',
		objRulerV : '',
		objRulerC : '',
		state: 'hold',
		originX : 0,
		originY : 0,
		dX : 0,
		dY : 0,
		
		activate : function () {
			if (this.parent.infoFrame.objCursorInfoFrame.ruler_display === true) {
				this.parent.infoFrame.objCursorInfoFrame.ruler_display = false;
				img = enugene.globals.imagePath_default + 'inactiveRulerSymbol.png';
				this.remove( );
			} else {
				this.parent.infoFrame.objCursorInfoFrame.ruler_display = true;
				img = enugene.globals.imagePath_default + 'activeRulerSymbol.png';
				this.create( );
			}
		},
		
		/**
		 * Switches the ruler actcion state
		 * 
		 * @return void
		 */ 
		clickRuler : function () {
			var me = enugene.tools.ruler.ruler;
			var objElem = enugene.DOM.util.getObject('originRuler_center');
			if (this.state == 'move') {
				this.state = 'hold';
				me.state = 'hold';
			} else {
				this.state = 'move';
				me.state = 'move';
			}
		},
	
		move : function () {
			this.objRulerH.style.width = document.body.offsetWidth + 'px';
			this.objRulerH.style.top = this.originY + 'px';
			this.objRulerV.style.left = this.originX + 'px';
			this.objRulerC.style.left = this.originX - 20 + 'px';
			this.objRulerC.style.top = this.originY - 20 + 'px';
		},
		
		/**
		 * Calculates the ruler absolute and relative positions and displays the
		 * relative position values.
		 */
		set_position : function () {
			if (this.parent.infoFrame.objCursorInfoFrame.ruler_display) {
				this.dX = this.parent.drag.posX - this.originX;
				this.dY = this.parent.drag.posY - this.originY;
				if (this.state == 'move') {
					this.originX = this.parent.drag.posX;
					this.originY = this.parent.drag.posY;
					this.move();
				}
				// display relative distance beside the ruler center
				if (this.objRulerC) {
					this.objRulerC.childNodes[0].innerHTML = this.dX + ',' + this.dY;
				}
			}
		},

		/**
		 * Remove the ruler cross elements from display
		 */
		remove : function () {
			var objElem = enugene.DOM.util.getObject('originRuler_horizontal');
			if (!objElem) return;
			document.body.removeChild(objElem);
			objElem = enugene.DOM.util.getObject('originRuler_vertical');
			document.body.removeChild(objElem);
			objElem = enugene.DOM.util.getObject('originRuler_center');
			document.body.removeChild(objElem);
		},

		/**
		 * Create and append the ruler elements to the DOM
		 */
		create : function () {
			this.originX = document.body.offsetWidth / 2;
			this.originY = screen.height / 2;
			var newObj = document.createElement('div');
			newObj.id = 'originRuler_vertical';
			newObj.style.width = '1px';
			newObj.style.height = document.body.offsetHeight + 'px';
			newObj.style.borderLeft = '1px solid #000';
			newObj.style.position = 'absolute';
			newObj.style.zIndex = '100';
			newObj.style.top = '0px';
			newObj.style.left = this.originX + 'px';
			document.body.appendChild(newObj);
			this.objRulerV = newObj;
			
			newObj = document.createElement('div');
			newObj.id = 'originRuler_horizontal';
			newObj.style.height = '1px';
			newObj.style.width = document.body.offsetWidth + 'px';
			newObj.style.borderTop = '1px solid #000';
			newObj.style.position = 'absolute';
			newObj.style.zIndex = '100';
			newObj.style.left = '0px';
			newObj.style.top = this.originY + 'px';
			document.body.appendChild(newObj);
			this.objRulerH = newObj;
			
			newObj = document.createElement('div');
			newObj.id = 'originRuler_center';
			newObj.style.height = '40px';
			newObj.style.width = '40px';
			newObj.style.border = '1px solid #000';
			newObj.style.position = 'absolute';
			newObj.style.zIndex = '100';
			newObj.style.left = this.originX - 20 + 'px';
			newObj.style.top = this.originY - 20 + 'px';
			newObj.state = 'hold';
			this.state = 'hold';
		
			if (enugene.DOM.util.isIe( )) {
				newObj.onclick = new Function("return enugene.tools.ruler.ruler.clickRuler()");
			} else {
				newObj.onclick = enugene.tools.ruler.ruler.clickRuler;
			}
		
			newObj.style.backgroundImage = 'url(' + enugene.globals.imagePath_default + 'white_transparent.png' + ')';
			document.body.appendChild(newObj);
			this.objRulerC = enugene.DOM.util.getObject('originRuler_center');
			
			newObj = document.createElement('span');
			newObj.id = 'ruler_statusDisplay';
			newObj.style.fontSize = '12px';
			newObj.style.clear = 'left';
			newObj.style.position = 'relative';
			newObj.style.whiteSpace = 'nowrap';
			newObj.style.left = '45px';
			newObj.style.width = '20px';
			newObj.style.paddingLeft = '5px';
			newObj.style.paddingRight = '5px';
			newObj.style.backgroundColor = 'rgb(255,255,255)';
			this.objRulerC.appendChild(newObj);
		}
	}
	
	this.infoFrame = {
		/**
		 * objCursorInfoFrame: Is the DOM object ref to the info frame. it gets
		 * additional params: - .ruler_display - .displayIds
		 */
		parent : '',
		objCursorInfoFrame : '',
		posX : 0,
		posY : 0,
		
		/**
		 * Is associated to the objects mousedown eventhandler. Notice: mouse
		 * move management is controlled by ruler.get_mousePosition()
		 * 
		 * @param string
		 */
		activate : function (obj) {
			var me = enugene.tools.ruler.infoFrame;
			me.parent.drag.object = obj;
			me.parent.drag.startX = me.parent.drag.posX - me.parent.drag.object.offsetLeft;
			me.parent.drag.startY = me.parent.drag.posY - me.parent.drag.object.offsetTop;
		},
		
		/**
		 * Is associated to the objects mouseup eventhandler. Notice: mouse move
		 * management is controlled by ruler.get_mousePosition()
		 * 
		 * @param string
		 */
		deactivate : function (mm_event) {
			var me = enugene.tools.ruler.infoFrame;
			me.parent.drag.object.style.left = (me.parent.drag.posX - me.parent.drag.startX) + "px";
			me.parent.drag.object.style.top = (me.parent.drag.posY - me.parent.drag.startY) + "px";
			me.parent.drag.object = null;
		},
		
		/**
		 * mouse cursor position
		 */
		addButton : function (margin, obj) {
			var strReturn = '';
			var img = enugene.globals.imagePath_default + 'addSymbol.png';
			if (margin)
				margin = 'margin:' + margin + ';';
			else
				margin = '';
			if (!obj.displayIds)
				img = enugene.globals.imagePath_default + 'addSymbol.png';
			else
				img = enugene.globals.imagePath_default + 'minusSymbol.png';
			strReturn += '<div style="' + margin + 'width:13px;height:14px;display:inline;" onclick="enugene.tools.ruler.infoFrame.displayBasic()">';
			strReturn += '<img alt="" border="0" title="" src="' + img + '" width="14px" height="14px" />';
			strReturn += '</div>';
			return strReturn;
		},
		
		/**
		 * ruler activate button
		 */
		rulerButton : function (margin, obj) {
			if (!obj.displayIds) return '';
			var strReturn = '';
			var img = enugene.globals.imagePath_default + 'inactiveRulerSymbol.png';
			if (margin)
				margin = 'margin:' + margin + ';';
			else
				margin = '';
			if (!obj.ruler_display)
				img = enugene.globals.imagePath_default + 'inactiveRulerSymbol.png';
			else
				img = enugene.globals.imagePath_default + 'activeRulerSymbol.png';
			strReturn += '<div style="' + margin + 'width:13px;height:14px;display:inline;" onclick="enugene.tools.ruler.ruler.activate()">';
			strReturn += '<img alt="" border="0" title="" src="' + img + '" width="14px" height="14px" />';
			strReturn += '</div>';
			return strReturn;
		},
		
		/**
		 * Set the info container to default left position
		 */
		leftButton : function () {
			var strReturn = '';
			var img = enugene.globals.imagePath_default + 'arrow_boxedGreyLeft_15px.png';
			strReturn += '<div style="width:13px;height:14px;display:inline;">';
			strReturn += '<img alt="" border="0" title="" src="' + img + '" width="14px" height="14px" />';
			strReturn += '</div>';
			return strReturn;
		},
		
		/**
		 * Set the info container to right position
		 */
		rightButton : function () {
			var strReturn = '';
			var img = enugene.globals.imagePath_default + 'arrow_boxedGreyRight_15px.png';
			strReturn += '<div style="width:13px;height:14px;display:inline;">';
			strReturn += '<img alt="" border="0" title="" src="' + img + '" width="14px" height="14px" />';
			strReturn += '</div>';
			return strReturn;
		},
	
		/**
		 * Switch the flag to display the menu info details
		 * 
		 * @return void
		 */
		displayBasic : function (mm_event) {
			var objCursorInfoFrame = enugene.DOM.util.getObject('mousePos_frame');
			var innerHTML = '<div style="background-color:#aaa;font-size:12px;padding:0 3px 0 3px;margin-bottom:3px;">' + this.parent.drag.posX + ',' + this.parent.drag.posY + '</div>';
			if (objCursorInfoFrame && objCursorInfoFrame.displayIds) {
				// close options
				objCursorInfoFrame.ruler_display = false;
				objCursorInfoFrame.displayIds = false;
				innerHTML += '<div style="clear:left;"></div>'
				innerHTML += '<div style="text-align:center;width:56px;height:16px;margin:0px auto;">';
				innerHTML += this.leftButton();
				innerHTML += this.addButton( '0px auto', objCursorInfoFrame );
				innerHTML += this.rulerButton( '0px auto', objCursorInfoFrame );
				innerHTML += this.rightButton();
				innerHTML += '</div>';
				this.parent.ruler.remove( );
			} else {
				objCursorInfoFrame.displayIds = true;
				enugene.menus.info.menu = {};
				enugene.menus.info.item = {};
				innerHTML += this.displayExtended( objCursorInfoFrame );
			}
			objCursorInfoFrame.innerHTML = innerHTML;
		},
		
		/**
		 * Writes the mouse position and menu infos to the cursor info container
		 * 
		 * @return string
		 */
		displayExtended : function (obj) {
		
			var innerHTML = '';
			innerHTML += '<div style="clear:left"></div>'
			innerHTML += '<div style="text-align:center;width:56px;height:16px;margin:0px auto;">';
			innerHTML += this.leftButton();
			innerHTML += this.addButton( '0px auto', obj );
			innerHTML += this.rulerButton( '0px auto', obj );
			innerHTML += this.rightButton();
			innerHTML += '</div>';
		
			var strClass = 'margin-bottom:5px;';
			if (obj.displayIds) {
				innerHTML += '<div style="background-color:transparent;font-size:12px;padding-left:5px;clear:left" id="mm_statusDisplay">';
				if (enugene.menus.info && enugene.menus.info.item.id) {
					innerHTML += 'Item';
					innerHTML += '<div style="padding-left:8px;">Id:' + enugene.menus.info.item.id + '</div>';
					if (enugene.menus.info.item.width) {
						innerHTML += '<div style="padding-left:8px;">width:' + enugene.menus.info.item.width + '</div>';
						innerHTML += '<div style="padding-left:8px;">height:' + enugene.menus.info.item.height + '</div>';
						innerHTML += '<div style="padding-left:8px;">type:&nbsp;' + enugene.menus.info.item.type + '</div>';

					}
				}
				if (enugene.menus.info.menu && enugene.menus.info.menu.id) {
					innerHTML += 'Menu';
					innerHTML += '<div style="padding-left:8px;">Id:&nbsp;' + enugene.menus.info.menu.id + '</div>';
					if (enugene.menus.currentMenu.domObject) {
						innerHTML += '<div style="padding-left:8px;">width:' + enugene.menus.info.menu.width + '</div>';
						innerHTML += '<div style="padding-left:8px;">height:' + enugene.menus.info.menu.height + '</div>';
					}
				}
				if (enugene.menus.info.menu && enugene.menus.info.menu.theme) {
					innerHTML += 'Theme';
					innerHTML += '<div style="padding-left:8px;">Id:&nbsp;' + enugene.menus.info.menu.theme + '</div>';
				}
				if (enugene.menus.info.menu && enugene.menus.info.menu.module) {
					innerHTML += 'Module';
					innerHTML += '<div style="padding-left:8px;">Id:&nbsp;' + enugene.menus.info.menu.module + '</div>';
				}
				innerHTML += '</div>';
			}
			return innerHTML;
		},
		
		/**
		 * Set the position coodinates to the cursor and menu info container
		 * object reference.
		 */
		position_infoframe : function ($position) {
			if ($position == 'left') {
				this.posX = 0;
				this.objCursorInfoFrame.style.left = this.posX + 'px';
			} else {
				this.posX = this.posX + 200;
				this.objCursorInfoFrame.style.left = this.posX + 'px';
			}
		},
	
		/**
		 * Append mouse cursor info container to the document.
		 */

		create : function () {
			var newObj = document.createElement('div');
			newObj.id = 'mousePos_frame';
			newObj.style.width = '100px';
			newObj.style.height = 'auto';
			newObj.style.border= '1px solid transparent';
			newObj.style.padding= '5px';
			newObj.style.position = 'absolute';
			newObj.style.top = this.posY + 'px';
			newObj.style.left = this.posX + 'px';
			newObj.style.cursor = 'pointer';
			newObj.style.zIndex = '100';
			newObj.style.backgroundImage = 'url(' + enugene.globals.imagePath_default + 'white_transparent.png' + ')';
			newObj.displayIds = false;
			newObj.ruler_display = false;
			if (document.all) {
				newObj.onmouseup = new Function( "enugene.tools.ruler.infoFrame.deactivate()" );
				newObj.onmousedown = new Function( "enugene.tools.ruler.infoFrame.activate(this)" );
			} else {
				newObj.onmouseup = enugene.tools.ruler.infoFrame.deactivate;
				newObj.onmousedown = function () { enugene.tools.ruler.infoFrame.activate(this); };
			}
			document.body.appendChild(newObj);
			this.objCursorInfoFrame  = newObj;
		}

	}; // infoFrame
	this.infoFrame.parent = this;
	this.ruler.parent = this;
} // clsMgenRuler

// //////////////////////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////// EXTENSIONS
// //////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////

function clsMgenMenuProperties (parent) {
	this.parent = parent;
	
	/**
	 * Creates the content of the inner item elements to the left and right of
	 * the text element.
	 * 
	 * @param object objItem
	 * @param object elemObjRef
	 * @param string img
	 * @param string width
	 * @param string height
	 */
	this.append_imgElemContent = function ( objItem, elemObjRef, img, width, height ) {
		var newSpan = document.createElement('span');
		var newObj= document.createElement('img');
		img = img ? img : img = '';
		newObj.id = elemObjRef.id + 'img';
		newObj.style.width = width + 'px';
		newObj.style.height = height + 'px';
		newObj.style.border = '0px solid transparent';
		newObj.style.zIndex = '100';
		newObj.src = img;
		newSpan.appendChild(newObj);
		elemObjRef.appendChild(newSpan);
	};
	
	this.create_textElem_textContent = function (objItem, elemObjRef) {
		var text = '';
		var itemId = objItem.id;
		var theme = objItem.theme;
		var bdo = 'ltr';
		text = enugene.menus.elements[itemId].elemT;
		if (text === undefined) text = '';
		if (enugene.themes[theme].bdodir == 'rtl') {
			bdo = 'rtl';
		}
		if (elemObjRef.childNodes.length === 0 ){
			var newSpan = document.createElement('span');
			var newBdo = document.createElement('bdo');
			var newTextNode = document.createTextNode(text);
			newBdo.dir = bdo;
			newBdo.appendChild(newTextNode);
			newSpan.style.zIndex = '100';
			newSpan.appendChild(newBdo);
			elemObjRef.appendChild(newSpan);
		} else {
			elemObjRef.childNodes[0].childNodes[0].childNodes[0].nodeValue = text;
		}
	};

	/**
	 * All inner elements have to be included by a <span> for align them
	 * centered!
	 */
	this.getTextElem = function (objItem, elemObjRef) {
		
		if (enugene.menus.elements[objItem.id].itemtype == 'separator') 
			var texttype = enugene.menus.elements[objItem.id].texttype;
		else
			var texttype = 'text';
		if (texttype == 'text') {
			// load from js_vars.elemT property
			this.create_textElem_textContent( objItem, elemObjRef );
		}
		
		// Assign textcode as innerHTML to the item text <div>
		// contaíner leaving out all <bdo> and <span> elements.
		// Code content is always loaded by xmlhttpRequest and assigned
		// there into the text container.
		if (texttype == 'code') {
			// load each item text from the menus.elements
			if (elemObjRef && objItem){
				elemObjRef.innerHTML = objItem.elemT;
			}
		}
	};
	
	/**
	 * @param object objItem
	 * @param object elemObjRef
	 * @param string width
	 * @param string height
	 * @param string state
	 * @param string itemPos
	 */
	this.getImgElem = function (objItem, elemObjRef, state, width, height, itemPos) {
		var strReturn = '';
		var img = '';
		var itemId = objItem.id;
		var theme = objItem.theme;
		if (isNaN( parseInt(width) )) width = 0;
		if (isNaN( parseInt(height) )) height = 0;
		if (width === 0 && height === 0) return '';
		// the case user set one size zero to make the
		// elem unvisible for a distinct state
		if (width === 0 || height === 0) 
			elemObjRef.style.display = 'none';
		else
			elemObjRef.style.display = 'block';
		if (enugene.menus.elements[itemId]) {
			if (state) {
				img = enugene.menus.elements[itemId][ 'elem' + itemPos + '_Hover'] || enugene.themes[objItem.theme][ 'itemImg' + itemPos + '_Hover'];
			} else {
				img = enugene.menus.elements[itemId][ 'elem' + itemPos] || enugene.themes[objItem.theme][ 'itemImg' + itemPos];
			}
		}
		if (!img) {
			return '';
		} else {
			if (elemObjRef.childNodes.length === 0 || !enugene.DOM.util.getObject(itemId + itemPos + 'img')){
				this.append_imgElemContent( objItem, elemObjRef, img, width, height );
			} else {
				elemObjRef.childNodes[0].childNodes[0].style.width = width + 'px';
				elemObjRef.childNodes[0].childNodes[0].style.height = height  + 'px';
				elemObjRef.childNodes[0].childNodes[0].src = img;
			}
		}
	};
	
	/**
	 * The elemT always gets the text content, defined by joomla as item 'name'
	 * in the jos_menu table. The text comes over
	 * MgenMenuConstructor->appendItemElem() directly into the elemT property.
	 * 
	 * The application icon comes from jos_menu table, where it is defined as
	 * the 'menu_image' parameter. The image comes over
	 * MgenTblMenus->create_array_profile() - pack_items() to the enugene_menus
	 * table. It is noticed to there as item content param. From there it
	 * travels over MgenMenuConstructor->parseItems() as 'jos_menu_image' into
	 * the enugene.menus[menu]items object cluster. This way each item can
	 * access the image defined by the joomla menu manager.
	 * 
	 * Image priorities: First the joomla defined menu_image is taken. Then the
	 * theme wide enugene images are used - if a folderimage is declared it will
	 * be prefered to all other images. - If the image container size is set to
	 * zero the container won't be constructed.
	 * 
	 * @param objItem:
	 *            the enugene.menus object of the menuitem
	 * @param state:
	 *            string '_Hover' or empty controling the style at mouseover
	 * @return void
	 */
	this.set_itemElems = function (objItem, objRef, state ) {
		var elemObjRef = '';
		var orient = '';
		var width = '';
		var height = '';
		var innerHtml = '';
		var objItemWidth = '';
		
		var menu = objItem.getParentMenuObject();
		if (menu) objItemWidth = enugene.themes[menu.theme].mIwidth;
		
		if (state) { 
			state = '_Hover';
		} else {
			state = '';
		}
		
		if (objRef.childNodes.length === 0) return;

		var objElemL = false;
		var objElemT = false;
		var objElemR = false;
		
		var x = 0;
		
		if (objRef.childNodes[x].id.charAt(objRef.childNodes[x].id.length -1) == 'L') {
			var objElemL = objRef.childNodes[x];
			++x;
		}
		if (objRef.childNodes[x].id.charAt(objRef.childNodes[x].id.length -1) == 'T') {
			var objElemT = objRef.childNodes[x];
			++x;
		}
		if (objRef.childNodes.length > 1) {
			x = objRef.childNodes.length - 1;
			if (objRef.childNodes[x].id.charAt(objRef.childNodes[x].id.length -1) == 'R') {
				var objElemR = objRef.childNodes[x];
			}
		}
		
		if (!objElemL && !objElemT && !objElemR) return false;
			
		// Left item element
		elemObjRef = objElemL;
		if (elemObjRef) {
			// no hover size animation to separators
			if (objItem.type != 'separator') {
				elemObjRef.className = objItem.className + 'L' + state;
				if (state) {
					width = enugene.themes[objItem.theme].iELHoverwidth;
					height = enugene.themes[objItem.theme].iELHoverheight;
				} else {
					width = enugene.themes[objItem.theme].iELwidth;
					height = enugene.themes[objItem.theme].iELheight;
				}
			}
			
			// Now set the item content table attribute values
			// and override the theme related settings.
			
			// Do the size of image element for the separator, else item
			// elements css size animation is overwritten.
			if (enugene.menus.elements[objItem.id].itemtype == 'separator') {
				// item sizes
				var width = enugene.menus.elements[objItem.id].imagewidth;
				// item height
				var height = enugene.menus.elements[objItem.id].imageheight;
			}
			
			// item left
			var left = enugene.menus.elements[objItem.id].imageleft;
			if (left === 0 || parseInt( left )) elemObjRef.style.left = left + 'px';
			// item top
			var top = enugene.menus.elements[objItem.id].imagetop;
			if (top === 0 || parseInt( top )) elemObjRef.style.top = top + 'px';
			
			if (width === 0 || (parseInt( width ) && width != 'auto')) elemObjRef.style.width = width + 'px';
			if (height === 0 || (parseInt( height ) && height != 'auto')) elemObjRef.style.height = height + 'px';
			if (width == 'auto') {
				elemObjRef.style.width = '';
				width = '';
			}
			if (height == 'auto') {
				elemObjRef.style.height = '';
				height = '';
			}
			this.getImgElem (objItem, elemObjRef, state, width, height, 'L');
			if (menu && menu.getOrient().charAt(0) == 'v' && enugene.themes[objItem.theme].itemOrder == 'center') {
				if (objItemWidth == 'auto' || !objItemWidth) {
					enugene.DOM.util.set_Property(elemObjRef, "display", "inline", "important");
					enugene.DOM.util.set_Property(objItem.domObject, "text-align", "center", "important");
				}
			}
		}
		
		// Text item element
		width = '';
		height = '';
		top = '';
		left = '';
		elemObjRef = objElemT;
		if (elemObjRef) {
			elemObjRef.className = objItem.className + 'T' + state;
			this.getTextElem ( objItem, elemObjRef);
			
			// Now set the item content table attribute values
			// and override the theme related settings.
			// text div width
			var width = enugene.menus.elements[objItem.id].textwidth;
			
			// text div height
			var height = enugene.menus.elements[objItem.id].textheight;
			
			if (height === 0 || width === 0) {
				elemObjRef.childNodes[0].style.display = 'none';
			}
			if (height === 0 || parseInt( height )) elemObjRef.style.height = (height) + 'px';
			if (width === 0 || parseInt( width )) elemObjRef.style.width = (width) + 'px';
			
			// text div left
			var left = enugene.menus.elements[objItem.id].textleft;
			if (left === 0 || parseInt( left )) elemObjRef.style.left = left + 'px';
			// text div top
			var top = enugene.menus.elements[objItem.id].texttop;
			if (top === 0 || parseInt( top )) elemObjRef.style.top = top + 'px';
			
			if (menu && menu.getOrient().charAt(0) == 'v' && enugene.themes[objItem.theme].itemOrder == 'center') {
				if (objItemWidth == 'auto' || !objItemWidth) {
					enugene.DOM.util.set_Property(elemObjRef, "display", "inline", "important");
					enugene.DOM.util.set_Property(objItem.domObject, "text-align", "center", "important");
				}
			}
		}
		
		// The right item element - if no size no elems are constructed
		width = '';
		height = '';
		top = '';
		left = '';
		elemObjRef = objElemR;
		if (elemObjRef && objItem.type != 'separator') {
			elemObjRef.className = objItem.className + 'R' + state;
			if (state) {
				width = enugene.themes[objItem.theme].iERHoverwidth;
				height = enugene.themes[objItem.theme].iERHoverheight;
			} else {
				width = enugene.themes[objItem.theme].iERwidth;
				height = enugene.themes[objItem.theme].iERheight;
			}
			if (width === 0 || (parseInt( width ) && width != 'auto')) elemObjRef.style.width = width + 'px';
			if (height === 0 || (parseInt( height ) && height != 'auto')) elemObjRef.style.height = height + 'px';
			this.getImgElem ( objItem, elemObjRef, state, width, height, 'R' );
			var objItemHoverWidth = enugene.themes[objItem.theme].mIHoverwidth;
			// Prevent the right elem expanding the item to the menu width
			// if the menu orient is 'h' and no item width is set. In this
			// case the items are meant to be each as wide as the text is.
			if (menu && menu.getOrient().charAt(0) == 'h' && enugene.themes[objItem.theme].itemOrder == 'left') {
				if (!objItemWidth || !objItemHoverWidth)
					enugene.DOM.util.set_Property(elemObjRef, "float", "left", "important");
				if (objItemWidth == 'auto' || objItemHoverWidth == 'auto') 
					enugene.DOM.util.set_Property(elemObjRef, "float", "left", "important");
			}
			if (menu && menu.getOrient().charAt(0) == 'v' && enugene.themes[objItem.theme].itemOrder == 'center') {
				if (objItemWidth == 'auto' || !objItemWidth) {
					enugene.DOM.util.set_Property(elemObjRef, "display", "inline", "important");
					enugene.DOM.util.set_Property(objItem.domObject, "text-align", "center", "important");
				}
			}
		}
	}; // itemElems
	
	this.set_itemProperties = function (objItem, objRef) {
		// .type is the jos_menu type
		if (objItem.backgroundImage) {
			objRef.style.backgroundImage = 'url(' + enugene.menus.elements[objItem.id].backgroundImage + ')';
		}
		this.set_itemElems(objItem, objRef, false);
		if (objItem.style.className) {
			objRef.className = objItem.style.className;
			arrObjClassName = objItem.style.className.split('_');
			if (arrObjClassName[1] == 'Hover') {
				this.set_itemElems( objItem, objRef, true )
			}
		}
		var menu = objItem.getParentMenuObject();
		if (menu) {
			var objItemWidth = enugene.themes[menu.theme].mIwidth;
			var objItemHeight = enugene.themes[menu.theme].mIHeight;
		}
		
		// now set the item content table attribute values
		// item width
		width = enugene.menus.elements[objItem.id].width;
		if (width === 0 || (parseInt( width ) && width != 'auto')) objRef.style.width = width + 'px';
		// item height
		height = enugene.menus.elements[objItem.id].height;
		if (height === 0 || (parseInt( height ) && height != 'auto')) objRef.style.height = height + 'px';
		
		if (enugene.menus.elements[objItem.id].top) {
			var top = enugene.menus.elements[objItem.id].top;
			if (top === 0 || (parseInt( top ) && top != 'auto')) objRef.style.top = top + 'px';
		}
		if (enugene.menus.elements[objItem.id].left) {
			var left = enugene.menus.elements[objItem.id].left;
			if (left === 0 || (parseInt( left ) && left != 'auto')) objRef.style.left = left + 'px';
		}
	};

	/**
	 * @param objItem:
	 * the enugene.menus.elements object of the menuItem
	 * 
	 * @return void
	 */
	this.set_item = function (objItem, overItem) {
		var	arrObjClassName = '';
		var width = '';
		var height = '';
		var left = '';
		var top = '';
		var itemId = objItem.id;
		
		var objRef = enugene.DOM.util.getObject( itemId );
		
		// turn off the item fading for IE
		if (enugene.DOM.util.isIe( )) {
//			enugene.themes[objItem.theme].itemFadingAllow = false;
		}

		if(overItem && enugene.themes[objItem.theme].itemFadingAllow) {
				if (objItem.type != 'separator') {
					enugene.effects.item.itemEffectController( objItem );
				}
		} else {
			// This is the normal process without fading. - Only the original
			// item container has to be manipulated.
			var objRef = enugene.DOM.util.getObject( itemId );
			this.set_itemProperties( objItem, objRef );
		}
	}; // item
	
	/**
	 * Evaluate the menu size values and transfer them to the DOM affecting
	 * .style collection.
	 */
	this.eval_menuSize = function (obj, maxMenuWidth) {
		// transfer all sizes to the elements .style colletion
		// to be processed as DOM elements affecting value.
		if (parseInt(obj.width))
			obj.style.width = obj.width;
		if (parseInt(obj.height))
			obj.style.height = obj.height;
	};
	
	/**
	 * The submenu position calculation dispatch.
	 * 
	 *(mgen_obj is the enugene.elements object)
	 *   
	 * It writes the values to the 'mgen_obj.left' and 'mgen_obj.right' property which are 
	 * not used by setDOMProperty().
	 * 
	 * Later eval_menuPosition() will alter the 'mgen_obj.left' and 'mgen_obj.right' by the
	 * mgen_obj.disleft or mgen_obj.distop values and then write them to the 'mgen_obj.style.left' 
	 * and 'mgen_obj.style.top' properties.
	 * 
	 * The 'mgen_obj.style.left' and 'mgen_obj.style.top' properties are the values, later assigned 
	 * to the DOM elements by setDomProperties() - all (and only) properties noticed within the 
	 * 'mgen_obj.style' cluster.
	 * 
	 * Only the 'dynamic mode' is full automatically calculated!
	 * 
	 * For the 'horizontal' and 'vertical' modes only one size is calculated. The other 
	 * size first is set to zero here, then later the object related user settings are 
	 * calculated into.  
	 * 
	 * For the 'accordion' or the 'preset' modes both sizes (left and top) are set to zero here.
	 * Like above mentioned, this values will be altered by the other user settings. 
	 * 
	 * The menu container do respect the 'top' or 'left' values, whereas the:
	 * - 'preset' mode uses absolute position sizes 
	 * - and the 'accordion' mode appends the sub menu to the caller menuitem 'accordionFrame' 
	 *   and the accordion is a element of an relative or absolute positioned menu container. 
	 */
	this.set_subMenuPosition = function (idSub, menuItemId) {
		var mgenMenus_subMenu = enugene.menus.elements[idSub];
		if (!mgenMenus_subMenu) return;
		var positMode = enugene.menus.menutypes[mgenMenus_subMenu.moduleId].positMode;
		
		switch (positMode) {
			case 'dynamic':
				mgenMenus_subMenu.left = this.calc_subMenuPosition(idSub, menuItemId).left;
				mgenMenus_subMenu.top = this.calc_subMenuPosition(idSub, menuItemId).top;
				break;
			case 'horizontal' :
				mgenMenus_subMenu.left = this.calc_subMenuPosition(idSub, menuItemId).left;
				mgenMenus_subMenu.top = 0;
				break;
			case 'vertical' :
				mgenMenus_subMenu.left = 0;
				mgenMenus_subMenu.top = this.calc_subMenuPosition(idSub, menuItemId).top;
				break;
			case 'accordion' :
				mgenMenus_subMenu.left = 0;
				mgenMenus_subMenu.top = 0;
				break;
			case 'preset' :
				mgenMenus_subMenu.left = 0;
				mgenMenus_subMenu.top = 0;
				break;
			default :
				mgenMenus_subMenu.left = this.calc_subMenuPosition(idSub, menuItemId).left;
				mgenMenus_subMenu.top = this.calc_subMenuPosition(idSub, menuItemId).top;
				break;
		}
		return true;
	};
	
	/**
	 * @param string idSub Id of the submenu with the orgin to calculate
	 * @param string menuItemId Id of the menu calling Item
	 * @return void
	 */
	this.calc_subMenuPosition = function (idSub, menuItemId) {
		var orient = '';
		var top = '';
		var left = '';
		var subMenuWidth;
		var subMenuHeight;
		var subMenuTop;
		var subMenuLeft;
		var parentMenuHeight;
		var parentMenuTop;
		var menuItemLeft;
		var menuItemTop;
		var menuItemWidth;
		var menuItemHeight;	
		var parentMenu_orient;
		var arrReturn = {left:0,top:0};
		
		var mgenMenus_subMenu = enugene.menus.elements[idSub];
		if (!mgenMenus_subMenu) return;
		

		var positMode = enugene.menus.menutypes[mgenMenus_subMenu.moduleId].positMode;
		if (positMode == 'preset') {
			mgenMenus_subMenu.top = 0;
			mgenMenus_subMenu.left = 0;
			return;
		}
		
		subMenuWidth = enugene.DOM.util.getWidth( mgenMenus_subMenu.domObject );
		subMenuHeight = enugene.DOM.util.getHeight( mgenMenus_subMenu.domObject );
	
		var mgenMenus_MenuItem = enugene.menus.elements[menuItemId];
		if (!mgenMenus_subMenu) return;
	
		menuItemWidth = enugene.DOM.util.getWidth( mgenMenus_MenuItem.domObject );
		menuItemHeight = enugene.DOM.util.getHeight( mgenMenus_MenuItem.domObject );
		menuItemTop = enugene.DOM.util.getY( mgenMenus_MenuItem.domObject );
		menuItemLeft = enugene.DOM.util.getX( mgenMenus_MenuItem.domObject );
	
		var mgenMenus_parentMenu = mgenMenus_MenuItem.getParentMenuObject();
		parentMenuHeight = enugene.DOM.util.getHeight( mgenMenus_parentMenu.domObject );
		parentMenuTop = enugene.DOM.util.getY( mgenMenus_parentMenu.domObject );
	
		var topMenu = enugene.DOM.util.getObject( mgenMenus_subMenu.topMenuId );
		mainLeft = enugene.DOM.util.getX( topMenu );
		mainTop = enugene.DOM.util.getY( topMenu );
		
		orient = enugene.themes[mgenMenus_subMenu.theme].menuOrientation;
		var parentMenu_orient = enugene.themes[mgenMenus_parentMenu.theme].menuOrientation;
	
		if (parentMenu_orient.charAt(0) == 'h') { // if the parentMenu is horizontal
			if (orient.charAt(1) == 'b') { // subMenu's popup direction goes downwards
				subMenuTop = parentMenuTop + parentMenuHeight;
			} else { // subMenu's popup direction goes 'u'pwards
				subMenuTop = parentMenuTop - subMenuHeight;
			}
			if (orient.charAt(2) == 'r') { // subMenu popups is in right direction
				subMenuLeft = menuItemLeft;
			} else { // subMenu popups in 'l'eft direction
				subMenuLeft = menuItemLeft - subMenuWidth;
			}
			if (orient.charAt(2) == 'c') { // subMenu popups centered
				subMenuLeft = menuItemLeft + ((menuItemWidth - subMenuWidth) / 2)
			}
		} else { // the ParentMenu.orient is vertical
			if (orient.charAt(1) == 'b') { // subMenu's popup direction goes downwards
				if (orient.charAt(2) == 'c') { // subMenu popups centered
					subMenuTop = menuItemTop + menuItemHeight;
				} else {
					subMenuTop = menuItemTop;
				}
			} else { // subMenu's popup direction goes 'u'pwards
				if (orient.charAt(2) == 'c') { // subMenu popups centered
					subMenuTop = menuItemTop - subMenuHeight;
				} else {
					subMenuTop = menuItemTop + menuItemHeight - subMenuHeight;
				}
			}
			if (orient.charAt(2) == 'r') {// subMenu opens in 'r'ight
											// direction
				subMenuLeft = menuItemLeft + menuItemWidth;
			} else { // subMenu's align is in 'l'eft direction
				subMenuLeft = menuItemLeft - subMenuWidth;
			}
			if (orient.charAt(2) == 'c') { // subMenu popups centered
				subMenuLeft = menuItemLeft + ((menuItemWidth - subMenuWidth) / 2)
			}
		}
		if (isNaN( subMenuTop )) subMenuTop = 0;
		if (isNaN( subMenuLeft )) subMenuLeft = 0;
		
//		mgenMenus_subMenu.top = subMenuTop;
//		mgenMenus_subMenu.left = subMenuLeft;
		arrReturn.left = subMenuLeft;
		arrReturn.top = subMenuTop;
		
		return arrReturn;
	};
	
	/**
	 * Calculates optional user parameters to the basic position coordinates to get
	 * the final menu position. The calculations are affected upon the .style
	 * cluster properties of the elements object. All values to take affected on
	 * the DOM elements were prior collected there.
	 * 
	 * Later only the properties collected in the style cluster are affected on
	 * the DOM elements.
	 * 
	 * @param obj object
	 * @param domObj object
	 * @return void
	 */
	this.eval_menuPosition = function (obj) {
		var positioning = enugene.menus.menutypes[obj.moduleId].positMode;
		if (obj.type == 'sub') this.set_subMenuPosition( obj.id, obj.parentItemId);
		if (obj) {
			// Any dislocation set for menu styles? - set them affecting  
			if (obj.disleft === 0 || parseInt(obj.disleft)) {
				obj.style.left = parseInt(obj.disleft);
			}
			if (obj.distop === 0 || parseInt(obj.distop)) {
				obj.style.top = parseInt(obj.distop);
			}
			// Any position set for menu styles? - set them affecting
			if (obj.left === 0 || parseInt(obj.left)) {
				isNaN(obj.style.left) ? obj.style.left = obj.left : obj.style.left += obj.left;
			}
			if (obj.top === 0 || parseInt(obj.top)) {
				isNaN(obj.style.top) ? obj.style.top = obj.top : obj.style.top += obj.top;
			}
		}
	};
	
	/**
	 * Affects the menus.elements.style collected sizes on the DOM elements.
	 * 
	 * Don't force a value here: if no JS size is set, the css will do! So if
	 * the JS value is empty here leave it empty. Else all css settings or the
	 * native DOM HTML order will be overridden.
	 * 
	 * For using the effects the menus must have a fix size. The main menus 
	 * are not treated this way, for enabling the parent frame working 
	 * as blockFrame. 
	 * 
	 * The sizes fed here, are mainly the result of the styles database table 
	 * records.
	 */
	this.set_menuSize = function (menuObjRef, domObject) {
		var unit = 'px';
		var menuWidth = menuObjRef.style.width;
		var setImportant = enugene.themes[menuObjRef.theme].setImportant;
		var menuHeight = menuObjRef.style.height;
		
		if (!menuWidth && domObject.clientWidth) menuWidth = domObject.clientWidth;
		if (!menuHeight && domObject.clientHeight) menuHeight = domObject.clientHeight;
		
		if (!menuWidth || menuWidth === 0) {
			menuWidth = '0px';
		} else {
			if (menuWidth) {
				if (parseInt( menuWidth )) {
					menuWidth = menuWidth + unit;
				}
				domObject.style.width = menuWidth;
				if (menuObjRef.type != 'main')
					domObject.parentNode.style.width = menuWidth;
			}
		}

		if (!menuHeight || menuHeight === 0) {
			menuHeight = '0px';
		} else {
			if (menuHeight) {
				if (parseInt( menuHeight )) {
					menuHeight = menuHeight + unit;
				}
				domObject.style.height = menuHeight;
				if (menuObjRef.type != 'main')
					domObject.parentNode.style.height = menuHeight;
			}
		}
	};
	
	/**
	 * Affect the menus.elements.style collected position on the DOM elements.
	 * The position values realized here are the 'obj' recordset controlled
	 * ones, or they were set by 'setSubMenuPosition()'. If left out the css
	 * controlled position or the native HTML order is taken.
	 * 
	 * Forcing a value here affects the menu to be positioned anycase to this
	 * value.
	 */
	this.set_menuPosition = function (menuObjRef, domObject) {
		var unit = 'px';
		var menuTop = menuObjRef.style.top;
		var menuLeft = menuObjRef.style.left;

		// with version 0.9.9.5 the menu container is 
		// positioned 'static' into the subFrame container
		// and the subFrame container becomes the one 
		// to be positioned. - The menu container itself 
		// always get the zero position if no clipping effect 
		// is wanted.
			if (menuObjRef.type == 'main') {
				var objTarget = domObject;
			} else {
				var objTarget = domObject.parentNode;
				// Assure the menu container at zero position.
				// This becomes important if sliding effects are on.
				if (enugene.globals.mgen_arrExtensions
					&& enugene.globals.mgen_arrExtensions.ModContent) {
					domObject.style.top = '0px';
					domObject.style.left = '0px';
				}
			}

			if (menuTop === 0) {
				objTarget.style.top = '0px';
			} else {
				// empty? - do nothing.
				if (!isNaN(menuTop)) {
					if (parseInt( menuTop )) {
						objTarget.style.top = menuTop + unit;
					}
					if (menuObjRef.style.top == 'auto') {
						objTarget.style.top = menuTop;
					}
				}
			}
			if (menuLeft === 0) {
				objTarget.style.left = '0px';
			} else {
				if (!isNaN(menuLeft)) {
					if (parseInt( menuLeft )){
						objTarget.style.left = menuLeft + unit;
					}
					if (menuObjRef.style.left == 'auto') {
						objTarget.style.left = menuLeft;
					}
				}
			}
			
			// Append the menu to the accordion container.
			var orient = enugene.themes[menuObjRef.theme].menuOrientation.charAt(0);
			var positMode = enugene.menus.menutypes[menuObjRef.moduleId].positMode;
			if (positMode == 'accordion') {
				var objParentItem = enugene.menus.elements[menuObjRef.parentItemId]
				var objAccordionFrame = enugene.DOM.util.getObject(menuObjRef.parentItemId + '_accordionFrame');
				if (menuObjRef.type != 'main') objTarget.style.height = '0px';
				if (objAccordionFrame) objAccordionFrame.appendChild( objTarget );
			}

	};

	/**
	 * @param array
	 *            arrMenus array with references to the menu objects in
	 *            enugene.menus.elements
	 * @return void
	 */
	this.set_menu = function (menuObjRef) {
		var domObject = '';
		var x = '';
		var prop = '';
		var unit = 'px';
		var menuWidth = '';
		var mWunit = '';
		var jsVars = '';
		var maxMenuWidth = parseInt( enugene.themes[menuObjRef.theme].maxMenuWidth );
		var setImportant = enugene.themes[menuObjRef.theme].setImportant;

		if (!enugene.menus.elements[menuObjRef.id]) return;
		
		domObject = menuObjRef.domObject;
		
		if (menuObjRef.style.className) domObject.className = menuObjRef.style.className;

		this.eval_menuPosition( menuObjRef);
		this.eval_menuSize( menuObjRef, maxMenuWidth);
		
		// restrict to maxMenuWidth setting if the offsetWidth is greater
		// in such case try to calc any item margin or menu padding away
		var menuObjW = enugene.DOM.util.getWidth( menuObjRef.domObject );
		if (maxMenuWidth && (!menuObjRef.style.width || menuObjW > maxMenuWidth)) {
			if (menuObjW > maxMenuWidth) menuObjRef.style.width = Math.abs( maxMenuWidth - (menuObjW - maxMenuWidth) );
		}

		// Set obj related background image.
		if (menuObjRef.backgroundImage) {
			// For some silly reason - i d'know why - ie sets the visibility 
			// to empty if setAttribute is used. Stupid solution - i know!
			var bridgeVisibility = domObject.style.visibility;
			var img = 'url(' + menuObjRef.backgroundImage + ')';
			enugene.DOM.util.set_Property( domObject, "background-image", img, setImportant );
			domObject.style.visibility = bridgeVisibility;
		}

		// set the menu item visibility
		var argument = enugene.menus.elements[menuObjRef.id].hideMenuItems;
		if (argument != 'no') {
			enugene.menus.perform.hide.items.set_transparent( menuObjRef.items, argument );
		}
		
		this.set_menuSize( menuObjRef, domObject);
		this.set_menuPosition( menuObjRef, domObject);

		// set visibility
		if (menuObjRef.visibility) {
			if (enugene.themes[menuObjRef.theme].menuFadingAllow || enugene.themes[menuObjRef.theme].menuSlidingAllow) {
				// Do the effect specific initial changes before switching the object visible.
				enugene.effects.menu.menuEffectController( domObject, menuObjRef.visibility, enugene.themes[menuObjRef.theme] );
			} else {
				domObject.style.visibility = menuObjRef.visibility;
				if (menuObjRef.visibility == 'hidden') {
					domObject.parentNode.style.height = '0px';
				} else {
					domObject.parentNode.style.height = domObject.style.height;
				}
			}
		}

	}; // menu
	
	/**
	 * @param obj
	 *            enugene.menus.elements
	 * @return boolean
	 */
	this.setDOMProperties = function (obj, overItem) {
		var x = '';
		var menuObjRef = '';
		var arrMenus = new Array( );
		var arrItems = new Array( );
		var i = 0;
		for (x in obj) {
			menuObjRef = obj[x];
			if (!menuObjRef.published) continue;
			if (!menuObjRef || !menuObjRef.domObject.id) {
				continue;
			}
			if (menuObjRef.objtype == 'menuItem') {
				this.set_item( enugene.menus.elements[x], overItem );
				menuObjRef.style = new Object();
			}
			if (menuObjRef.objtype == 'menu') {
				arrMenus[i] = menuObjRef;
				++i;
			}
		}
		for(i = 0; i < arrMenus.length; ++i) {
			this.set_menu(arrMenus[i]);
			arrMenus[i].style = new Object();
		}
		arrMenus = null;

		enugene.menus.updateList = new Object( );

		return true;
	}; 

}// clsMgenContentMenuProperties

// //////////////////////////////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////// EFFECTS ////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////

function clsMgenEffects () {
	
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////// ITEM EFFECTS ////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
	this.clsItemEffects = function () {
		this.testout = null;
		this.fadeMin = 0;
		this.fadeMax = 1;
		this.duration = 1000;
		
		this.transferProperties = function (objTargetItem, objSourceItem) {
			if(objSourceItem.onmouseover) objTargetItem.onmouseover = objSourceItem.onmouseover;
			if(objSourceItem.onmousedown) objTargetItem.onmousedown = objSourceItem.onmousedown;
			if(objSourceItem.onmouseup) objTargetItem.onmouseup = objSourceItem.onmouseup;
			
			if(objSourceItem.theme) objTargetItem.theme = objSourceItem.theme;
			if(objSourceItem.topMenuId) objTargetItem.topMenuId = objSourceItem.topMenuId;
			if(objSourceItem.myMenuId) objTargetItem.myMenuId = objSourceItem.myMenuId;
		};
		
		this.transferCssMargins = function (objTarget, objComputedStyles) {
			if(objComputedStyles.marginTop) objTarget.style.marginTop = objComputedStyles.marginTop;
			if(objComputedStyles.marginRight) objTarget.style.marginRight = objComputedStyles.marginRight;
			if(objComputedStyles.marginBottom) objTarget.style.marginBottom = objComputedStyles.marginBottom;
			if(objComputedStyles.marginLeft) objTarget.style.marginLeft = objComputedStyles.marginLeft;
		};
		
		/**
		 * Create two clones for normal and hover item and clear the original
		 * item box content.
		 */
		this.createClone = function (obj, className) {
			var objCloneFadeOut = obj.cloneNode( true );
			objCloneFadeOut.id = obj.id + '_out';
			objCloneFadeOut.style.margin = '0px 0px 0px 0px';
			objCloneFadeOut.style.top = '0px';
			objCloneFadeOut.style.left = '0px';
			objCloneFadeOut.style.position = 'static';
			objCloneFadeOut.style.opacity = this.fadeMax;
			objCloneFadeOut.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity = ' + Math.floor( (this.fadeMax * 100) ) +')';
			
			var objCloneFadeIn = obj.cloneNode( true );
			objCloneFadeIn.className = className;
			objCloneFadeIn.id = obj.id + '_in';
			objCloneFadeIn.style.margin = '0px 0px 0px 0px';
			objCloneFadeIn.style.top = '0px';
			objCloneFadeIn.style.left = '0px';
			objCloneFadeIn.style.position = 'absolute';
			objCloneFadeIn.style.opacity = this.fadeMin;
			objCloneFadeIn.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity = ' + Math.floor( (this.fadeMin * 100) ) +')';
						
			var height = obj.offsetHeight;
			var width = obj.offsetWidth;
			
			// The first has to be static to protect 'auto' sized
			// item container sizes.
			var objCloneFadeFrame = obj.cloneNode( false );
			objCloneFadeFrame.id = obj.id;
			objCloneFadeFrame.style.border = '0px solid transparent';
			objCloneFadeFrame.style.padding = '0px 0px 0px 0px';
			objCloneFadeFrame.style.position = 'relative';
			objCloneFadeFrame.style.width =  width + 'px';
			objCloneFadeFrame.style.height = height + 'px';
			
			objCloneFadeFrame.appendChild( objCloneFadeOut );
			objCloneFadeFrame.appendChild( objCloneFadeIn );
			
			this.transferProperties( objCloneFadeFrame, obj );
			
			obj.parentNode.replaceChild( objCloneFadeFrame, obj );
			
			// The following changes by set_itemProperties() are made to the clone.
			return objCloneFadeIn;
		};
		
		this.removeClone = function (cloneInId, className) {
			var objCloneFadeIn = enugene.DOM.util.getObject( cloneInId );
			var objCloneFadeFrame = objCloneFadeIn.parentNode;
			if (objCloneFadeFrame.childNodes == null ) return false;
			
			var newItem = objCloneFadeFrame.childNodes[objCloneFadeFrame.mgenEffects.childFadeIn];
								
			newItem.id = newItem.id.split('_')[0];
			newItem.style.filter = '';
			newItem.style.position = 'relative';
			var cssStyle = enugene.DOM.util.get_computedStyle( objCloneFadeFrame );
			this.transferProperties( newItem, objCloneFadeFrame );
			this.transferCssMargins( newItem, cssStyle );
			
			objCloneFadeFrame.parentNode.replaceChild( newItem, objCloneFadeFrame );
			
			objCloneFadeFrame = null;
			
			enugene.menus.elements[newItem.id].domObject = enugene.DOM.util.getObject( newItem.id );
			return true;
		};
		
		/**
		 * Opacity
		 */
		this.set_opacity = function (fadeIn, fadeOut, indexIn, objRef) {
			var objCloneFadeFrame = objRef.parentNode;
			var indexFadeOut = Math.abs( objCloneFadeFrame.mgenEffects.childFadeIn - 1 );
			// Invert the item clone children if the mouse changes the
			// buttons during fading.
			var objCloneFadeOut = objCloneFadeFrame.childNodes[indexFadeOut];
			var objCloneFadeIn = objCloneFadeFrame.childNodes[objCloneFadeFrame.mgenEffects.childFadeIn];
			objCloneFadeIn.style.opacity = fadeIn;
			objCloneFadeOut.style.opacity = fadeOut;
			objCloneFadeIn.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity = ' + Math.floor( (fadeIn * 100) ) +')';
			objCloneFadeOut.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity = ' + Math.floor( (fadeOut * 100) ) +')';
		};
		
		this.invertFading = function (objRef) {
			var className = '';
			var objCloneFadeIn = objRef.childNodes[Math.abs( objRef.mgenEffects.childFadeIn - 1 )];
			var fadeInClassName = objCloneFadeIn.className;
			var fadingItemClassName = objRef.className;

			// Don't invert the fading of the clone[childFadeIn], if the clone
			// className has 'Hover' AND the fading menuItem is not the
			// currentItem.
			if (	enugene.menus.currentItem.id != objRef.id 
					&& fadeInClassName.search( '_Hover' ) != -1) {
				// Force the the fadeIn item to normal class and don't 
				// invert the effect direction.
				objRef.childNodes[ objRef.mgenEffects.childFadeIn ].className = fadeInClassName.split( '_Hover' )[0];
				return;
			}
			// Don't invert fading to normal state if the requesting
			// item is the currentItem.
			if (	enugene.menus.currentItem.id == objRef.id 
					&& fadeInClassName.search( '_Hover' ) == -1) {
				objRef.childNodes[ objRef.mgenEffects.childFadeIn ].className = fadeInClassName + '_Hover';
				return;
			}
	
			// Invert the clone index - [1] is always the
			// item clone to be faded in.
			objRef.mgenEffects.childFadeIn = Math.abs( objRef.mgenEffects.childFadeIn - 1 );
			// Invert the counter.
			objRef.mgenEffects.affectVal = (1 + (objRef.mgenEffects.affectVal * -1));
		};
		
		this.setParams = function (objTheme) {
			// Get the user defined preferences or use the class variable values.
			if (objTheme) {
				this.duration = objTheme.itemFadingDuration ? objTheme.itemFadingDuration : 1000;
			} else {
				return;
			}
		};
		
		/**
		 * INITIALIZE - this is called by mouseover event only. Return the item
		 * clone which is to be faded in.
		 * 
		 * All changes made by setItem() will be made to the returned fadeIn
		 * clone. The fadeIn clone is the one which is 'hovered'.
		 * 
		 * After the clone was processed by set_itemProperties(), it will be
		 * passed to the fade animation.
		 * 
		 * FADING CHANGE - if fading is already running it changes the direction
		 * of fading, by resetting the index value of the objItem childFadeIn to
		 * zero.
		 * 
		 * As normally the fadeIn child is child[1], the fadeIn child now
		 * becomes child[0].
		 * 
		 * The index value change does not affect the child[1] while passing the
		 * setItem() function. They are later affected in set_opacity(). - For
		 * set_itemProperties() everything stay the same, because the return
		 * value in both cases is the ref to child[1].
		 * 
		 * The change of fading direction only affects the fading parameters for
		 * the according menu item container object.
		 * 
		 * Means: the fading process continues without interruption.
		 * 
		 * FADING STOP - If the opacity value exceeds the high level - 1 - the
		 * process leaves the timeout loop.
		 * 
		 * Leaving the fading loop causes the item clones to be resolved,
		 * affecting parent item container to be replaced by its inner
		 * clone[1]object.
		 * 
		 * UPDATING THE MENUS ELEMENTS INDEX - A carefully updating of the
		 * menus.elements index, is important for a appropriate function of the
		 * items - and inner item elements - CSS class and style manipulation.
		 */
		this.initCrossFading = function (objRef, objTheme) {
			this.setParams( objTheme );
			if (this.fadeMax > 1) this.fadeMax = 1;
			if (this.fadeMin < 0) this.fadeMin = 0;
			
			var objCloneFadeIn = this.createClone( objRef, objRef.className );

			if (!objCloneFadeIn.parentNode.mgenEffects) {
				this.initItemEffects( objCloneFadeIn.parentNode );
			}
			
			objCloneFadeIn.parentNode.mgenEffects.active = true;
			objCloneFadeIn.parentNode.mgenEffects.affectVal = this.fadeMin;
			objCloneFadeIn.parentNode.mgenEffects.elapsedTime = 0;
			// the normal fade in clone is clone[1]
			objCloneFadeIn.parentNode.mgenEffects.childFadeIn = '1';

			enugene.menus.elements[objRef.id].domObject = objCloneFadeIn;
			
			if (objCloneFadeIn)
				return objCloneFadeIn;
			else
				return objRef;
		};
		
		this.initItemEffects = function(objCloneFadeFrame) {
			if (!objCloneFadeFrame.mgenEffects) {
				objCloneFadeFrame.mgenEffects = {
					elapsedTime : 0,
					affectVal : 0,
					active : false,
					childFadeIn : '1'
				};
			}
		};
		
		this.itemEffectController = function (objItem) {
//this.testout = enugene.DOM.util.getObject('mousePos_frame');
//this.testout.innerHTML += 'OUT->' + objRef.id + objRef.className +'<br />';
			var itemId = objItem.id.split('_')[0];
			var objFrame = enugene.DOM.util.getObject( itemId );

			var objRef = enugene.DOM.util.getObject( objItem.id );
			// The passed item has no active fading process - Init the process:
			// - Create clones for the item container; 
			// - Do all further settings only to the unvisible clone[1], returned
			//   by the fade init function.
			if (!objFrame.mgenEffects) {
				objRef = this.initCrossFading( objRef, enugene.themes[objRef.theme] );
				// Realize the property settings for the 'hover' clone[1] 
				// only - that's objRef - objRef is the objCloneFadeIn.
				enugene.DOM.properties.set_itemProperties( objItem, objRef );
				// Start the fading process after clone[1] was updated to the
				// item highlight state effects.

				this.playFade( objRef.id, new Date().getTime() );
				return;
			} else {
				if (objRef.mgenEffects.active === true) {
					// Do no property settings here! All settings has been done to
					// the processed clones. - Do only change the item object fading
					// parameters for the running process.
					enugene.effects.item.invertFading( objRef );
					return;
				}
			}
		};
		
		/*
		 * Executes the fading animation
		 */
		this.playFade = function (cloneInId, lastTime) {
			var objRef = enugene.DOM.util.getObject( cloneInId );
			
			var objCloneFadeFrame = objRef.parentNode;
			// sync time value		
			var curTime = new Date().getTime();
			objCloneFadeFrame.mgenEffects.elapsedTime += curTime - lastTime;
			
			if (!objRef || !objCloneFadeFrame.mgenEffects.active) return false;
			
			if (objCloneFadeFrame.mgenEffects.affectVal >= this.fadeMax || isNaN( objCloneFadeFrame.mgenEffects.affectVal )) {
				this.set_opacity( this.fadeMax, this.fadeMin, objCloneFadeFrame.mgenEffects.childFadeIn, objRef );
				enugene.effects.item.removeClone( cloneInId, objRef.className );
				return;
			}
			
			var range = this.fadeMax - this.fadeMin;
			var affectVal = (range / this.duration) * objCloneFadeFrame.mgenEffects.elapsedTime;			
			objCloneFadeFrame.mgenEffects.affectVal = affectVal;
			if (isNaN( objCloneFadeFrame.mgenEffects.affectVal )) objCloneFadeFrame.mgenEffects.affectVal = this.fadeMin;
			
			this.set_opacity( objCloneFadeFrame.mgenEffects.affectVal, 1 - objCloneFadeFrame.mgenEffects.affectVal, objCloneFadeFrame.mgenEffects.childFadeIn, objRef );
			setTimeout(  'enugene.effects.item.playFade("' + cloneInId + '","' + curTime + '")', 33 );
	
		}; // play
		
	}; // clsCrossFading
	
// //////////////////////////////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////// MENU EFFECTS ///////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////


	
	this.clsMenuEffects = function () {
		this.testout = null;
		this.frequency = 33;
		
		/**
		 * DESCRIPTION: Effects open / close.
		 * 
		 * STATE - The zero state causes the effect affecting value 
		 * to shrink.
		 * 
		 * CLOSED - The 'closed' flag indicates the total state of the 
		 * effect. It indicates an effect has run through to the end.
		 * 
		 * Most effects run two times ( up and down ) until they are 
		 * closed. Some future effects may run to close by only one direction.
		 * 
		 * Those which use two calls to be closed ( like fading in - fading 
		 * out ), needs this flag indicating their wait state until the 
		 * following call.
		 * 
		 * The usage is: If the 'state' shows ZERO and 'closed' is 'false',
		 * the started process will run inverting the previous effect.
		 * 
		 * ACTIVE - The 'active' flag only indicates the process 
		 * is currently running. It does not tell anything about the effect is closed! 
		 * 
		 * The 'active' flag controls the running process to be inverted 
		 * by the controller function.
		 * 
		 * VISIBILITY - The visibility control for the menus is delegated to 
		 * the effect functions.
		 * 
		 * As the effect process values are affected by a recursive 
		 * timeout call, there is no way for linear processing. All 
		 * action has to be done according to the effects process state.
		 * 
		 * Passing the visibility as 'hidden', does not cause the DOM object 
		 * visibility to be set immediately. Just when all effects are closed,
		 * the 'hidden' value is executed.
		 * 
		 * SAVE AND RESTORE STYLES - Properties which are manipulated during 
		 * the effect runtime can be saved to an 'originalStyles' object 
		 * within the DOM element. They are restored on effect closed. 
		 */
		this.openEffect = function (objRef, name, state) {
			if (!objRef) return;
			
			if (!objRef.mgenEffects) {
				objRef.mgenEffects = {count:0,playing:false};
			}
			
			if (objRef.mgenEffects[name]['closed'] === true) {
				++objRef.mgenEffects.count;
			}

			if (objRef.mgenEffects.count > 0 && state) {
				this.setOpenDefaults( objRef, name );
				objRef.style.visibility = 'visible';
				objRef.parentNode.style.visibility = 'visible';
				objRef.mgenEffects[name]['closed'] = false;
			}
		};
		
		/**
		 * There is no way to set the visibility of the object directly.
		 * 
		 * The visibility has to respect other effects running with the 
		 * recently closed one.
		 * 
		 * Only if no mgenEffects object exists the DOM object visibility 
		 * is automatically executed to 'hidden' on effect close.
		 * 
		 * Any else case closing executes the visibility value saved in the 
		 * mgenEffects object. This value is first set on opening the effect
		 * automatically as 'visible', or to the to the value passed to the 
		 * openEffect() function.
		 * 
		 * Else the visibility can extra be set by the setEffectVisibility() 
		 * function (sure directly too).
		 * 
		 */
		this.closeEffect = function (objRef, name, visibility) {
			if (!objRef) return;
			
			objRef.mgenEffects.visibility = visibility;

			if (objRef.mgenEffects.count > 0) {
				--objRef.mgenEffects.count;
				if (objRef.mgenEffects[name]) {
					objRef.mgenEffects[name]['affectVal'] = 0;
					objRef.mgenEffects[name]['closed'] = true;
					objRef.mgenEffects[name]['active'] = false;
					objRef.mgenEffects[name]['state'] = 0;
				}
			}

			// affect object visibility only if no effect is registrated 
			if (!objRef.mgenEffects.count && visibility) {
				objRef.parentNode.style.visibility = visibility;
				objRef.style.visibility = visibility;
				objRef.style.left = '0px';
				objRef.style.top = '0px';
			} else {
				if (!objRef.mgenEffects.count) {
					objRef.parentNode.style.visibility = 'hidden';
					objRef.style.visibility =  'hidden';
				}
			}
			
			// Do this after hidden.
			this.restoreStyles( objRef, name );
			
		};
		
		this.saveStyles = function (objRef, effect) {
			// commons
			if (objRef.parentNode) {
				if (!objRef.parentNode.originalStyles) objRef.parentNode.originalStyles = {};
				if (objRef.parentNode.style.overflow) objRef.parentNode.originalStyles.overflow = objRef.parentNode.style.overflow;
			}
			if (objRef) {
				if (!objRef.originalStyles) objRef.originalStyles = {};	
				if (objRef.style.overflow) objRef.originalStyles.overflow = objRef.parentNode.style.overflow;
			}
			// specials
			switch (effect) {
				case 'sliding' :
					if (objRef) {				
						objRef.originalStyles.position = objRef.style.position;
						objRef.originalStyles.width = objRef.clientWidth;
						objRef.originalStyles.height = objRef.clientHeight;
					}
					
					if (objRef.parentNode) {
						objRef.parentNode.originalStyles.width = objRef.parentNode.clientWidth;
						objRef.parentNode.originalStyles.height = objRef.parentNode.clientHeight;
					}
				break;
			}
		};
		
		this.restoreStyles = function (objRef, effect) {
			if (objRef && objRef.originalStyles) {
				if (objRef.originalStyles.overflow) objRef.style.overflow = objRef.originalStyles.overflow;
				else objRef.style.overflow = 'visible';
			}
			if (objRef && objRef.parentNode.originalStyles) {
				if (objRef.parentNode.originalStyles.overflow) objRef.parentNode.style.overflow = objRef.parentNode.originalStyles.overflow;
				else objRef.parentNode.style.overflow = 'visible';
			}
			switch (effect) {
				case 'sliding' :
					if (objRef && objRef.originalStyles) {
						objRef.style.position = objRef.originalStyles.position;
						objRef.style.width = objRef.originalStyles.width + 'px';
						objRef.style.height = objRef.originalStyles.height + 'px';
					}
					if (objRef.parentNode && objRef.parentNode.originalStyles) {
						objRef.parentNode.style.width = objRef.parentNode.originalStyles.width + 'px';
						objRef.parentNode.style.height = objRef.parentNode.originalStyles.height + 'px';
					}
					break;
			}
		};
		
// //////////////////////////////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////// MENU EFFECT PLAYER FUNCTIONS ///////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////

		
// FADING ///////////////////////////////////////////////////////////////////////////////////		
		
		/**
		 * Setting the fading opacity
		 */
		this.set_opacity = function (objRef) {
			var objEffects = enugene.themes[objRef.theme].effects;
			var objEffectsIndex = enugene.themes[objRef.theme].effectsIndex;
			
			var id = objEffectsIndex.fading;

			if (objRef.mgenEffects.fading.affectVal > objEffects[id].max) 
				objRef.mgenEffects.fading.affectVal = objEffects[id].max;
			if (objRef.mgenEffects.fading.affectVal < objEffects[id].min) 
				objRef.mgenEffects.fading.affectVal = objEffects[id].min;

			// State is zero? - shrinking value against zero.
			if (objRef.mgenEffects.fading.state) {
				var fadeVal = objRef.mgenEffects.fading.affectVal;
			} else {
				var fadeVal = (1 + (objRef.mgenEffects.fading.affectVal * -1));
			}
			
			//objRef.mgenEffects.fading.affectVal = fadeVal;
			objRef.style.opacity = fadeVal;
			objRef.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity = ' + Math.floor( (fadeVal * 100) ) +')';
		};
		
		/**
		 * Executes one time related step forward with the opacity animation.
		 */
		this.animateFading = function (objRef) {
			var objEffects = enugene.themes[objRef.theme].effects;
			var objEffectsIndex = enugene.themes[objRef.theme].effectsIndex;
			var id = objEffectsIndex.fading;
			if (objRef.mgenEffects.fading.affectVal >= objEffects[id].max || isNaN( objRef.mgenEffects.fading.affectVal )) {
				this.set_opacity( objRef );
				// Set visibility after fading, if direction was low.
				// Means: obj is reset back to hidden after fading stops.
				objRef.mgenEffects.fading.active = false;
				objRef.mgenEffects.fading.affectVal = objEffects[id].min;
				return true;
			}
			
			var range = objEffects[id].max - objEffects[id].min;
			var affectVal = (range / objEffects[id].duration) * objRef.mgenEffects.fading.elapsedTime;
			objRef.mgenEffects.fading.affectVal = affectVal;
			
			if (isNaN( objRef.mgenEffects.fading.affectVal )) objRef.mgenEffects.fading.affectVal = objEffects[id].min;
			this.set_opacity( objRef );
			
			return false;
		};
		
// SLIDING ///////////////////////////////////////////////////////////////////////////////////
		
		/**
		* Calculating the sizes:
		* 
		* The menu container are moved through the parent
		* subFrame container. Not the menus are positioned but 
		* the subFrames are.
		* 
		* The menu container must not be sized, but the subFrame 
		* may be sized, having the overflow set to 'hidden'.
		* 
		* Sizing the menu container, would cause the inner item 
		* container to loose their order.
		*/
		this.set_innerPosition = function (objRef,maxWidth,maxHeight,calcWidth,calcHeight,orient) {
			var objEffects = enugene.themes[objRef.theme].effects;
			var objEffectsIndex = enugene.themes[objRef.theme].effectsIndex;
			var modId = enugene.menus.elements[objRef.id].moduleId;
			if (modId) {
				var positMode = enugene.menus.menutypes[modId].positMode;
				// accordion? - Allow only downward sliding!
				if (positMode == 'accordion') {
					orient = 'vbc';
				}
			}
			var id = objEffectsIndex.sliding;
			if (orient.charAt(2) == 'r' || orient.charAt(1) == 'c') { //below or centered
				// horizontal position stays the same
				if (objEffects[id].horizontal) {
					objRef.style.left = (maxWidth - calcWidth) * -1 + 'px';
				}
				if(orient.charAt(1) == 'b') {
					// The menu container is topwards moved out of the
					// subFrame window. By processing the menu will
					// stepwise be moved back into the subFrame. 
					if (objEffects[id].vertical) {
						objRef.style.top = (maxHeight - calcHeight) * -1 + 'px';
					}
				} else {
					// The menu is not positioned out of the subFrame window.
					// It stays in place at 0px, but the subFrame is enlarged 
					// and new postionioned upwards - exactly for the distance 
					// of it's enlargement.
					if (objEffects[id].vertical) {
						objRef.style.top = maxHeight - calcHeight + 'px';
					}
				}
			}
			if (orient.charAt(2) == 'l') {
				if(orient.charAt(1) == 'b') {
					if (objEffects[id].horizontal) {
						objRef.style.left = maxWidth - calcWidth + 'px';
					}
					if (objEffects[id].vertical) {
						objRef.style.top = (maxHeight - calcHeight) * -1 + 'px';
					}
				} else {
					if (objEffects[id].horizontal) {
						objRef.style.left = maxWidth - calcWidth + 'px';
					}
					if (objEffects[id].vertical) {
						objRef.style.top = maxHeight - calcHeight + 'px';
					}
				}
			}
			// For this only the below sliding direction is allowed.
			if (positMode == 'accordion') {
				objRef.parentNode.style.height = calcHeight + 'px';
			}
		};
		
		this.set_slidingValues = function (objRef) {
			var objEffects = enugene.themes[objRef.theme].effects;
			var objEffectsIndex = enugene.themes[objRef.theme].effectsIndex;
			var id = objEffectsIndex.sliding;
			var orient = enugene.themes[objRef.theme].menuOrientation;
			var maxWidth = objRef.originalStyles.width;
			var maxHeight = objRef.originalStyles.height;

			if (objRef.mgenEffects.sliding.affectVal < objEffects[id].min) {
				// Add the min value to the affect val - if it 
				// becomes larger than max, it is cut by the statement below
				objRef.mgenEffects.sliding.affectVal = objRef.mgenEffects.sliding.affectVal + objEffects[id].min;
				if (isNaN( objRef.mgenEffects.sliding.affectVal )) {
					objRef.mgenEffects.sliding.affectVal = objEffects[id].min;
				}
			}
			// Assure the largest value is the max
			if (objRef.mgenEffects.sliding.affectVal > objEffects[id].max) {
				objRef.mgenEffects.sliding.affectVal = objEffects[id].max;
				if (objRef.mgenEffects.sliding.affectVal > 100) {
					objRef.mgenEffects.sliding.affectVal = 100;
				}
			}
						
			// State is zero? - shrinking value against zero.
			if (objRef.mgenEffects.sliding.state) {
				var slideVal = objRef.mgenEffects.sliding.affectVal;
			} else {
				var slideVal = (100 + (objRef.mgenEffects.sliding.affectVal * -1));
			}

			if (maxWidth && objEffects[id].horizontal) {
				var calcWidth = (maxWidth/100) * slideVal;
			} else {
				var calcWidth = maxWidth;
			}
			if (maxHeight && objEffects[id].vertical) {
				var calcHeight = (maxHeight/100) * slideVal;
			} else {
				var calcHeight =  maxHeight;
			}
			this.set_innerPosition ( objRef, maxWidth, maxHeight, calcWidth, calcHeight, orient );
		};
		
		/**
		 * Calculates and assigns the time related position to the menu container.
		 */
		this.animateSliding = function (objRef) {
			var objEffects = enugene.themes[objRef.theme].effects;
			var objEffectsIndex = enugene.themes[objRef.theme].effectsIndex;
			var id = objEffectsIndex.sliding;
			if (objRef.mgenEffects.sliding.affectVal >= objEffects[id].max || isNaN( objRef.mgenEffects.sliding.affectVal )) {
				objRef.mgenEffects.sliding.active = false;
				objRef.mgenEffects.sliding.affectVal = objEffects[id].min;
				return true;
			}
			var range = objEffects[id].max - objEffects[id].min;
			var affectVal = (range / objEffects[id].duration) * objRef.mgenEffects.sliding.elapsedTime;
			objRef.mgenEffects.sliding.affectVal = affectVal;

			if (isNaN( objRef.mgenEffects.sliding.affectVal )) objRef.mgenEffects.sliding.affectVal = objEffects[id].min;
	
			this.set_slidingValues( objRef );

			return false;
		};
		
// EFFECTS PLAYER ///////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * This are the effect according start values called each time
		 * the effect is started up from 'closed'.
		 */
		this.setOpenDefaults = function (objRef,name) {
			var objEffects = enugene.themes[objRef.theme].effects;
			var objEffectsIndex = enugene.themes[objRef.theme].effectsIndex;
			
			switch (name) {
			case 'fading' :
				var id = objEffectsIndex.fading;
				objRef.mgenEffects.fading.state = 1;
				objRef.mgenEffects.fading.affectVal = objEffects[id].min;
				this.set_opacity( objRef, '0' );
				break;
			case 'sliding' :
				var id = objEffectsIndex.sliding;
				objRef.mgenEffects.sliding.state = 1;
				objRef.mgenEffects.sliding.affectVal = objEffects[id].min;
				objRef.style.overflow = 'hidden';
				this.set_slidingValues( objRef, '0' );
				break;
			}
		};
		
		/**
		* Reset the filters - else IE clips the menu overflow
		* after fading and all overhanging elems are cut.
		*
		* Clearing the filter causes the IE not to show 
		* the menu if the fading is started next time.
		* For this reason the filter is only reset if no 
		* fading was set to this theme.
		*
		* Practically this means for the IE:
		* Using the menu fading, all menu content exceeding the 
		* menu container gets clipped. Disallowing the menu fading
		* the IE filter gets cleared and the overflow is shown.
		*/
		this.clearIEFilter = function (objRef) { 
			if (!enugene.themes[objRef.theme].menuSlidingAllow) {
				objRef.style.filter = '';
			}
		};
		
		/**
		 * Executes the effect animations recursion.
		 * 
		 * This may be called as the 'engine' for the menu effects 
		 * animation sequence.
		 */
		this.playMenuEffects = function (objId, visibility, lastTime) {
			var objRef = enugene.DOM.util.getObject( objId );
			
			// sync time value		
			var curTime = new Date().getTime();

			if (!objRef.mgenEffects)
				return;
			
			// fading
			if (enugene.themes[objRef.theme].menuFadingAllow
				&& objRef.mgenEffects.fading
				&& objRef.mgenEffects.fading.active
				&& objRef.mgenEffects.fading.closed == false) {
				objRef.mgenEffects.fading.elapsedTime += curTime - lastTime;
				this.animateFading( objRef );
			}
			// sliding
			if (enugene.themes[objRef.theme].menuSlidingAllow
				&& objRef.mgenEffects.sliding
				&& objRef.mgenEffects.sliding.active
				&& objRef.mgenEffects.sliding.closed == false) {
				objRef.mgenEffects.sliding.elapsedTime += curTime - lastTime;
				this.animateSliding( objRef );

				// Successfully passed? - Reset the subFrame overflow back to visible
				// else overlapping elements and the menu borders are lost.
				if (objRef.mgenEffects.sliding.active === false) {
					objRef.parentNode.style.overflow = 'visible';
				}
			}

			if (objRef.mgenEffects != null) {
				var activeEffects = 0;
				for (effect in objRef.mgenEffects) {
					if (typeof(objRef.mgenEffects[effect]) != 'object') continue;
					var name = effect;
					if (objRef.mgenEffects[name].active === false) {
						// close the effect if its end is at state zero
						if (!objRef.mgenEffects[name].state) {
							this.closeEffect( objRef, name, 'hidden' );
						}
					}
					if (objRef.mgenEffects[name].active === true) ++activeEffects;
				}
				// Don't leave the timeout loop until all Effects 
				// has been executed.
				if (!activeEffects) {
					// Respecting the IE overflow behavior
					this.clearIEFilter( objRef );
					objRef.style.overflow = 'visible';
					objRef.mgenEffects.playing = false;
					return;
				}
			}
			setTimeout('enugene.effects.menu.playMenuEffects("' + objId + '","' + visibility + '","' + curTime + '")', this.frequency );
		}; // play
		
// //////////////////////////////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////// INIT MENU EFFECTS //////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 *  Registrates the user given effect parameters to an effect collection array.
		 *  The parameter collection and the according index are appended to each menu 
		 *  according theme cluster of the enugene.themes object.
		 *  
		 *  The index is needed to identify and access the effects and their parameter 
		 *  to be played for each theme.
		 *  
		 *  Each time an menu or item is activated, the process first looks up the index, 
		 *  determining which effects are to play. Then it obtains the effect parameter 
		 *  using the index number, found within the index accorded to the effect name.
		 *  
		 *  With this version the effects collection array and the associative effects index 
		 *  is created and collected here, reading each menus theme to obtain the effect 
		 *  parameter.
		 *  
		 *  With some later version this collection should be created by the JsVars compiler.  
		 */
		this.setUserControlParams = function (objTheme) {
			objEffects = objTheme.effects = [];
			objEffectsIndex = objTheme.effectsIndex = {};
			var id = '';
			
			// turn off the effects for IE
			if (enugene.DOM.util.isIe( )) {
//				objTheme.menuFadingAllow = false;
//				objTheme.menuSlidingAllow = false;
			}
			
			if (objTheme) {
				if (objTheme.menuFadingAllow == true) {
					id = objEffectsIndex['fading'] = objEffects.length;
					objEffects[id] = {};
					objEffects[id]['name'] = 'fading';
					objEffects[id]['duration'] = objTheme.menuFadingDuration ? objTheme.menuFadingDuration : 1000;
					objEffects[id]['min'] = 0;
					objEffects[id]['max'] = 1;
				}
				if (objTheme.menuSlidingAllow == true) {
					id = objEffectsIndex['sliding'] = objEffects.length;
					objEffects[id] = {};
					objEffects[id]['name'] = 'sliding';
					objEffects[id]['duration'] = objTheme.menuSlidingDuration ? objTheme.menuSlidingDuration : 1000;
					objEffects[id]['horizontal'] = objTheme.menuSlidingHorizontal ? true : false;
					objEffects[id]['vertical'] = objTheme.menuSlidingVertical ? true : false;
					// next comes in as percent
					objEffects[id]['min'] = objTheme.menuSlidingStartvalue ? objTheme.menuSlidingStartvalue : 0;
					objEffects[id]['max'] = objTheme.menuSlidingEndvalue ? objTheme.menuSlidingEndvalue : 100;
				}
			} else {
				return;
			}
		};
		
		/**
		 * This initialization is run only once per menu and document load.
		 * At the end execute initializations of any effect related 
		 * parameter.
		 */
		this.initMenuEffects = function (objRef, visibility, objTheme) {
			if (!objRef.mgenEffects) {
				// Load the user params provided by the js_vars.
				this.setUserControlParams( objTheme );
				
				// No object at all? - the object was not initialized 
				// before.
				// Install the mgenEffects object into the dom object. It is 
				// needed for detecting the menu object has been saved and 
				// ready for effects.
				objRef.mgenEffects = {count:0,playing:false};
				
				var objEffects = enugene.themes[objRef.theme].effects;
				var objEffectsIndex = enugene.themes[objRef.theme].effectsIndex;
				for (var i = 0; i < objEffects.length; ++i) {
					// The numeric ONE state causes the effect 
					// elapsedTime and affectVal counter to grow.
					var name = objEffects[i].name;
					var id = objEffectsIndex[name];
					if (!objRef.mgenEffects[name]) {
						objRef.mgenEffects[name] = {};
					}
					if (objRef.mgenEffects[name]) {
						objRef.mgenEffects[name] = {};
						objRef.mgenEffects[name]['elapsedTime'] = 0;
						objRef.mgenEffects[name]['affectVal'] = 0;
						objRef.mgenEffects[name]['closed'] = true;
						objRef.mgenEffects[name]['active'] = false;
						objRef.mgenEffects[name]['state'] = (visibility == 'visible') ? 1 : 0;
					}
					
					// Do this before obj is visible and only once per document load.
					// It shall save the default object styles AFTER all enuGene 
					// settings were done. The saved properties are the point of return 
					// when the effects are closed again.
					this.saveStyles( objRef, name );
				}
			}
		};
		
		/**
		 * CONTROLLER for effect Initialization. 
		 * 
		 * The controller is responsible for effect state and the initialization 
		 * of the basic effect parameter - As also it manages the registration of 
		 * each effect to the dom objects (menu container).
		 * 
		 * The Registration appends a control interface to each menu. - called 
		 * 'mgenEffects' - installed by 'openEffect()'.
		 * 
		 * The 'openEffect()' has a contraire method 'closeEffect()' called by
		 * 'playMenuEffects()', where the registrated effect are remove from 
		 * registration if they 
		 */
		this.menuEffectController = function (objRef, visibility, objTheme) {
			var eid = '';
			var state = visibility == 'visible' ? 1 : 0;
			if (!visibility) visibility = 'hidden';
			
			var objEffects = enugene.themes[objRef.theme].effects;
			var objEffectsIndex = enugene.themes[objRef.theme].effectsIndex;
			// Next comes the basic initialization, only started if 
			// the menu dom object doesn't have a 'mgenEffects' 
			// object cluster. - Generally this is the case at first 
			// initialization of the menu system after basic construction.
			// Executed by setDomProperties() and called by init(). 
			if (!objRef.mgenEffects) {
				this.initMenuEffects( objRef, visibility, objTheme );
				return;
			}
			// If direction will be high, set menu visibility before
			// effects are started. Be aware: Not all menus are set
			// visible - some other menus on update stack are switched off.			
			if (objTheme.menuFadingAllow == true) {
				eid = objEffectsIndex.fading;
				objRef.mgenEffects.fading.state = state;
				if (objRef.mgenEffects.fading.active === true) {
					// Revert the process exchanging the elapsed and unused parts 
					// of the time and affecting value. 
					objRef.mgenEffects.fading.affectVal = 1 - objRef.mgenEffects.fading.affectVal;
					objRef.mgenEffects.fading.elapsedTime = objEffects[eid].duration - objRef.mgenEffects.fading.elapsedTime;
				} else {
					objRef.mgenEffects.fading.affectVal = objEffects[eid].min;
					objRef.mgenEffects.fading.elapsedTime = 0;
					if (state) {
						this.openEffect(objRef, 'fading', visibility);
					}
					objRef.mgenEffects.fading.active = true;
				}
			}

			if (objTheme.menuSlidingAllow) {
				eid = objEffectsIndex.sliding;
				objRef.mgenEffects.sliding.state = state;
				if (objRef.mgenEffects.sliding.active === true) {
					// Revert process
					objRef.mgenEffects.sliding.affectVal = 100 - objRef.mgenEffects.sliding.affectVal;
					objRef.mgenEffects.sliding.elapsedTime = objEffects[eid].duration - objRef.mgenEffects.sliding.elapsedTime;
				} else {
					objRef.mgenEffects.sliding.affectVal = objEffects[eid].min;
					objRef.mgenEffects.sliding.elapsedTime = 0;
					if (state) {
						this.openEffect(objRef, 'sliding', visibility);
					}
					objRef.mgenEffects.sliding.active = true;
				}
				objRef.parentNode.style.overflow = 'hidden';
			}
			
			// Do effects only upon visible objects
			if (objRef.style.visibility == 'visible' && objRef.mgenEffects.playing === false) {
				var menuObjRef = enugene.menus.elements[objRef.id];
				objRef.mgenEffects.playing = true;
				enugene.effects.menu.playMenuEffects( objRef.id, menuObjRef.visibility, new Date().getTime() );
			}
		};
		
	}; // clsMenuEffects
	
} // clsMgenEffects

// //////////////////////////////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////// INIT ON DOCLOAD ////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////////////////////

enugene.asyncTrans = new clsMgenAsyncTrans( );
enugene.asyncTrans.get_usermenu();

// init enugene instance
function mgen_enugeneload(timemark) {
	var mgenClasses = new clsEnugeneKernel( );
	enugene.menus.util = new mgenClasses.clsEnugeneUtil( );
	enugene.menus.currentItem = new mgenClasses.objects.clsCurrentItem( );
	enugene.menus.currentMenu = new mgenClasses.objects.clsCurrentMenu( );
	enugene.menus.savedItem = new mgenClasses.objects.clsSavedItem( );
	enugene.menus.perform = new mgenClasses.clsEnugenePerformer( enugene.menus );
	
	// construction
	enugene.DOM = new clsEnugeneDOM( enugene.menus );
	
	// Item content table values implemented?
	if (enugene.globals.mgen_arrExtensions.ModContent) {
		enugene.DOM.properties = new clsMgenMenuProperties( enugene.menus );
	}
	if (enugene.globals.mgen_arrExtensions.ModEffects) {
		enugene.effects = new clsMgenEffects( );
		enugene.effects.item = new enugene.effects.clsItemEffects( );
		enugene.effects.menu = new enugene.effects.clsMenuEffects( );
	}

	enugene.DOM.constructor.create( document.body );
	
	// init ruler
	if (enugene.globals.mgen_showCursorPosition != 'no') {
		enugene.tools.ruler = new clsMgenRuler( );
		enugene.tools.ruler.startMouseMoveHandler( );
	}
	// init globals
	enugene.globals.menuTimeout = null;
};


