/*	
 * jQuery mmenu v4.7.5
 * @requires jQuery 1.7.0 or later
 *
 * mmenu.frebsite.nl
 *	
 * Copyright (c) Fred Heusschen
 * www.frebsite.nl
 *
 * Licensed under the MIT license:
 * http://en.wikipedia.org/wiki/MIT_License
 */
(function($) {

	var _PLUGIN_ = 'mmenu',
		_VERSION_ = '4.7.5';


	//	Plugin already excists
	if ($[_PLUGIN_]) {
		return;
	}


	//	Global variables
	var _c = {},
		_d = {},
		_e = {},
		plugin_initiated = false;

	var glbl = {
		$wndw: null,
		$html: null,
		$body: null
	};


	/*
		Class
	*/
	$[_PLUGIN_] = function($menu, opts, conf) {
		this.$menu = $menu;
		this.opts = opts;
		this.conf = conf;
		this.vars = {};

		if (typeof this.___deprecated == 'function') {
			this.___deprecated();
		}

		this._initMenu();
		this._initAnchors();
		this._initEvents();

		var $panels = this.$menu.children(this.conf.panelNodetype);

		for (var a in $[_PLUGIN_].addons) {
			//	Add add-ons to plugin
			$[_PLUGIN_].addons[a]._add.call(this);
			$[_PLUGIN_].addons[a]._add = function() {};

			//	Setup adds-on for menu
			$[_PLUGIN_].addons[a]._setup.call(this);
		}

		this._init($panels);

		if (typeof this.___debug == 'function') {
			this.___debug();
		}

		return this;
	};

	$[_PLUGIN_].version = _VERSION_;

	$[_PLUGIN_].addons = {};

	$[_PLUGIN_].uniqueId = 0;

	$[_PLUGIN_].defaults = {
		classes: '',
		slidingSubmenus: true,
		onClick: {
			//			close				: true,
			//			blockUI				: null,
			//			preventDefault		: null,
			setSelected: true
		}
	};

	$[_PLUGIN_].configuration = {
		panelNodetype: 'ul, ol, div',
		transitionDuration: 400,
		openingInterval: 25,
		classNames: {
			panel: 'Panel',
			selected: 'Selected',
			label: 'Label',
			spacer: 'Spacer'
		}
	};
	$[_PLUGIN_].prototype = {

		_init: function($panels) {
			$panels = $panels.not('.' + _c.nopanel);
			$panels = this._initPanels($panels);

			for (var a in $[_PLUGIN_].addons) {
				$[_PLUGIN_].addons[a]._init.call(this, $panels);
			}
			this._update();
		},

		_initMenu: function() {
			var that = this;

			//	Clone if needed
			if (this.opts.offCanvas && this.conf.clone) {
				this.$menu = this.$menu.clone(true);
				this.$menu.add(this.$menu.find('*')).filter('[id]').each(
					function() {
						$(this).attr('id', _c.mm($(this).attr('id')));
					}
				);
			}

			//	Strip whitespace
			this.$menu.contents().each(
				function() {
					if ($(this)[0].nodeType == 3) {
						$(this).remove();
					}
				}
			);

			this.$menu
				.parent()
				.addClass(_c.wrapper);

			var clsn = [_c.menu];

			//	Add direction class
			clsn.push(_c.mm(this.opts.slidingSubmenus ? 'horizontal' : 'vertical'));

			//	Add options classes
			if (this.opts.classes) {
				clsn.push(this.opts.classes);
			}

			this.$menu.addClass(clsn.join(' '));
		},

		_initPanels: function($panels) {
			var that = this;

			//	Add List class
			this.__findAddBack($panels, 'ul, ol')
				.not('.' + _c.nolist)
				.addClass(_c.list);

			var $lis = this.__findAddBack($panels, '.' + _c.list).find('> li');

			//	Refactor Selected class
			this.__refactorClass($lis, this.conf.classNames.selected, 'selected');

			//	Refactor Label class
			this.__refactorClass($lis, this.conf.classNames.label, 'label');

			//	Refactor Spacer class
			this.__refactorClass($lis, this.conf.classNames.spacer, 'spacer');

			//	setSelected-event
			$lis
				.off(_e.setSelected)
				.on(_e.setSelected,
					function(e, selected) {
						e.stopPropagation();

						$lis.removeClass(_c.selected);
						if (typeof selected != 'boolean') {
							selected = true;
						}
						if (selected) {
							$(this).addClass(_c.selected);
						}
					}
				);

			//	Refactor Panel class
			this.__refactorClass(this.__findAddBack($panels, '.' + this.conf.classNames.panel), this.conf.classNames.panel, 'panel');

			//	Add Panel class			
			$panels
				.add(this.__findAddBack($panels, '.' + _c.list).children().children().filter(this.conf.panelNodetype).not('.' + _c.nopanel))
				.addClass(_c.panel);

			var $curpanels = this.__findAddBack($panels, '.' + _c.panel),
				$allpanels = $('.' + _c.panel, this.$menu);

			//	Add an ID to all panels
			$curpanels
				.each(
					function(i) {
						var $t = $(this),
							id = $t.attr('id') || that.__getUniqueId();

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

			//	Add open and close links to menu items
			$curpanels
				.each(
					function(i) {
						var $t = $(this),
							$u = $t.is('ul, ol') ? $t : $t.find('ul ,ol').first(),
							$l = $t.parent(),
							$a = $l.children('a, span'),
							$p = $l.closest('.' + _c.panel);

						if ($l.parent().is('.' + _c.list) && !$t.data(_d.parent)) {
							$t.data(_d.parent, $l);

							var $btn = $('<a class="' + _c.subopen + '" href="#' + $t.attr('id') + '" />').insertBefore($a);
							if (!$a.is('a')) {
								$btn.addClass(_c.fullsubopen);
							}
							if (that.opts.slidingSubmenus) {
								$u.prepend('<li class="' + _c.subtitle + '"><a class="' + _c.subclose + '" href="#' + $p.attr('id') + '">' + $a.text() + '</a></li>');
							}
						}
					}
				);

			if (this.opts.slidingSubmenus) {
				//	Add opened-classes
				var $selected = this.__findAddBack($panels, '.' + _c.list).find('> li.' + _c.selected);
				$selected
					.parents('li')
					.removeClass(_c.selected)
					.end()
					.add($selected.parents('li'))
					.each(
						function() {
							var $t = $(this),
								$u = $t.find('> .' + _c.panel);

							if ($u.length) {
								$t.parents('.' + _c.panel).addClass(_c.subopened);
								$u.addClass(_c.opened);
							}
						}
					)
					.closest('.' + _c.panel)
					.addClass(_c.opened)
					.parents('.' + _c.panel)
					.addClass(_c.subopened);
			} else {
				//	Replace Selected-class with opened-class in parents from .Selected
				var $selected = $('li.' + _c.selected, $allpanels);
				$selected
					.parents('li')
					.removeClass(_c.selected)
					.end()
					.add($selected.parents('li'))
					.addClass(_c.opened);
			}

			//	Set current opened
			var $current = $allpanels.filter('.' + _c.opened);
			if (!$current.length) {
				$current = $curpanels.first();
			}
			$current
				.addClass(_c.opened)
				.last()
				.addClass(_c.current);

			//	Rearrange markup
			if (this.opts.slidingSubmenus) {
				$curpanels
					.not($current.last())
					.addClass(_c.hidden)
					.end()
					.appendTo(this.$menu);
			}

			return $curpanels;
		},

		_initAnchors: function() {
			var that = this;

			glbl.$body
				.on(_e.click,
					'a',
					function(e) {
						var $t = $(this),
							fired = false,
							inMenu = that.$menu.find($t).length;


						//	Find behavior for addons
						for (var a in $[_PLUGIN_].addons) {
							if ($[_PLUGIN_].addons[a]._clickAnchor &&
								(fired = $[_PLUGIN_].addons[a]._clickAnchor.call(that, $t, inMenu))
							) {
								break;
							}
						}

						//	Open/Close panel
						if (!fired && inMenu) {
							var _h = $t.attr('href') || '';
							if (_h.slice(0, 1) == '#') {
								try {
									if ($(_h, that.$menu).is('.' + _c.panel)) {
										fired = true;
										$(_h).trigger(that.opts.slidingSubmenus ? _e.open : _e.toggle);
									}
								} catch (error) {}
							}
						}

						if (fired) {
							e.preventDefault();
						}


						//	All other anchors in lists
						if (!fired && inMenu) {
							if ($t.is('.' + _c.list + ' > li > a') &&
								!$t.is('[rel="external"]') &&
								!$t.is('[target="_blank"]')) {

								//	Set selected item
								if (that.__valueOrFn(that.opts.onClick.setSelected, $t)) {
									$t.parent().trigger(_e.setSelected);
								}

								//	Prevent default / don't follow link. Default: false
								var preventDefault = that.__valueOrFn(that.opts.onClick.preventDefault, $t, _h.slice(0, 1) == '#');
								if (preventDefault) {
									e.preventDefault();
								}

								//	Block UI. Default: false if preventDefault, true otherwise
								if (that.__valueOrFn(that.opts.onClick.blockUI, $t, !preventDefault)) {
									glbl.$html.addClass(_c.blocking);
								}

								//	Close menu. Default: true if preventDefault, false otherwise
								if (that.__valueOrFn(that.opts.onClick.close, $t, preventDefault)) {
									that.$menu.trigger(_e.close);
								}
							}
						}
					}
				);
		},

		_initEvents: function() {
			var that = this;

			this.$menu
				.on(_e.toggle + ' ' + _e.open + ' ' + _e.close,
					'.' + _c.panel,
					function(e) {
						e.stopPropagation();
					}
				);

			if (this.opts.slidingSubmenus) {
				this.$menu
					.on(_e.open,
						'.' + _c.panel,
						function(e) {
							return that._openSubmenuHorizontal($(this));
						}
					);
			} else {
				this.$menu
					.on(_e.toggle,
						'.' + _c.panel,
						function(e) {
							var $t = $(this);
							$t.trigger($t.parent().hasClass(_c.opened) ? _e.close : _e.open);
						}
					)
					.on(_e.open,
						'.' + _c.panel,
						function(e) {
							$(this).parent().addClass(_c.opened);
						}
					)
					.on(_e.close,
						'.' + _c.panel,
						function(e) {
							$(this).parent().removeClass(_c.opened);
						}
					);
			}
		},

		_openSubmenuHorizontal: function($opening) {
			if ($opening.hasClass(_c.current)) {
				return false;
			}

			var $panels = $('.' + _c.panel, this.$menu),
				$current = $panels.filter('.' + _c.current);

			$panels
				.removeClass(_c.highest)
				.removeClass(_c.current)
				.not($opening)
				.not($current)
				.addClass(_c.hidden);

			if ($opening.hasClass(_c.opened)) {
				$current
					.addClass(_c.highest)
					.removeClass(_c.opened)
					.removeClass(_c.subopened);
			} else {
				$opening
					.addClass(_c.highest);

				$current
					.addClass(_c.subopened);
			}

			$opening
				.removeClass(_c.hidden)
				.addClass(_c.current);

			//	Without the timeout, the animation won't work because the element had display: none;
			setTimeout(
				function() {
					$opening
						.removeClass(_c.subopened)
						.addClass(_c.opened);
				}, this.conf.openingInterval
			);

			return 'open';
		},

		_update: function(fn) {
			if (!this.updates) {
				this.updates = [];
			}
			if (typeof fn == 'function') {
				this.updates.push(fn);
			} else {
				for (var u = 0, l = this.updates.length; u < l; u++) {
					this.updates[u].call(this, fn);
				}
			}
		},

		__valueOrFn: function(o, $e, d) {
			if (typeof o == 'function') {
				return o.call($e[0]);
			}
			if (typeof o == 'undefined' && typeof d != 'undefined') {
				return d;
			}
			return o;
		},

		__refactorClass: function($e, o, c) {
			return $e.filter('.' + o).removeClass(o).addClass(_c[c]);
		},

		__findAddBack: function($e, s) {
			return $e.find(s).add($e.filter(s));
		},

		__transitionend: function($e, fn, duration) {
			var _ended = false,
				_fn = function() {
					if (!_ended) {
						fn.call($e[0]);
					}
					_ended = true;
				};

			$e.one(_e.transitionend, _fn);
			$e.one(_e.webkitTransitionEnd, _fn);
			setTimeout(_fn, duration * 1.1);
		},

		__getUniqueId: function() {
			return _c.mm($[_PLUGIN_].uniqueId++);
		}
	};


	/*
		jQuery plugin
	*/
	$.fn[_PLUGIN_] = function(opts, conf) {
		//	First time plugin is fired
		if (!plugin_initiated) {
			_initPlugin();
		}

		//	Extend options
		opts = $.extend(true, {}, $[_PLUGIN_].defaults, opts);
		conf = $.extend(true, {}, $[_PLUGIN_].configuration, conf);

		return this.each(
			function() {
				var $menu = $(this);
				if ($menu.data(_PLUGIN_)) {
					return;
				}
				$menu.data(_PLUGIN_, new $[_PLUGIN_]($menu, opts, conf));
			}
		);
	};


	/*
		SUPPORT
	*/
	$[_PLUGIN_].support = {
		touch: 'ontouchstart' in window || navigator.msMaxTouchPoints
	};



	function _initPlugin() {
		plugin_initiated = true;

		glbl.$wndw = $(window);
		glbl.$html = $('html');
		glbl.$body = $('body');

		//	Classnames, Datanames, Eventnames
		$.each([_c, _d, _e],
			function(i, o) {
				o.add = function(c) {
					c = c.split(' ');
					for (var d in c) {
						o[c[d]] = o.mm(c[d]);
					}
				};
			}
		);

		//	Classnames
		_c.mm = function(c) {
			return 'mm-' + c;
		};
		_c.add('wrapper menu inline panel nopanel list nolist subtitle selected label spacer current highest hidden opened subopened subopen fullsubopen subclose');
		_c.umm = function(c) {
			if (c.slice(0, 3) == 'mm-') {
				c = c.slice(3);
			}
			return c;
		};

		//	Datanames
		_d.mm = function(d) {
			return 'mm-' + d;
		};
		_d.add('parent');

		//	Eventnames
		_e.mm = function(e) {
			return e + '.mm';
		};
		_e.add('toggle open close setSelected transitionend webkitTransitionEnd mousedown mouseup touchstart touchmove touchend scroll resize click keydown keyup');

		$[_PLUGIN_]._c = _c;
		$[_PLUGIN_]._d = _d;
		$[_PLUGIN_]._e = _e;

		$[_PLUGIN_].glbl = glbl;
	}


})(jQuery);