/**
* YUI-Based Accordion Menu Item
* 
* @author Donald J. Sipe <donald.sipe@newsobserver.com>
* @version 1.0b
* @copyright 2007 - News & Observer Publishing Company
*/

YAHOO.namespace("NAOwidget");

(function() {
	
	var Dom   = YAHOO.util.Dom;
	var Event = YAHOO.util.Event;
	var Anim  = YAHOO.util.Anim;
	
	/**
	 * A widget to control an "accordion" menu item
	 * 
	 * @namespace YAHOO.djsWidget 
	 * @constructor
	 * @param {HTMLElement | String} container  The HTML element that contains
	 * the menu item.
	 */
	YAHOO.NAOwidget.AccordionItem = function (container, height)
	{
		this._containerEl = Dom.get(container);
		
		// Extract head elements
		var hEls = Dom.getElementsByClassName(this.HEAD_CLASSNAME, "*", this._containerEl);
		if (hEls.length > 0)
		{
			this._headEl = hEls[0]; // Use the first match
		}
		
		// Extract body elements
		var bEls = Dom.getElementsByClassName(this.BODY_CLASSNAME, "*", this._containerEl);
		if (bEls.length > 0)
		{
			this._bodyEl = bEls[0]; // Use the first match
		}
		
		
		if (YAHOO.lang.isNumber(height))
		{
			this.animConfig.value = height;
		}
		
		// If the item has the class "selected" it's considered open
		this._isOpen = Dom.hasClass(this._containerEl, "selected"); 
		
		
		// Collapse body element if this item is closed
		if (this._isOpen === false)
		{
			Dom.setStyle(this._bodyEl, "height",  "1px"); 
		}
		else
		{
			Dom.setStyle(this._bodyEl, "height",  this.animConfig.value + this.animConfig.unit); 
		}
		
		
		Dom.setStyle(this._containerEl, "overflow", "hidden");
		Dom.setStyle(this._bodyEl, "overflow", "hidden");
	
	
		// Create Custom Events
		this.openEvent  		= new YAHOO.util.CustomEvent("openEvent", 		this, true);
		this.afterOpenEvent 	= new YAHOO.util.CustomEvent("afterOpenEvent", 	this, true);
		this.closeEvent 		= new YAHOO.util.CustomEvent("closeEvent", 		this, true); 
		this.afterCloseEvent 	= new YAHOO.util.CustomEvent("afterCloseEvent",	this, true); 
	
		
		
		// Subscribe to open and close events
		this.openEvent.subscribe(this.onOpen, this);
		this.closeEvent.subscribe(this.onClose, this);
		
		this.afterOpenEvent.subscribe(this.onAfterOpen, this);
		this.afterCloseEvent.subscribe(this.onAfterClose, this);
		
		// Add toggle behavior to head element
		Event.addListener(this._headEl, "click", this.onClick, this, true);
		Event.addListener(this._headEl, "mouseover", this.onMouseOver, this, true);
		Event.addListener(this._headEl, "mouseout", this.onMouseOut, this, true);
		
		
	
	};
	
	
	
	
	var proto = YAHOO.NAOwidget.AccordionItem.prototype;
	
	
	
		
	/**
	 * The class name of the HTMLElement containing the clickable heading. 
	 * Clicking this heading will hide and show the body HTMLElement.
	 * @property HEAD_CLASSNAME
	 */
	proto.HEAD_CLASSNAME = "nao-am-item-hd";
	
	
	
	
	/**
	 * The class name of the body text that will hidden and shown when a user 
	 * clicks on a menu item's heading.
	 * @property BODY_CLASSNAME
	 */	
	proto.BODY_CLASSNAME = "nao-am-item-bd";
	

	
	proto._containerEl 	= null;
	proto._headEl 		= null;
	proto._bodyEl 		= null;
	
	
	
	
	proto._isOpen 		= false;
	
	/**
	 * Timeout Delay
	 * 
	 * Amount of time (in miliseconds) to delay transitioning the accordion 
	 * menu items.
	 * 
	 * @property timeoutDelay
	 */
	proto.timeoutDelay = 300; 
	
	
	/**
	 * Timeout Instance
	 * 
	 * Instance of timeout object.
	 */
	proto._timeoutId		= null;
	
	
	proto.animConfig = {
		value: 150,
		unit: "px",
		duration: 0.3,
		easing: YAHOO.util.Easing.easeIn
	};
	
	
		
	proto.onMouseOver = function () 
	{
		me = this;
		
		function fireOpenEvent()
		{
			me.open();
		}
		
		this._timeoutId = window.setTimeout(fireOpenEvent, this.timeoutDelay);
	};
	
	
	
	
	proto.onMouseOut = function ()
	{
		window.clearTimeout(this._timeoutId);	
	};
	
	
	
	proto.onClick = function () 
	{
		this.onMouseOut();
		this.open();
	};
	
	
	
	proto.open = function ()
	{
		if (this._isOpen === true)
		{
			return;
		}
		this.openEvent.fire();
	};
	
	
	proto.close = function ()
	{
		if (this._isOpen === false) 
		{
			return;
		}
		this.closeEvent.fire();
	};
	
	
	
	
	
	/**
	 * Open Event 
	 * 
	 * This custom event can be subscribed to.
	 */
	proto.openEvent  = null;
	
	
	
	
	
	
	/**
	 * After Open Event
	 * 
	 */
	proto.afterOpenEvent = null;
	
	
	
	
	
	/**
	 * Close Event
	 * 
	 * This custom event can be subscribed to.
	 */
	proto.closeEvent = null; 
	
	
	
	
	
	
	/**
	 * After Close Event
	 * 
	 * This custom event can be subscribed to.
	 */
	proto.afterCloseEvent = null; 
	
	
	
	
	
	/**
	 * On Open Event Handler
	 * 
	 * Fired when the menu item is opened 
	 * 
	 * @param {String} type
	 * @param {mixed} 	args
	 * @param {Object} me
	 */
	proto.onOpen = function (type, args, me)
	{
		var c = me.animConfig;
		var animProp = {
			height:{
				from: 	1,
				to: 	c.value
			}
		};
		
		Dom.setStyle(me._bodyEl, "height", "1px");
		Dom.setStyle(me._bodyEl, "display", "block");
		
		
		var anim = new YAHOO.util.Anim(me._bodyEl, animProp, c.duration);
		
		anim.onComplete.subscribe(function() {me.afterOpenEvent.fire();});
		
		me._isOpen = true;

		anim.animate();
	};
	
	
	
	
	
	/**
	 * On Close Event Handler
	 * 
	 * Fired when the menu item is closed
	 * 
	 * @param {String} type
	 * @param {mixed} args
	 * @param {Object} me
	 */
	proto.onClose = function (type, args, me)
	{
		var c = me.animConfig;
		var animProp = {
			height: {
				to: 1	
			}
		};
		
		var animObj = new YAHOO.util.Anim(me._bodyEl, animProp, c.duration);
		
		animObj.onComplete.subscribe(function(){me.afterCloseEvent.fire();});
		
		me._isOpen = false;
		
		animObj.animate();
	};
	
	
	
	
	proto.onAfterOpen = function (type, args, me)
	{
		Dom.addClass(me._containerEl, "selected");
	};
	
	
	
	proto.onAfterClose = function (type, args, me)
	{
		Dom.removeClass(me._containerEl, "selected");
		Dom.setStyle(me._bodyEl, "height",  "1px");
	};


})();