(function() {

	var $$ = YAHOO.util.Selector.query;
	var DOM = YAHOO.util.Dom;
	var Anim = YAHOO.util.Anim;
	var Event = YAHOO.util.Event;
	
	// custom helper functions
	DOM.getPreviousSiblingByTagName = function(element, tagName) {
		return DOM.getPreviousSiblingBy(element, function(el) { return el.tagName.toLowerCase() == tagName.toLowerCase(); });
	};

	DOM.getNextSiblingByTagName = function(element, tagName) {
		return DOM.getNextSiblingBy(element, function(el) { return el.tagName.toLowerCase() == tagName.toLowerCase(); });
	};

	DOM.getFirstChildByTagName = function(element, tagName) {
		return DOM.getFirstChildBy(element, function(el) { return el.tagName.toLowerCase() == tagName.toLowerCase(); });
	};
	
	YAHOO.namespace("Apollo");
	
	// flyout menu constructor
	
	var CascadeMenu = function(element, oConfigs) {

		CascadeMenu.superclass.constructor.call(this, element, oConfigs);
		
		this.openMenuItems = {};
		
		// check for any open menus
		this._detectOpenMenuItems();
		
		this.on("click", this._menuOnClick);
	};
	
	YAHOO.lang.extend(CascadeMenu, YAHOO.util.Element, {

        initAttributes: function (oAttr) {
            CascadeMenu.superclass.initAttributes.call(this, oAttr);
			
			this.setAttributeConfig('durationOpen', {
                value: 0.4,
                validator: YAHOO.lang.isFloat
            });

			this.setAttributeConfig('blurAfterClick', {
                value: true,
                validator: YAHOO.lang.isBoolean
            });

			this.setAttributeConfig('durationClose', {
                value: 0.4,
                validator: YAHOO.lang.isFloat
            });

			this.setAttributeConfig('openClassName', {
                value: 'open',
                validator: YAHOO.lang.isString
            });

			this.setAttributeConfig('oneMenuPerLevel', {
                value: true,
                validator: YAHOO.lang.isBoolean
            });
            
		},

		_menuOnClick: function(e) {
			
			var target = Event.getTarget(e);
			
			this._applyDivWrap(target);
			
			// now get the sub-menu div element
			if (menu = this._getMenu(target))
			{
				// check the state
				if (DOM.hasClass(target, this.get("openClassName")))
				{
					// close the sub menu
					this.closeMenu(target);
				}
				else
				{
					// open the sub menu
					this.openMenu(target);
				}
				
				Event.preventDefault(e);
			}	
			
			if (this.get("blurAfterClick") && target.blur)
			{
				target.blur();
			}
		},
		
		_applyDivWrap: function(menuItem) {
			
			// see if there is a div that wraps the sub menu as a sibling, if not create one (allows us to preserve the current markup)
			
			var menu = this._getMenu(menuItem);
			var parentMenuItem = DOM.getAncestorByTagName(menuItem, "li");
			
			if (!menu)
			{
				if (menuList = DOM.getNextSiblingByTagName(menuItem, "ul"))
				{
					var menu = document.createElement("div");
					parentMenuItem.removeChild(menuList);
					menu.appendChild(menuList);
					parentMenuItem.appendChild(menu);
				}
			}
		},
		
		closeMenu: function(menuItem) {

			var menu = this._getMenu(menuItem);

			var menuList = this._getMenuList(menu);
			var menuDepth = this._getMenuDepth(menuItem);

			
			this.closingMenu = menu;
			this.closingMenuItem = menuItem;
			
			menu.style.overflow = "hidden";
			menuList.style.display = "block";
			
			var closeAnimation = new Anim(menu, { height: { from: menuList.offsetHeight, to: 0 } }, this.get("durationClose"), YAHOO.util.Easing.easeOut );
			closeAnimation.onComplete.subscribe(this._closeAnimationOnComplete, this, true);
			closeAnimation.animate();

			DOM.removeClass(menuItem, this.get("openClassName"));
		},
		
		_closeAnimationOnComplete: function(e) {
			if (this.closingMenu)
			{
				this.closingMenu.style.display = "none";
				this.closingMenu.style.overflow = "visible";
			}
			
			this.closingMenu = null;
			this.closingMenuItem = null;
		},
		
		openMenu: function(menuItem) {
			
			var menu = this._getMenu(menuItem);
			var menuList = this._getMenuList(menu);
			var menuDepth = this._getMenuDepth(menuItem);
			
			if (this.openMenuItems[menuDepth] && this.openMenuItems[menuDepth] != menuItem && this.get("oneMenuPerLevel"))
			{
				// close the active menu at this level
				this.closeMenu(this.openMenuItems[menuDepth]);
			}
			
			this.openingMenu = menu;
			this.openingMenuItem = menuItem;
			this.openMenuItems[menuDepth] = menuItem;
			
			menu.style.overflow = "hidden";
			menu.style.height = "1px";
			
			menu.style.display = "block";
			menuList.style.display = "block";
			
			// open the sub menu
			var openAnimation = new Anim(menu, { height: { from: 1, to: menuList.offsetHeight } }, this.get("durationOpen"), YAHOO.util.Easing.easeIn );
			openAnimation.onComplete.subscribe(this._openAnimationOnComplete, this, true);
			openAnimation.animate();
			
			DOM.addClass(menuItem, this.get("openClassName"));
		},
		
		_openAnimationOnComplete: function(e)
		{
			if (this.openingMenu)
			{
				this.openingMenu.style.overflow = "visible";				
				this.openingMenu.style.height = "auto";		
			}

			this.openingMenu = null;
			this.openingMenuItem = null;
		},
		
		_getMenuDepth: function(menuItem) {
			
			var count = 1;
			var parentMenu = DOM.getAncestorByTagName(menuItem, "ul");
			
			while (parentMenu && parentMenu != this.get("element"))
			{
				count++;
				parentMenu = DOM.getAncestorByTagName(parentMenu, "ul");
			}

			return count;
		},
		
		_getMenu: function(menuItem) {
			return DOM.getNextSiblingByTagName(menuItem, "div");
		},
		
		_getMenuList: function(menu) {
			return DOM.getFirstChildByTagName(menu, "ul");
		},
		
		_detectOpenMenuItems: function() {
			var openMenuItems = $$("ul li a." + this.get("openClassName"), this.get("element"));
			
			for (i in openMenuItems)
			{
				var openMenuItem = openMenuItems[i];
				
				this._applyDivWrap(openMenuItem);
				
				var openMenuDepth = this._getMenuDepth(openMenuItem);
				
				this.openMenuItems[openMenuDepth] = openMenuItem;
			}
			
		}
	});

	YAHOO.Apollo.CascadeMenu = CascadeMenu;
})();


YAHOO.register("flyout-menu", YAHOO.Apollo.FlyoutMenu, {version: "1.00", build: "00"});


	YAHOO.util.Event.onDOMReady(
		
		function(event)
		{
		    
			var cascadeMenu = new YAHOO.Apollo.CascadeMenu('side-menu');
		}
	
	);	
