/*====================================*\
|| ################################## ||
|| # iDeal 2.0 Ajax Core            # ||
|| # ------------------------------ # ||
|| # Copyright ©2008 MediaPulse     # ||
|| # ------------------------------ # ||
|| # Revision Alpha                 # ||
|| ################################## ||
\*====================================*/

/**
 * Menu controller. Groups multiple pop ups together as a menu.
 */
iDeal.Menu = Class.create({
	/**
	 * Array of all popups managed by this menu object.
	 *
	 * @var array
	 * @access protected
	 */
	_menus: new Array(),
	
	/**
	 * Array of all open popups managed by this menu object.
	 *
	 * @var array
	 * @access protected
	 */
	_openMenus: new Array(),

	/**
	 * Cache of the appear method of the next menu to appear. Note
	 * that being able to do this is a weird side effect of how
	 * prototype framework emulates class inherits - the function object we
	 * are caching here belongs to the parent of the menu popup child class
	 * and wouldn't normally be callable in a normal OO setup.
	 *
	 * @var function object
	 * @access protected
	 */
	_appearAfter: null,
	
	_appearInProgress: false,
	
	/**
	 * Constructor
	 *
	 * @param list element to be made a menu object
	 * @param string class used to label the trigger elements within the list
	 * @param object parameters to pass onto the popup elements to control their settings.
	 *
	 * @access public
	 * @return Menu Object
	 */
	initialize: function( list, trigger, params )
	{
		list = $(list);
		
		list.select(trigger).each(function(s){
			params.target = s;
			this._menus.push( new iDeal.MenuPopUp( this, params ));
		}.bind(this));
	},
	

	/**
	 * Hide all menus, then fire the appear method provided by the popup class
	 * so that it can complete it's appearance transition.
	 *
	 * @param object the popup that called this function.
	 * @param function the $super function that needs to be called once all other menus are hidden.
	 *
	 * @return void
	 * @access public
	 */
	hideOthers: function ( menu, appear )
	{
		if (this._openMenus.length > 0)
		{
			this._appearAfter = appear;
			
			while (menu = this._openMenus.pop())
			{
				menu.hide();				
			}
		}
		else
		{
			appear();
		}
	},
	
	/**
	 * Register the provided popup object as being in the open state.
	 *
	 * @param object to register
	 *
	 * @return void
	 * @access public
	 */	 
	registerOpen: function ( obj )
	{
		this._openMenus.push(obj);	
		this._appearAfter = null;
	},
	
	/**
	 * Register the provided popup object as closed (deleting it from the openMenus array),
	 * then fire any appearance that is waiting.
	 *
	 * @param object object to register
	 *
	 * @return void
	 * @access public
	 */
	registerClosed: function ( obj )
	{
		this._openMenus = this._openMenus.reject(function(o) { return o == obj; }.bind(this));
		
		if (this._appearAfter && this._openMenus.length == 0)
		{
			this._appearAfter();
		}
	}
});

/**
 * Menu pop up - extends basic pop up class.
 */
iDeal.MenuPopUp = Class.create( iDeal.PopUp, {
	/**
	 * Reference to the menu controller object.
	 *
	 * @var object
	 * @access protected
	 */
	_parent: null,
	
	/**
	 * Constructor. Here we just attach our parent param then run the super method.
	 *
	 * @param object the parent object
	 * @params object the parameters (see parent class for full description)
	 *
	 * @return object
	 * @access public
	 */
	initialize: function ( $super, parent, params ) {
		this._parent = parent;
		$super(params);
	},
	
	/**
	 * Appear the menu popup, hiding the other menus first.
	 */
	appear: function($super)
	{
		if (!this._parent.appearInProgress)
		{
			this._parent.appearInProgress = true;
			this._parent.hideOthers( this, $super );	
		}
	},
	
	/**
	 * Appearance complete - here we register ourselves as being open.
	 */
	_appearCompleteProto: function($super)
	{
		$super();
		this._parent.appearInProgress = false;
		this._parent.registerOpen(this);
	},
	
	/**
	 * Hide complete - here we register ourselves as being closed.
	 */
	_hideCompleteProto: function($super)
	{
		$super();
		this._parent.registerClosed(this);
	}
});