
/**
 * Standard-Navi
 * Liste von Menues mit optionalen Submenues. 
 * Maus- und Tastatursteuerung.
 * 
 * @author Niels Bobogk <n.bobogk@i-d.de>
 */
(function(Controls){
	Controls.Menu = Class.create(iD, {	
		NAME: "iD.UI.Controls.Menu",
		
		/**
		 * Konstruktor
		 * - Initialisiert alle Anker und Listen
		 * - registriert Events
		 *
		 * @param {Object} container - Html-Knoten
		 */
		initialize: function(container){
			try {
				if (!container) {
					return;
				}
				this.container = container;
				
				// Navi geoeffnet oder geschlossen?				
				this.isActive = false;
				
				// (z.B.) optional vorhandener Navi-Button
				this.mainAnchor = this.container.down('.uc-head') || this.container;
				
				// alle (Unter)menues
				this.Uls = this.container.select('ul');
				this.Uls.invoke('hide').invoke('setStyle', 'visibility : visible');
				
				// alle Links
				this.links = this.container.select('a');
				
				// alle Menues referenzieren, welche bei aktivem Link
				// sichtbar sein muessen (alle uebergeordneten und die untergeordneten des Eltern-li-Knotens				
				for (var i = 0; i < this.links.length; i++) {
					this.links[i].index = i;
					this.links[i].refUls = [];
					
					// wenn item == head-Element(Button "Navigation" etwa), dann 
					// diesem die erste Liste zuordnen
					if (i > 0 && this.mainAnchor) {
						var tmp = [];
						this.getSuperiorUls(this.links[i].up('ul'), tmp);
						this.links[i].refUls = tmp.concat(this.links[i].up('li').down('ul'));
					}
					else {
						this.links[i].refUls.push(this.Uls[0]);
					}
					
					this.links[i].refUls.compact().uniq();
				}
				
				this.container.observe('keyup', this.show.bindAsEventListener(this));
				document.observe('keyup', this.hideAll.bindAsEventListener(this));	
				document.observe('iD:UI:Controls:Menu:opened', this.onMenuOpened.bindAsEventListener(this));
							
				this.container.observe('mouseover', this.show.bindAsEventListener(this));	
				document.observe('mouseover', this.hideAll.bindAsEventListener(this));		
				
				this.container.fire(this.separatedName(":") + ':initialized');				
			} 
			catch (ex) {
				this.logError(ex);
			}
		},
		
		/**
		 * Prueft, ob beim KeyUp dieses Menu oder ein anderes der Seite aktiv ist
		 * und schliesst ggf. 
		 * @param {Object} event
		 */
		onMenuOpened: function(event) {
			event.stop();
			if (event.element() != this.container) {
				this.hideAll();	
			}
		},
		
		/**
		 * Prueft, ob ein Event innerhalb des Containers stattfindet
		 * @param {Object} event
		 */
		checkActive: function(event) {
			var evElem = event.element();
			this.isActive = (evElem == this.container || evElem == this.mainAnchor);			
			
			if (false == this.isActive) {
				// alle Kindelemente auf Eventausloeser checken
				var elems = this.container.select("*");
				for (var i = 0; i < elems.length; i++) {
					this.isActive |= (elems[i] == evElem);
					if (true == this.isActive) {
						break;
					}
				}
			}
			
			if (true == this.isActive) {
				this.show(event);
				this.container.fire(this.separatedName(":") + ':opened');
			}
			else {
				this.hideAll();
				this.container.fire(this.separatedName(":") + ':closed');
			}
		},		
		
		/**
		 * Einblenden der zu einem Link gehoerenden ul-Listen.
		 * Alle anderen Listen werden ausgeblendet.
		 * @param {Object} Event
		 */
		show: function(event){
			event.stop();
			
			var node = event.element();
			var inner = (node == this.container || node == this.mainAnchor);
			
			try {
				var showIt = false;
				
				// alle Listen checken
				for (var i = 0; i < this.Uls.length; i++) {
					showIt = false;
					
					// Knoten mit verknuepften Menues?
					if (!node.refUls) {
						continue;
					}
					
					// verknuepften Menues ermitteln...
					for (var j = 0; j < node.refUls.length; j++) {
						if (this.Uls[i] == node.refUls[j]) {
							showIt = true;
							inner = true;
							break;
						}
					}
					
					// ...und anzeigen
					if (showIt) {
						// Anpassen der Hoehe des ul-Containers an den Viewport	(BIK)							
						this.Uls[i].show();
						this.setMaxDimension(this.Uls[i]);
					}
					else {
						this.Uls[i].hide();
					}
				}
			} 
			catch (ex) {
				this.logError(ex);
			}
			this.container.fire(this.separatedName(":") + ':opened');
		},
		
		/**
		 * Setzt maximale Abmessungen eines Submenues
		 * in Abhaengigkeit vom ViewPort
		 * @param {Object} subMenu
		 */
		setMaxDimension: function(subMenu){
			// Viewport
			var vp = document.viewport.getDimensions();
			// Scrollpos.
			var so = document.viewport.getScrollOffsets();
			// Elementposition
			var pos = subMenu.cumulativeOffset();
			// Elementmasze
			var h = subMenu.getHeight();
			var w = subMenu.getWidth();
			
			var scrollOverflow = false;
			
			// Maximalhoehe ist Viewporthoehe - MenuTop + ScrollOffset
			var maxH = parseInt(vp.height) - pos.top + so.top - 40;
			if (h > maxH) {
				subMenu.setStyle({
					'height'   : maxH + 'px'
				});				
				scrollOverflow = true;
			}
			else {
				subMenu.setStyle({
					'height'   : 'auto'
				});
			}
			
			var maxW = parseInt(vp.width) - pos.left + so.left - 40;
			if (w > maxW) {
				subMenu.setStyle({
					'width'    : maxH + 'px'
				});
				scrollOverflow = true;
			}
			else {
				subMenu.setStyle({
					'width'    : 'auto'
				});
			}
			
			subMenu.setStyle({
				'overflow' : (scrollOverflow ? 'auto' : 'hidden')
			});
		},
		
		/**
		 * Alle Menues ausblenden
		 * @param {Object} Event
		 */
		hideAll: function(event){
			if (event) {
				Event.stop(event);
			}
			this.Uls.invoke('hide');			
			this.container.fire(this.separatedName(":") + ':closed');
		},
		
		/**
		 * Elterlisten sammeln bis zur Root-Liste (container)
		 * @param {Object} aktueller Knoten (ul)
		 * @param {Array} Sammelliste
		 */
		getSuperiorUls: function(currUl, refUls){
			try {
				if (typeof currUl != 'undefined' && refUls) {
					refUls.push(currUl);
					if (currUl.up() != this.container) {
						this.getSuperiorUls(currUl.up('ul'), refUls);
					}
				}
				return;
			} 
			catch (ex) {
				this.logError(ex);
			}
		}
	});
})(iD.UI.Controls);


