/*______________
|       ______  |   U I Z E     J A V A S C R I P T     A P I
|     /      /  |   -----------------------------------------
|    /    O /   |    MODULE : Uize.Widget.Tree.Menu Class (version 1.1.0)
|   /    / /    |    AUTHOR : Chris van Rensburg (http://www.tomkidding.com)
|  /    / /  /| |    ONLINE : http://www.tomkidding.com/uize/uize-js-api
| /____/ /__/_| | COPYRIGHT : (c)2008 UIZE
|          /___ |   LICENSE : Distributed under the terms of the GNU General Public License
|_______________|             http://www.gnu.org/licenses/gpl.txt
*/

/*
	DESCRIPTION
		Implements a JavaScript class for drop down menus

	REQUIRES
		- Uize.Widget.Tree.js (base class)

	TO DO
		- build submenus dynamically -- only when needed (for load performance optimization)

		- move to using UL/LI for markup
		- make highlight of active menu items "sticky" (ie. not based on a:hover pseudoclass), so that entire choice path can be indicated
		- support for heading items
*/

/*ScruncherSettings Mappings="=d" LineCompacting="TRUE"*/

Uize.module ({
	name:'Uize.Widget.Tree.Menu',
	required:'Uize.Node',
	builder:function (_superclass) {
		var
			_undefined,
			_true = true,
			_false = false,
			_Uize_Node = Uize.Node,
			_pathToResources = Uize.pathToResources + 'Uize_Widget_Tree_Menu/'
		;

		/*** Object Constructor ***/
			var
				_class = _superclass.subclass (),
				_classPrototype = _class.prototype
			;

		/*** Private Instance Methods ***/
			_classPrototype._getItemClassName = function (_item,_depth) {
				var _this = this;
				return (
					(_depth ? _this._subMenuItemCssClass : _this._menuItemCssClass) +
					(
						_item.expanded
							? (' ' + (_depth ? _this._subMenuItemActiveCssClass : _this._menuItemActiveCssClass))
							: ''
					) +
					(
						_item.items && _item.items.length
							? (
								' ' +
								(
									_depth
										? _this._subMenuItemChildrenIndicatorCssClass
										: _this._menuItemChildrenIndicatorCssClass
								)
							)
							: ''
					)
				);
			};

		/*** Public Instance Methods ***/
			_classPrototype.setItemExpanded = function (_itemSpecifier,_expanded) {
				var
					_this = this,
					_item = _this.getItemFromSpecifier (_itemSpecifier),
					_depth = _itemSpecifier.split (_this.get ('itemDelimiter')).length - 1,
					_hasChildren = _item.items && _item.items.length
				;
				if (typeof _expanded != 'boolean') _expanded = _item.expanded === _false;
				if (_expanded != _item.expanded) {
					_item.expanded = _expanded;
					_this.setNodeProperties (
						_itemSpecifier + 'TitleLink',
						{className:_this._getItemClassName (_item,_depth)}
					);
					if (_hasChildren) {
						var _itemChildrenNode = _this.getNode (_itemSpecifier + 'Children');
						_this.displayNode (_itemChildrenNode,_expanded);
						if (_expanded) {
							/*** move submenu node to root of document, if necessary ***/
								var _docBody = document.body;
								if (_itemChildrenNode.parentNode != _docBody)
									_docBody.appendChild (_itemChildrenNode)
								;
		
							/*** position the submenu ***/
								var _itemCoords = _Uize_Node.getCoords (_this.getNode (_itemSpecifier + 'TitleLink'));
								/*
								alert ([
									_this.getNode (_itemSpecifier + 'TitleLink').offsetTop,
									_this.getNode (_itemSpecifier + 'TitleLink').offsetParent.offsetTop,
								]);
								*/

								_Uize_Node.setAbsPos (
									_itemChildrenNode,
									{
										left:(_itemCoords.left + _itemCoords.right) >> 1,
										top:(_itemCoords.top + _itemCoords.bottom) >> 1
									},
									{
										x:(_itemCoords.width >> 1) * (_depth ? 1 : -1),
										y:(_itemCoords.height >> 1) * (_depth ? -1 : 1)
									}
								);
						}
					}
				}
			};

			_classPrototype.wireUi = function () {
				var _this = this;
				if (!_this.wired ()) {
					/*** code for managing dismiss when mousing out of the menu ***/
						/* NOTE:
							sure, you could have more anonymous functions in this code, but sharing a single reference across all occurrences should provide better performance
						*/
						var _dismissTimeout;
						function _clearDismissTimeout () {
							if (_dismissTimeout) {
								clearTimeout (_dismissTimeout);
								_dismissTimeout = _undefined;
							}
						}
						function _dismiss () {
							_this.setExpandedDepth (0);
						}
						function _setDismissTimeout () {
							_clearDismissTimeout ();
							_dismissTimeout = setTimeout (_dismiss,_this._dismissDelay);
						}
						function _wireMenuShellEvents (_node) {
							_this.wireNodeEvents (
								_node,
								{
									onmouseover:_clearDismissTimeout,
									onmouseout:_setDismissTimeout
								}
							);
						}

					_this.traverseTree ({
						itemHandler:
							function (_item,_itemSpecifier) {
								_this.wireNodeEvent (
									_itemSpecifier + 'TitleLink',
									'onmouseover',
									function () {_this.collapseAllBut (_itemSpecifier)}
								);
							},
						beforeSubItemsHandler:
							function (_item,_itemSpecifier) {
								_wireMenuShellEvents (_itemSpecifier + 'Children');
							}
					});
					_wireMenuShellEvents ('');

					_superclass.prototype.wireUi.call (_this);
				}
			};

		/*** Setup Properties ***/
			_class.registerProperties ({
				_dismissDelay:{
					name:'dismissDelay',
					value:400
				},
				_menuCssClass:'menuCssClass',
				_menuDividerClass:'menuDividerClass',
				_menuItemActiveCssClass:'menuItemActiveCssClass',
				_menuItemChildrenIndicatorCssClass:'menuItemChildrenIndicatorCssClass',
				_menuItemCssClass:'menuItemCssClass',
				_subMenuCssClass:'subMenuCssClass',
				_subMenuDividerClass:'subMenuDividerClass',
				_subMenuItemActiveCssClass:'subMenuItemActiveCssClass',
				_subMenuItemChildrenIndicatorCssClass:'subMenuItemChildrenIndicatorCssClass',
				_subMenuItemCssClass:'subMenuItemCssClass'
			});

		/*** Override Initial Values for Inherited Set-Get Properties ***/
			_class.set ({
				html:function () {
					var
						_this = this,
						_html = '',
						_itemDelimiter = _this.get ('itemDelimiter'),
						_blankImageUrl = _class.getBlankImageUrl ()
					;
					_this.traverseTree ({
						itemHandler:
							function (_item,_itemSpecifier,_depth) {
								var
									_itemItems = _item.items,
									_itemTitle = _item.title
								;
								_html += _itemTitle == '-' && !(_itemItems && _itemItems.length)
									? (
										'<div class="' + (_depth ? _this._subMenuDividerClass : _this._menuDividerClass) + '" href="javascript://">&nbsp;</div>'
									) : (
										'<a id="[#idPrefix]-' + _itemSpecifier + 'TitleLink" class="' + _this._getItemClassName (_item,_depth) + '" href="' + (_item.link || 'javascript://') + '">' + _itemTitle + '</a>'
									)
								;
							},
						beforeSubItemsHandler:
							function (_item,_itemSpecifier,_depth) {
								_html += '<div id="[#idPrefix]-' + _itemSpecifier + 'Children" class="' + _this._subMenuCssClass + '">';
							},
						afterSubItemsHandler:function () {_html += '</div>\n'}
					});
					return (
						'<div id="[#idPrefix]" class="' + _this._menuCssClass + '">' +
						_html +
						'<br style="clear:both;"/>' +
						'</div>\n'
					);
				}
			});

		return _class;
	}
});


