/*	
 *	jQuery mmenu 1.3.1
 *	
 *	Copyright (c) 2013 Fred Heusschen
 *	www.frebsite.nl
 *
 *	Dual licensed under the MIT and GPL licenses.
 *	http://en.wikipedia.org/wiki/MIT_License
 *	http://en.wikipedia.org/wiki/GNU_General_Public_License
 */


(function( $ ) {

	//	Global nodes
	var $wndw = null,
		$html = null,
		$body = null,
		$page = null,
		$blck = null;

	var $scrollTopNode = null;

	//	Global vars
	var _serialnr = 0;


	$.fn.mmenu = function( opts )
	{
		if ( !$wndw )
		{
			$wndw = $(window);
			$html = $('html');
			$body = $('body');
		}

		opts = extendOptions( opts );
		opts = $.extend( true, {}, $.fn.mmenu.defaultOptions, opts );
		opts = complementOptions( opts );

		$html[ opts.configuration.hardwareAcceleration ? 'addClass' : 'removeClass' ]( cls( 'accelerated' ) );

		return this.each(
			function()
			{

				//	STORE VARIABLES
				var $menu 		= $(this),
					_opened 	= false,
					_direction	= ( opts.slidingSubmenus ) ? 'horizontal' : 'vertical';

				_serialnr++;



				//	INIT PAGE, MENU, LINKS & LABELS
				$page = _initPage( $page, opts.configuration );
				$blck = _initBlocker( $blck, $menu, opts.configuration );
				$menu = _initMenu( $menu, opts.configuration );
				_initSubmenus( $menu, _direction, _serialnr );
				_initLinks( $menu, opts.onClick, opts.configuration );
				_initCounters( $menu, opts.counters, opts.configuration );
				_initSearch( $menu, opts.searchfield );
				_initOpenClose( $menu, $page );


				//	BIND EVENTS
				var $subs = $menu.find( 'ul' );
				$menu.add( $subs )
					.bind(
						evt( 'toggle' ) + ' ' + evt( 'open' ) + ' ' + evt( 'close' ),
						function( e )
						{
							e.preventDefault();
							e.stopPropagation();
						}
					);

				//	menu-events
				$menu
					.bind(
						evt( 'toggle' ),
						function( e )
						{
							return $menu.triggerHandler( evt( _opened ? 'close' : 'open' ) );
						}
					)
					.bind(
						evt( 'open' ),
						function( e )
						{
							if ( _opened )
							{
								return false;
							}
							_opened = true;
							return openMenu( $menu, opts.position );
						}
					)
					.bind(
						evt( 'close' ),
						function( e )
						{
							if ( !_opened )
							{
								return false;
							}
							_opened = false;
							return closeMenu( $menu, opts );
						}
					);


				//	submenu-events
				if ( _direction == 'horizontal' )
				{
					$subs
						.bind(
							evt( 'toggle' ),
							function( e )
							{								
								return $(this).triggerHandler( evt( 'open' ) );
							}
						)
						.bind(
							evt( 'open' ),
							function( e )
							{
								return openSubmenuHorizontal( $(this), opts );
							}
						)
						.bind(
							evt( 'close' ),
							function( e )
							{
								return closeSubmenuHorizontal( $(this), opts );
							}
						);
				}
				else
				{
					$subs
						.bind(
							evt( 'toggle' ),
							function( e )
							{
								var $t = $(this);
								return $t.triggerHandler( evt( ( $t.parent().hasClass( cls( 'opened' ) ) ) ? 'close' : 'open' ) );
							}
						)
						.bind(
							evt( 'open' ),
							function( e )
							{
								$(this).parent().addClass( cls( 'opened' ) );
								return 'open';
							}
						)
						.bind(
							evt( 'close' ),
							function( e )
							{
								$(this).parent().removeClass( cls( 'opened' ) );
								return 'close';
							}
						);
				}
			}
		);
	};


	$.fn.mmenu.defaultOptions = {
		position		: 'right',
		slidingSubmenus	: true,
		counters		: {
			add					: false,
			count				: true
		},
		searchfield		: {
			add					: false,
			search				: true,
			showLinksOnly		: true,
			placeholder			: 'Search',
			noResults			: 'No results found.'
		},
		onClick			: {
			close				: true,
			delayPageload		: true,
			blockUI				: false
		},
		configuration	: {
			hardwareAcceleration: true,
			selectedClass		: 'Selected',
			labelClass			: 'Label',
			counterClass		: 'Counter',
			pageNodetype		: 'div',
			menuNodetype		: 'nav',
			slideDuration		: 500
		}
	};

	$.fn.mmenu.debug = function( msg )
	{
		if ( typeof console != 'undefined' && typeof console.log != 'undefined' )
		{
			console.log( 'MMENU: ' + msg );
		}
	};
	$.fn.mmenu.deprecated = function( depr, repl )
	{
		if ( typeof console != 'undefined' && typeof console.warn != 'undefined' )
		{
			console.warn( 'MMENU: ' + depr + ' is deprecated, use ' + repl + ' instead.' );
		}
	};


	function extendOptions( o )
	{
		if ( typeof o == 'string' )
		{
			if ( o == 'left' || o == 'right' )
			{
				o = {
					position: o
				};
			}
		}
		else if ( typeof o != 'object' )
		{
			o = {};
		}

		//	DEPRECATED
		if ( typeof o.addCounters != 'undefined' )
		{
			$.fn.mmenu.deprecated( 'addCounters-option', 'counters.add-option' );
			o.counters = {
				add: o.addCounters
			};
		}
		if ( typeof o.closeOnClick != 'undefined' )
		{
			$.fn.mmenu.deprecated( 'closeOnClick-option', 'onClick.close-option' );
			o.onClick = {
				close: o.closeOnClick
			};
		}
		//	/DEPRECATED

		//	Counters
		if ( typeof o.counters == 'boolean' )
		{
			o.counters = {
				add		: o.counters,
				count	: o.counters
			};
		}
		else if ( typeof o.counters != 'object' )
		{
			o.counters = {};
		}

		//	OnClick
		if ( typeof o.onClick == 'boolean' )
		{
			o.onClick = {
				close	: o.onClick
			};
		}
		else if ( typeof o.onClick != 'object' )
		{
			o.onClick = {};
		}

		//	Search
		if ( typeof o.searchfield == 'boolean' )
		{
			o.searchfield = {
				add		: o.searchfield,
				search	: o.searchfield
			};
		}
		else if ( typeof o.searchfield == 'string' )
		{
			o.searchfield = {
				add			: true,
				search		: true,
				placeholder	: o.searchfield
			};
		}
		else if ( typeof o.searchfield != 'object' )
		{
			o.searchfield = {};
		}

		return o;
	}
	function complementOptions( o )
	{
		if ( typeof o.onClick.delayPageload == 'boolean' )
		{
			o.onClick.delayPageload = ( o.onClick.delayPageload ) ? o.configuration.slideDuration : 0;
		}
		return o;
	}

	function _initPage( $p, conf )
	{
		if ( !$p )
		{
			$p = $('> ' + conf.pageNodetype, $body);
			if ( $p.length > 1 )
			{
				$p = $p.wrapAll( '<' + conf.pageNodetype + ' />' ).parent();
			}
			$p.addClass( cls( 'page' ) );
		}
		return $p;
	}

	function _initMenu( $m, conf )
	{
		if ( !$m.is( conf.menuNodetype ) )
		{
			$m = $( '<' + conf.menuNodetype + ' />' ).append( $m );
		}
	//	$_dummy = $( '<div class="mmenu-dummy" />' ).insertAfter( $m ).hide();
		$m.addClass( cls( '' ).slice( 0, -1 ) ).prependTo( 'body' );

		//	Refactor selected class
		$('li.' + conf.selectedClass, $m).removeClass( conf.selectedClass ).addClass( cls( 'selected' ) );

		//	Refactor label class
		$('li.' + conf.labelClass, $m).removeClass( conf.labelClass ).addClass( cls( 'label' ) );

		return $m;
	}

	function _initSubmenus( $m, direction, serial )
	{
		$m.addClass( cls( direction ) );

		$( 'ul ul', $m )
			.addClass( cls( 'submenu' ) )
			.each(
				function( i )
				{
					var $t = $(this)
						$a = $t.parent().find( '> a, > span' ),
						id = $t.attr( 'id' ) || cls( 's' + serial + '-' + i );

					$t.attr( 'id', id );

					var $btn = $( '<a class="' + cls( 'subopen' ) + '" href="#' + id + '" />' ).insertBefore( $a );
					if ( !$a.is( 'a' ) )
					{
						$btn.addClass( cls( 'fullsubopen' ) );
					}

					if ( direction == 'horizontal' )
					{
						var $p = $t.parent().parent(),
							id = $p.attr( 'id' ) || cls( 'p' + serial + '-' + i );
	
						$p.attr( 'id', id );
						$t.prepend( '<li class="' + cls( 'subtitle' ) + '"><a class="' + cls( 'subclose' ) + '" href="#' + id + '">' + $a.text() + '</a></li>' );
					}
				}
			);

		if ( direction == 'horizontal' )
		{
			//	Add opened-classes
			$('li.' + cls( 'selected' ), $m)
				.parents( 'li.' + cls( 'selected' ) ).removeClass( cls( 'selected' ) )
				.end().each(
					function()
					{
						var $t = $(this),
							$u = $t.find( '> ul' );
	
						if ( $u.length )
						{
							$t.parent().addClass( cls( 'subopened' ) );
							$u.addClass( cls( 'opened' ) );
						}
					}
				)
				.parent().addClass( cls( 'opened' ) )
				.parents( 'ul' ).addClass( cls( 'subopened' ) );

			if ( !$('ul.' + cls( 'opened' ), $m).length )
			{
				$('ul', $m).not( '.' + cls( 'submenu' ) ).addClass( cls( 'opened' ) );
			}

			//	Rearrange markup
			$('ul ul', $m).appendTo( $m );

		}
		else
		{
			//	Replace Selected-class with opened-class in parents from .Selected
			$('li.' + cls( 'selected' ), $m)
				.addClass( cls( 'opened' ) )
				.parents( '.' + cls( 'selected' ) ).removeClass( cls( 'selected' ) );
		}
	}
	function _initBlocker( $b, $m, conf )
	{
		if ( !$b )
		{
			$b = $( '<div id="' + cls( 'blocker' ) + '" />' ).appendTo( $body );
		}

		click( $b,
			function()
			{
				$m.trigger( evt( 'close' ) );
			}
		);
		return $b;
	}
	function _initLinks( $m, onClick, conf )
	{
		if ( onClick.close )
		{
			var $a = $('a', $m)
				.not( '.' + cls( 'subopen' ) )
				.not( '.' + cls( 'subclose' ) );

			click( $a,
				function()
				{
					var $t = $(this),
						href = $t.attr( 'href' );
	
					$m.trigger( evt( 'close' ) );
					$a.parent().removeClass( cls( 'selected' ) );
					$t.parent().addClass( cls( 'selected' ) );

					if ( onClick.blockUI && href.slice( 0, 1 ) != '#' )
					{
						$html.addClass( cls( 'blocking' ) );
					}

					if ( href != '#' )
					{
						setTimeout(
							function()
							{
								window.location.href = href;
							}, onClick.delayPageload
						);
					}
				}
			);
		}
	}
	function _initCounters( $m, counters, conf )
	{
		//	Refactor counter class
		$('em.' + conf.counterClass, $m).removeClass( conf.counterClass ).addClass( cls( 'counter' ) );

		//	Add counters
		if ( counters.add )
		{
			$('.' + cls( 'submenu' ), $m).each(
				function()
				{
					var $s = $(this),
						id = $s.attr( 'id' );
	
					if ( id && id.length )
					{
						var $c = $( '<em class="' + cls( 'counter' ) + '" />' ),
							$a = $('a.' + cls( 'subopen' ), $m).filter( '[href="#' + id + '"]' );

						if ( !$a.parent().find( 'em.' + cls( 'counter' ) ).length )
						{
							$a.before( $c );
						}
					}
				}
			);
		}

		//	Bind count event
		if ( counters.count )
		{
			$('em.' + cls( 'counter' ), $m).each(
				function()
				{
					var $c = $(this),
						$s = $('ul' + $c.next().attr( 'href' ), $m);

					$c.bind(
						evt( 'count' ),
						function( e )
						{
							e.preventDefault();
							e.stopPropagation();

							var $lis = $s.children()
								.not( '.' + cls( 'label' ) )
								.not( '.' + cls( 'subtitle' ) )
								.not( '.' + cls( 'noresult' ) )
								.not( '.' + cls( 'noresults' ) );

							$c.html( $lis.length );
						}
					);
				}
			).trigger( evt( 'count' ) );
		}
	}
	function _initSearch( $m, search )
	{
		if ( search.add )
		{
			var $s = $( '<div class="' + cls( 'search' ) + '" />' ).prependTo( $m );
			$s.append( '<input placeholder="' + search.placeholder + '" type="text" autocomplete="off" />' );

			if ( search.noResults )
			{
				$('ul', $m).not( '.' + cls( 'submenu' ) ).append( '<li class="' + cls( 'noresults' ) + '">' + search.noResults + '</li>' );
			}
		}

		if ( search.search )
		{
			var $s = $('div.' + cls( 'search' ), $m),
				$i = $('input', $s);

			var $labels = $('li.' + cls( 'label' ), $m),
				$counters = $('em.' + cls( 'counter' ), $m),
				$items = $('li', $m)
					.not( '.' + cls( 'subtitle' ) )
					.not( '.' + cls( 'label' ) )
					.not( '.' + cls( 'noresults' ) );

			var _searchText = '> a';
			if ( !search.showLinksOnly )
			{
				_searchText += ', > span';
			}

			$i.bind(
				evt( 'keyup' ),
				function()
				{
					var query = $i.val().toLowerCase();

					//	search through items
					$items.add( $labels ).addClass( cls( 'noresult' ) );
					$items.each(
						function()
						{
							var $t = $(this);
							if ( $(_searchText, $t).text().toLowerCase().indexOf( query ) > -1 )
							{
								$t.add( $t.prevAll( '.' + cls( 'label' ) ).first() ).removeClass( cls( 'noresult' ) );
							}
						}
					);

					//	update parent for submenus
					$( $('ul.' + cls( 'submenu' ), $m).get().reverse() ).each(
						function()
						{
							var $t = $(this),
								$p = null,
								id = $t.attr( 'id' ),
								$i = $t.find( 'li' )
									.not( '.' + cls( 'subtitle' ) )
									.not( '.' + cls( 'label' ) )
									.not( '.' + cls( 'noresult' ) );

							if ( id && id.length )
							{
								var $p = $('a.' + cls( 'subopen' ), $m).filter( '[href="#' + id + '"]' ).parent();
							}
							if ( $i.length )
							{
								if ( $p )
								{
									$p.removeClass( cls( 'noresult' ) );
									$p.removeClass( cls( 'nosubresult' ) );
								}
							}
							else
							{
								$t.trigger( evt( 'close' ) );
								if ( $p )
								{
									$p.addClass( cls( 'nosubresult' ) );
								}
							}
						}
					);

					//	show/hide no results message
					$m[ $items.not( '.' + cls( 'noresult' ) ).length ? 'removeClass' : 'addClass' ]( cls( 'noresults' ) );

					//	update counters
					$counters.trigger( evt( 'count' ) );
				}
			);
		}
	}
	function _initOpenClose( $m, $p )
	{
		//	toggle menu
		var id = $m.attr( 'id' );
		if ( id && id.length )
		{
			click( 'a[href="#' + id + '"]',
				function()
				{
					$m.trigger( evt( 'toggle' ) );
				}
			);
		}

		//	close menu
		var id = $p.attr( 'id' );
		if ( id && id.length )
		{
			click( 'a[href="#' + id + '"]',
				function()
				{
					$m.trigger( evt( 'close' ) );
				}
			);
		}

		//	open submenu
		click( $('a.' + cls( 'subopen' ) + ', ' + 'a.' + cls( 'subclose' ), $m),
			function()
			{
				$( $(this).attr( 'href' ) ).trigger( evt( 'toggle' ) );
			}
		);
	}

	function openMenu( $m, p )
	{
		var _scrollTop = findScrollTop();

		//	resize page
		var _w = 0;
		$wndw.bind(
			evt( 'resize' ),
			function( e )
			{
				var nw = $wndw.width();
				if ( nw != _w )
				{
					_w = nw;
					$page
						.attr( 'style', $page.data( dta( 'style' ) ) )
						.width( nw );
				}
			}
		);

		//	store style and position
		$page
			.data( dta( 'style' ), $page.attr( 'style' ) || '' )
			.data( dta( 'scrollTop' ), _scrollTop )
			.width( $page.outerWidth() )
			.css( 'top', -_scrollTop );

		//	open
		$m.addClass( cls( 'opened' ) );
		$html.addClass( cls( 'opened' ) ).addClass( cls( p ) );
		setTimeout(
			function()
			{
				//	opened
				$html.addClass( cls( 'opening' ) );
			}, 25
		);

		return 'open';
	}
	function closeMenu( $m, o )
	{
		//	close
		$html.removeClass( cls( 'opening' ) );
		setTimeout(
			function()
			{
				//	closed
				$html.removeClass( cls( 'opened' ) ).removeClass( cls( o.position ) );
				$m.removeClass( cls( 'opened' ) );

				//	restore style and position
				$page.attr( 'style', $page.data( dta( 'style' ) ) );
				$wndw.unbind( evt( 'resize' ) );
				if ( $scrollTopNode )
				{
					$scrollTopNode.scrollTop( $page.data( dta( 'scrollTop' ) ) );
				}
			}, o.configuration.slideDuration + 25
		);

		return 'close';
	}

	function openSubmenuHorizontal( $t, o )
	{
		$t.prevAll( 'ul' ).addClass( cls( 'subopened' ) );
		$t.nextAll( 'ul' ).removeClass( cls( 'subopened' ) );
		$t.removeClass( cls( 'subopened' ) ).addClass( cls( 'opened' ) );
		setTimeout(
			function()
			{
				$t.nextAll( 'ul' ).removeClass( cls( 'opened' ) );
			}, o.configuration.slideDuration + 25
		);
		return 'open';
	}
	function closeSubmenuHorizontal( $t, o )
	{
		$t.prevAll( 'ul.' + cls( 'opened' ) ).first().trigger( evt( 'open' ) );
		return 'close';
	}

	function findScrollTop()
	{
		if ( !$scrollTopNode )
		{
			if ( $('html').scrollTop() != 0 )
			{
				$scrollTopNode = $('html');
			}
			else if ( $('body').scrollTop() != 0 )
			{
				$scrollTopNode = $('body');
			}
		}
		return ( $scrollTopNode ) ? $scrollTopNode.scrollTop() - 1 : 0;
	}

	function click( $b, fn )
	{
		if ( typeof $b == 'string' )
		{
			$b = $( $b );
		}
		$b.bind(
			evt( 'click' ),
			function( e )
			{
				e.preventDefault();
				e.stopPropagation();

				fn.call( this, e );
			}
		);
	}

	function cls( c )
	{
		return 'mmenu-' + c;
	}
	function dta( d )
	{
		return 'mmenu-' + d;
	}
	function evt( e )
	{
		return e + '.mmenu';
	}

})( jQuery );