(function() {
	/**
	* The accordionview module provides a widget for managing content in an accordion.
	* @module accordionview
	* @requires yahoo, dom, event, element, animation
	*
	* By Marco van Hylckama Vlieg (marco@i-marco.nl)
	* Some inspiration taken from the YUI TabView widget
	*
	* THIS IS A WORK IN PROGRESS
	*
	* Many, many thanks go out to Daniel Satyam Barreiro!
	* (http://satyam.com.ar/)
	* Without his excellent help and advice this widget would not
	* be half as good as it is now.
	*
	*/
	
	/**
	* A widget to control accordion views.
	* @namespace YAHOO.widget
	* @class AccordionView
	* @extends YAHOO.util.Element
	* @constructor
	* @param {HTMLElement | String} The id of the html 
	* element that represents the AccordionView. 
	* @param {Object} oAttr (optional) A key map of the AccordionView's 
	* initial oAttributes.  
	*/


	var YUD = YAHOO.util.Dom, YUE = YAHOO.util.Event, YUA = YAHOO.util.Anim, YUS = YAHOO.util.Selector;

	var AccordionView = function(el, oAttr) {
		
		el = YUD.get(el);
		
		// some sensible defaults
		
		oAttr = oAttr || {};

		if(!el) {
			el = document.createElement('ul');
			YUD.generateId(el, 'acc-');
		}
		YAHOO.widget.AccordionView.superclass.constructor.call(this, el, oAttr); 
		this.initList(el, oAttr);
		// set defaults
		for(i=0;i<this._configOrder.length;i++) {
			this.set(this._configOrder[i], this.get(this._configOrder[i]));
		}
	};



	YAHOO.widget.AccordionView = AccordionView;

	YAHOO.extend(AccordionView, YAHOO.util.Element, {
		
		// attributeprovider stuff
		
		initAttributes: function (oAttr) {
			AccordionView.superclass.initAttributes.call(this, oAttr);
		 	var bAnimate = (YAHOO.env.modules.animation) ? true : false;	
			this.setAttributeConfig('id', {
		        writeOnce: true,
		        validator: function (value) {
		            return (/^[a-zA-Z_][\w]*$/.test(value));
		        },
		        value: YUD.generateId(),
		        method: function (value) {
		            this.id = value;
		        }
		    });
			this.setAttributeConfig('width', {
				value: '400px',
				method: function (value) {
					this.setStyle('width', value);
					}
				}
			);
			this.setAttributeConfig('animationSpeed', {
				value: 0.7
				}
			);
			this.setAttributeConfig('animate', {
				value: bAnimate,
				validator: YAHOO.lang.isBoolean
				}
			);			
			this.setAttributeConfig('collapsible', {
				value: false,
				validator: YAHOO.lang.isBoolean
				}
			);
			this.setAttributeConfig('expandable', {
				value: false,
				validator: YAHOO.lang.isBoolean
				}
			);
			this.setAttributeConfig('effect', {
				value: YAHOO.util.Easing.easeBoth,
				validator: YAHOO.lang.isString

				}
			);
			this.setAttributeConfig('hoverActivated', {
			        value: false,
			        validator: YAHOO.lang.isBoolean,
			        method: function (value) {
			                if (value) {
			                        YUE.on(this, 'mouseover', this.handleClicks, this, true);                        
			                } else {
			                        YUE.removeListener(this, 'mouseover', this.handleClicks);
			                }        
			        }
			});
			
		}
	});
			
		
	var proto = AccordionView.prototype;
	
	/**
	* The className to add when building from scratch. 
	* NOT used yet
	* @property CLASSNAME
	* @default "yui-accordionview"
	*/
	proto.CLASSNAME = 'yui-accordionview';
	proto.PREFIX = 'yui-accordion-';
	proto.idCounter = '1';
	
	proto.initList = function(el, oAttr) {	
		YUD.addClass(el, this.CLASSNAME);
		el.setAttribute('role', 'tablist');
		var aCollectedItems = [];
		var aListItems = el.getElementsByTagName('LI');

		for(i=0;i<aListItems.length;i++) {
			if(aListItems[i].parentNode.id == el.id) {
                		for (var eHeader = aListItems[i].firstChild; eHeader && eHeader.nodeType != 1; eHeader = eHeader.nextSibling) {
				// This loop looks for the first non-textNode element
				}
				if (eHeader) {
					for (var eContent = eHeader.nextSibling; eContent && eContent .nodeType != 1; eContent = eContent .nextSibling) {
					// here we go for the second non-textNode element, if there was a first one
					}
				aCollectedItems.push({label: eHeader.innerHTML, content: (eContent && eContent.innerHTML)});
				}
			}
		}
		el.innerHTML = '';
		
		this.addPanels(aCollectedItems);
		
		
		//alert('done');
		var aItems = this.collapseAccordion();
		if((oAttr.expandItem === 0) || (oAttr.expandItem > 1)) {			
			YUD.removeClass(aItems[oAttr.expandItem], 'hidden');			
			var l = YUD.getElementsByClassName('yui-accordion-toggle', 'a', this)[oAttr.expandItem];
			var c = YUD.getElementsByClassName('yui-accordion-content', 'div', this)[oAttr.expandItem];
			YUD.addClass(l, 'active');
			l.setAttribute('aria-pressed', 'true');
			c.setAttribute('aria-hidden', 'false');
			
		}
		if(true === this.get('hoverActivated')) {
			YUE.on(el, 'mouseover', this.handleClicks, this, true);			
			YUE.on(el, 'click', this.handleClicks, this, true);
		}
		else {
			YUE.on(el, 'click', this.handleClicks, this, true);
		}		
	};

	proto.collapseAccordion = function() {

		aItems = YUD.getElementsByClassName('yui-accordion-content' ,'div', this);		
		YUD.batch(aItems, function(e) {
			if(!YUD.hasClass(this.parentNode, 'yui-accordion-content')) { 
				YUD.removeClass(e.parentNode.firstChild, 'active');
				YUD.addClass(e, 'hidden');
				e.setAttribute('aria-hidden', 'true');
			}
		}, this);
		
		return aItems;
	};

	/**
	* Adds an Accordion panel to the AccordionView instance.  
	* If no index is specified, the panel is added to the end of the tab list.
	* @method addPanel
	* @param {Object} oAttr A key map of the Panel's properties
	* @param {Integer} nIndex The position to add the tab. 
	* @return void
	*/

	proto.addPanel = function(oAttr, nIndex) {
		var oPanelParent = document.createElement('li');
		YUD.addClass(oPanelParent, this.PREFIX + 'panel');
		var elPanelLink = oPanelParent.appendChild(document.createElement('a'));
		elPanelLink.id = this.get('element').id + '-' + this.idCounter + '-label';
		this.idCounter++;
		elPanelLink.setAttribute('role', 'tab');
		var elIndicator = document.createElement('span');
		YUD.addClass(elIndicator, 'indicator');
		elPanelLink.innerHTML = oAttr.label || '';
		elPanelLink.appendChild(elIndicator);		
		YUD.addClass(elPanelLink, this.PREFIX + 'toggle');
		elPanelLink.href = oAttr.href || '#toggle';
		var elPanelContent = document.createElement('div');
		elPanelContent.setAttribute('role', 'tabpanel');
		elPanelContent.innerHTML = oAttr.content || '';
		elPanelContent.setAttribute('aria-labelledby', elPanelLink.id);
		YUD.addClass(elPanelContent, this.PREFIX + 'content');
		oPanelParent.appendChild(elPanelContent);
		
		if((nIndex !== null) && (nIndex !== undefined)) {
			var panelBefore = this.getPanel(nIndex);
			this.insertBefore(oPanelParent, panelBefore);
		}
		else {
			this.appendChild(oPanelParent);
		}

		if(oAttr.expand) {
			this.collapseAccordion();
			YUD.removeClass(elPanelContent, 'hidden');
			YUD.addClass(elPanelLink, 'active');
			elPanelContent.setAttribute('aria-hidden', 'false');
			elPanelLink.setAttribute('aria-pressed', 'true');
		}
		else {
			YUD.addClass(elPanelContent, 'hidden');
			elPanelContent.setAttribute('aria-hidden', 'true');
			elPanelLink.setAttribute('aria-pressed', 'false');
		}
	};

	proto.addPanels = function(oPanels) {
		for(var i=0;i<oPanels.length;i++) {
			this.addPanel(oPanels[i]);
		}
	};

	/**
	* Removes the specified Panel from the AccordionView.
	* @method removePanel
	* @param {Integer} index of the panel to be removed
	* @return void
	*/

	proto.removePanel = function(index) {
		this.removeChild(YUD.getElementsByClassName('yui-accordion-panel', 'li', this)[index]);		
	};

	/**
	* Returns the HTMLElement of the panel at the specified index.
	* @method getPanel
	* @param {Integer} nIndex The position of the Panel.
	* @return HTMLElement
	*/

	proto.getPanel = function(nIndex) {
		var aPanels = YUD.getElementsByClassName('yui-accordion-panel', 'li', this);
		return aPanels[nIndex];
	};

	/**
	* Event handler for the AccordionView
	* We only need to handle clicks for an AccordionView
	* @method handleClicks
	* @param {event} ev The Dom event that is being handled.
	* @param {Object} oAttr The oAttributes for this AccordionView
	* @return void
	*/

	proto.handleClicks = function(ev) {
		YUE.stopPropagation(ev);			

		var elClickedNode = YUE.getTarget(ev);
		if(!YUD.hasClass(elClickedNode, 'indicator') && !YUD.hasClass(elClickedNode, 'yui-accordion-toggle') && !YUD.hasClass(elClickedNode, 'yui-accordion-panel')) {
			return true;	
		}

		function iezoom(el, sZoom) {
			if(YAHOO.env.ua.ie < 7 && YAHOO.env.ua.ie > 0) {
				var aInnerAccordions = YUD.getElementsByClassName('yui-accordionview', 'ul', el);
					if(aInnerAccordions[0]) {
						YUD.setStyle(aInnerAccordions[0], 'zoom', sZoom);
					}
				}
			}
		function iehide(el, sHide) {
			if(YAHOO.env.ua.ie < 7 && YAHOO.env.ua.ie > 0) {
				var aInnerAccordions = YUD.getElementsByClassName('yui-accordionview', 'ul', el);
					if(aInnerAccordions[0]) {
						YUD.setStyle(aInnerAccordions[0], 'visibility', sHide);
					}
				}
		}

		function toggleItem(el, elClicked) {			
			if(!elClicked) {
				if(!el) { return false ;}
				elClicked = el.parentNode.firstChild;
			}
			var oOptions = {};
			var bHideAfter = false;
			var nHeight = 0;
			if(YUD.hasClass(el, 'hidden')) {

				// still a bit experimental. trying to eliminate mild flash sometimes seen in FF //

				YUD.setStyle(el, 'display', 'block');
				YUD.addClass(el, 'almosthidden');
				YUD.removeClass(el, 'hidden');
				nHeight = el.offsetHeight;
				YUD.setStyle(el, 'height', 0);
				YUD.removeClass(el, 'almosthidden');
				oOptions = {height: {from: 0, to: nHeight}};
			}
			else {
				nHeight = el.offsetHeight;
				oOptions = {height: {from: nHeight, to: 0}};
				bHideAfter = true;
			}
			if(this.get('animate')) {
				var nSpeed = (this.get('animationSpeed')) ? this.get('animationSpeed') : 0.5;
				var sEffect = (this.get('effect')) ? this.get('effect') : YAHOO.util.Easing.easeBoth;
				var oAnimator = new YUA(el, oOptions, nSpeed, sEffect);
				if(bHideAfter) {
					YUD.removeClass(elClicked, 'active');
					iehide(el, 'hidden');
					el.setAttribute('aria-hidden', 'true');
					elClicked.setAttribute('aria-pressed', 'false');
					oAnimator.onComplete.subscribe(function(){
						YUD.addClass(el, 'hidden');
						YUD.setStyle(el, 'height', 'auto');
						YUD.setStyle(el, 'display', 'none');
						iezoom(el, 'normal');
					});
				}
				else {
					//changed from visible to hidden so it doesn't show up behind the parent accordion until after the animation
					iehide(el, 'hidden');
					oAnimator.onComplete.subscribe(function(){
						YUD.setStyle(el, 'height', 'auto');
						iezoom(el, '1');
						//Added to make the inner accordion visible again
						iehide(el, 'visible');
						el.setAttribute('aria-hidden', 'false');
						elClicked.setAttribute('aria-pressed', 'true');
					});					
					YUD.addClass(elClicked, 'active');
				}
				oAnimator.animate();
			}
			else {
				if(bHideAfter) {
					YUD.addClass(el, 'hidden');
					YUD.setStyle(el, 'height', 'auto');
					YUD.setStyle(el, 'display', 'none');
					YUD.removeClass(elClicked, 'active');
					el.setAttribute('aria-hidden', 'true');
					elClicked.setAttribute('aria-pressed', 'false');
				}
				else {
					YUD.removeClass(el, 'hidden');
					YUD.setStyle(el, 'height', 'auto');
					YUD.addClass(elClicked, 'active');
					el.setAttribute('aria-hidden', 'false');
					elClicked.setAttribute('aria-pressed', 'true');
				}
			}
			return true;
		}
		
		var eTargetListNode = (elClickedNode.nodeName.toUpperCase() == 'SPAN') ? elClickedNode.parentNode.parentNode : elClickedNode.parentNode;
		
		var containedPanel = YUD.getElementsByClassName('yui-accordion-content', 'div', eTargetListNode)[0]; 

		if(this.get('collapsible') === false) {
			if (!YUD.hasClass(containedPanel, 'hidden')) {
				YUE.preventDefault(ev);
				return false;
			}
		}
		else {
			if(!YUD.hasClass(containedPanel, 'hidden')) {
				toggleItem.call(this, containedPanel);
				YUE.preventDefault(ev);
				return false;				
			}
		}

		if(this.get('expandable') !== true) {
			var aPanelCollection = YUD.getElementsByClassName('yui-accordion-content', 'div', this);

			// skip panels within a panel

			for(var element in aPanelCollection) {
				if(this.get('element').id == aPanelCollection[element].parentNode.parentNode.id) {
					var bMustToggle = YUD.hasClass(aPanelCollection[element], 'hidden');
					if(!bMustToggle) {
						toggleItem.call(this,aPanelCollection[element]);
					}
				}
			}
		}
		if(elClickedNode.nodeName.toUpperCase() == 'SPAN')  {
			toggleItem.call(this, containedPanel, elClickedNode.parentNode);
		}
		else {
			toggleItem.call(this, containedPanel, elClickedNode);
		}
		
		YUE.preventDefault(ev);
		return true;
	};

	/**
	* Provides a readable name for the AccordionView instance.
	* @method toString
	* @return String
	*/
	proto.toString = function() {
		var name = this.get('id') || this.get('tagName');
		return "AccordionView " + name; 
	};
})();
YAHOO.register("accordionview", YAHOO.widget.AccordionView, {version: "0.99", build: "13"});

