/*****
* 
* FadeMenu
* 
* Description:	fade a list menu recursive with delay
* Author:		Matthias von Deetzen
* Copyright:	CeWe Color AG & Co OhG
* 
*****/

var FadeMenu = new Class({
	initialize: function fadeMenu(elem,options) {

		// Retrieve the element properly
		if ($type(elem) == 'element') {
			this.parentElem = elem;
		}
		else {
			this.parentElem = $(elem);
		}

		if($type(this.parentElem) != 'element') {throw new Error('invalid element or id passed as first argument');}

		// Add the options
		this.options = new Abstract({ // Defaults
			fadeRecursive: false,
			fadeInSpeed: 150,
			fadeOutSpeed: 100,
			fadeOutDelay: 300,
			fadeInDelay: 300,
			ignoreClass: false,
			autoIndent: true
		});
		if($type(options) == 'object') {this.options.extend(options);}

		// Retrieve the child items
		this.menuItems = this.parentElem.getChildren().filterByTag('li');

		// Setup all sub menus
		for(var i=0; i<this.menuItems.length; i++) {

			// Find this item's sub menu
			var subMenu = this.menuItems[i].getElement('ul');

			// If we have a sub menu, set it up
			if($type(subMenu) == 'element') { // Make sure it's an element)
				this.menuItems[i].subMenu = subMenu;
				this.setupSubMenu(subMenu);
				subMenu.create(this.options);
			}
		}
	},

	setupSubMenu: function(subMenu) {
		if($type(subMenu) == 'element') {
			new Abstract(subMenu).extend({
				create: function(options) {
					// Get options
					this.options = options;

					// Retrieve elements
					this.parentElem = this.getParent();

					if (this.options.fadeRecursive) {
						new FadeMenu(subMenu, this.options);
					}

					// Make sure the element and all it's items are hidden
					this.menuItems().setOpacity(0);
					this.setOpacity(0);
					this.setStyles();
					if (this.options.autoIndent) {
						this.autoIndent(subMenu);
					}

					// Create new events for fadein and fadeout
					this.addEvent('fadein',this.showMenu);
					this.addEvent('fadeout',this.hideMenu);

					// Add mouseenter and mouseleave events to the sub menu
					var thisMenu = this;
					this.parentElem.addEvent('mouseenter',function(evt) {thisMenu.latestEvent = 'mouseenter'; thisMenu.fireEvent('fadein',evt,thisMenu.options.fadeInDelay)});
					this.parentElem.addEvent('mouseleave',function(evt) {thisMenu.latestEvent = 'mouseleave'; thisMenu.fireEvent('fadeout',evt,thisMenu.options.fadeOutDelay)});
				},
				showMenu: function(evt) {
					if(this.latestEvent == 'mouseleave') {return false;}
					// Show each item
					this.fadeInQueue = this.menuItems(); // get our menu items
					this.fadeInItems();
				},
				hideMenu: function(evt) {
					if(this.latestEvent == 'mouseenter') {return false;}
					// Hide all items
					this.fadeOutQueue = this.menuItems(); // get out menu items
					this.fadeOutItems();
				},
				fadeInItems: function() {
					// Get the list element
					var thisMenu;
					if(this.element) {thisMenu = this.element.getParent();}
					else {thisMenu = this;}
					// If there are still menu items left, and we're still fading in, fade in the first one
					if(thisMenu.latestEvent == 'mouseenter') {
						thisItem = thisMenu.fadeInQueue.shift();
						// Stop any fade outs going on
						if($defined(thisItem.fadeout)) {thisItem.fadeout.stop();}
						// Check it needs fading in - otherwise move onto the next item
						if(thisItem.getStyle('opacity') < 1) {
							// Fade this item, then chain on to the next
							thisItem.style.zIndex = '10000';
							thisItem.fadein = new Fx.Style(thisItem, 'opacity', {duration: thisMenu.options.fadeInSpeed}).start(thisItem.getStyle('opacity'),1).chain(thisMenu.fadeInItems);
						} else {thisMenu.fadeInItems();}
					} else {return false;}
				},
				fadeOutItems: function() {
					// Get the list element
					var thisMenu;
					if(this.element) {thisMenu = this.element.getParent();}
					else {thisMenu = this;}
					// If there are still menu items left, fade out the last one
					if(thisMenu.fadeOutQueue && thisMenu.fadeOutQueue.length > 0) {
						// If we are still fading out...
						if(thisMenu.latestEvent == 'mouseleave') {
							thisItem = thisMenu.fadeOutQueue.pop();
							// Stop any fade ins going on
							if($defined(thisItem.fadein)) {thisItem.fadein.stop();}
							// Check it needs fading out - otherwise move on
							if(thisItem.getStyle('opacity') > 0) {
								// Fade this item, then chain on to the next
								thisItem.fadeout = new Fx.Style(thisItem, 'opacity', {duration: thisMenu.options.fadeOutSpeed}).start(thisItem.getStyle('opacity'),0).chain(thisMenu.fadeOutItems).chain(thisItem.style.zIndex = '5000');
							} else {thisMenu.fadeOutItems();}
						} else {return false;}
					} else {
						if(thisMenu.latestEvent == 'mouseleave') {thisMenu.setOpacity(0);}
					}
				},
				menuItems: function() {return this.parentElem.getChildren().filterByTag('ul')},
				autoIndent: function(subMenu) {
					if ((is_ie && subMenu.firstChild && subMenu.firstChild.nextSibling && subMenu.childNodes[0].childNodes.length > 0) ||
						(is_moz && subMenu.firstChild && subMenu.firstChild.nextSibling && subMenu.childNodes[0].length > 0))
					{
						if (is_ie)
						{
							var item_width = subMenu.offsetWidth;
							var item_left = subMenu.parentNode.offsetLeft;
							var num_sub_items = subMenu.childNodes.length;
							var sub_item_width = subMenu.childNodes[0].offsetWidth;
							var sub_items_width = 0;
							var sub_item = new Array();
						}
						else {
							var item_width = subMenu.offsetWidth;
							var item_left = subMenu.parentNode.offsetLeft;
							var num_sub_items = subMenu.childNodes.length;
							var sub_item_width = subMenu.childNodes[1].offsetWidth;
							var sub_items_width = 0;
							var sub_item = new Array();
						}

						for (var i = 0; i < num_sub_items; i++)
						{
							if (typeof(subMenu.childNodes[i]) != 'undefined' && subMenu.childNodes[i].tagName == 'LI')
							{
								sub_items_width += subMenu.childNodes[i].offsetWidth;
								sub_item[i] = new Array();
								sub_item[i]['width'] = subMenu.childNodes[i].offsetWidth + 'px'
							}
						}

						if (sub_items_width < item_width)
						{
							var left_pos = (Math.ceil(item_left/sub_item_width) - 1) * (sub_item_width + 15);
							if (left_pos + sub_items_width > item_width) {
								left_pos = left_pos + item_width - (left_pos + sub_items_width) - (num_sub_items * (is_ie ? 24 : 11));
							}

							if (left_pos > 0)
							{
								subMenu.style.paddingLeft = left_pos + 'px';
								subMenu.style.width = item_width - left_pos + 'px';

								for (var i = 0; i < num_sub_items; i++)
								{
									if (typeof(subMenu.childNodes[i]) != 'undefined' && subMenu.childNodes[i].tagName == 'LI')
									{
										subMenu.childNodes[i].style.width = sub_item[i]['width'];
									}
								}
							}
						}
					}
				},
				setStyles: function () {for(var i=0; i<this.menuItems().length; i++){this.menuItems()[i].style.display = 'block';}}
			});
		}
	}
});
