/**
 * @class Navigation
 * @author Adam "NiX0n" VanBerlo
 * @requires Prototype >= 1.6.0
 * @requires Navigation CSS
 * @copyright (c)2011 Adam "NiX0n" VanBerlo
 * @license Navigation is licensed under a Creative Commons 
 * 		Attribution 3.0 United States License 
 * 		<http://creativecommons.org/licenses/by/3.0/us/>
 * @classDescription Provides a W3C standards compliant navigation.
 * Complete with contextual linked data and minimalist JavaScript.
 */
var Navigation = Class.create(
{
	//
	// Properties
	//
		
	/**
	 * Collection of parent menus
	 * @var HTMLElement[]
	 */
	menus: null,
	
	defaultMenus: null,
	
	/**
	 * Parent menu currently active
	 * @var HTMLElement
	 */
	active: null,
	
	doPreventClick: false,
	
	options: null,

	//
	// Methods
	//
	
	/**
	 * Prepare navigation menus with necessary event listeners
	 * @param HTMLElement[] elements
	 */
	initialize: function(elements, options)
	{
		this.options = {
			activeClassName: 'active',
			submenuSelector: 'ul',
			menuSelector: 'li'
		};
		var o = this.options;
		Object.extend(this.options, options || {});
		this.menus = $A(elements);
		this.defaultMenus = this.menus.findAll(function(menu) {
			return menu.hasClassName(o.activeClassName);
		});
		
		this.reset();
		this.menus.each(function(menu)
		{
			var submenus = menu.immediateDescendants();
			menu.observe('mouseout', this.menu_Mouseout.bind(this));
			menu.observe('click', this.menu_Click.bind(this));
			submenus.each(function(submenu) 
			{
				submenu.observe('mouseover', this.submenu_Mouseover.bind(this));
			}.bind(this));
		}.bind(this));
	},
	
	reset: function()
	{
		//var self = Navigation;
		this.hideAll();
		this.defaultMenus.each(function(menu) {
			this.show(menu, true);
			this.active = menu;
		}.bind(this));
	},
	
	
	/**
	 * Hide all submenus
	 */
	hideAll: function()
	{
		this.menus.each(function(menu)
		{
			this.show(menu, false);
		}.bind(this));
		this.active = null;
	},
	

	/**
	 * Show/Hide submenu
	 * @param HTMLElement parent parent menu
	 * @param boolean show true, show; false, hide
	 */
	show: function (parent, show)
	{
		//var this = Navigation;
		var o = this.options;
		parent[(show ? 'add' : 'remove') + 'ClassName'](o.activeClassName);
		// find submenu and hide/show
		var menus = parent.select(o.submenuSelector);
		menus.each(function(menu) {
			menu[show ? 'show' : 'hide']();
		}.bind(this));
	},

	/**
	 * Menu 'mouseout' event handler
	 * @param Event event
	 */
	menu_Mouseout: function (event)
	{
		//var this = this;
		var o = this.options;
		var e = event.element();
		var x = Event.pointerX(event);
		var y = Event.pointerY(event);
		var menu = e.up(o.menuSelector);
		var submenu = menu.down(o.submenuSelector);
		var inside = false;
		if(submenu)
		{	
			inside = Position.within(e, x, y) || Position.within(submenu, x, y);
		}
		if(!inside)
		{
			this.reset();
			//this.show(this, false);
			//this.active = null;
		}
	},
	
	/**
	 * Menu 'click' event handler
	 * @param Event event
	 */
	menu_Click: function (event)
	{
		if(this.doPreventClick)
			event.stop();
	},

	/**
	 * Submenu 'mouseover' event handler
	 * @param Event event
	 */
	
	submenu_Mouseover: function (event)
	{
		var o = this.options;
		var e = event.element();
		var menu = e.up(o.menuSelector);
		if(this.active !== menu)
		{
			this.hideAll();
			this.active = menu;
			this.show(menu, true);
			this.preventClick();
		}
	},
	
	/**
	 * Temporarily (1/10th second) prevent top menu click
	 * This prevents browsers (mobile) from sending mouseover AND click
	 * events simultaneously.
	 */
	preventClick: function()
	{
		this.doPreventClick = true;
		new PeriodicalExecuter(function(pe) 
		{
			this.doPreventClick = false;
			pe.stop();
		}.bind(this), .1);
	}
});

