/**
  *
  * jPanelMenu 1.3.0 (http://jpanelmenu.com)
  * By Anthony Colangelo (http://acolangelo.com)
  *
* */

(function($){
	$.jPanelMenu = function(options) {
		if ( typeof(options) == "undefined" || options == null ) { options = {}; };

		var jP = {
			options: $.extend({
				menu: '#menu',
				trigger: '.menu-trigger',
				excludedPanelContent: 'style, script',

				direction: 'left',
				openPosition: '250px',
				animated: true,
				closeOnContentClick: true,

				keyboardShortcuts: [
					{
						code: 27,
						open: false,
						close: true 
					},
					{
						code: 37,
						open: false,
						close: true 
					},
					{
						code: 39,
						open: true,
						close: true 
					},
					{
						code: 77,
						open: true,
						close: true 
					}
				],

				duration: 150,
				openDuration: options.duration || 150,
				closeDuration: options.duration || 150,

				easing: 'ease-in-out',
				openEasing: options.easing || 'ease-in-out',
				closeEasing: options.easing || 'ease-in-out',

				before: function(){ },
				beforeOpen: function(){ },
				beforeClose: function(){ },

				after: function(){ },
				afterOpen: function(){ },
				afterClose: function(){ },

				beforeOn: function(){ },
				afterOn: function(){ },

				beforeOff: function(){ },
				afterOff: function(){ }
			},options),

			settings: {
				transitionsSupported:	'WebkitTransition' in document.body.style ||
										'MozTransition' in document.body.style ||
										'msTransition' in document.body.style ||
										'OTransition' in document.body.style ||
										'Transition' in document.body.style
				,
				shiftFixedChildren: false,
				panelPosition: 'relative',
				positionUnits: 'px'
			},

			menu: '#jPanelMenu-menu',

			panel: '.jPanelMenu-panel',

			fixedChildren: [],

			timeouts: {},

			clearTimeouts: function() {
				clearTimeout(jP.timeouts.open);
				clearTimeout(jP.timeouts.afterOpen);
				clearTimeout(jP.timeouts.afterClose);
			},

			setPositionUnits: function() {
				var foundUnit = false,
					allowedUnits = ['%','px','em']
				;

				for ( unitID in allowedUnits ) {
					var unit = allowedUnits[unitID];
					if ( jP.options.openPosition.toString().substr(-unit.length) == unit )
					{
						foundUnit = true;
						jP.settings.positionUnits = unit;
					}
				}

				if ( !foundUnit ) { jP.options.openPosition = parseInt(jP.options.openPosition) + jP.settings.positionUnits }
			},

			checkFixedChildren: function() {
				jP.disableTransitions();

				var defaultPanelStyle = { position: $(jP.panel).css('position') };

				defaultPanelStyle[jP.options.direction] = ($(jP.panel).css(jP.options.direction) == 'auto')?0:$(jP.panel).css(jP.options.direction);

				$(jP.panel).find('> *').each(function(){
					if ( $(this).css('position') == 'fixed' && $(this).css(jP.options.direction) == 'auto' ) { jP.fixedChildren.push(this); }
				});
				
				if ( jP.fixedChildren.length > 0 )
				{
					var newPanelStyle = { position: 'relative' };
					newPanelStyle[jP.options.direction] = '1px';
					jP.setPanelStyle(newPanelStyle);

					if ( parseInt($(jP.fixedChildren[0]).offset().left) == 0 ) { jP.settings.shiftFixedChildren = true; }
				}

				jP.setPanelStyle(defaultPanelStyle);
			},

			setjPanelMenuStyles: function() {
				var bgColor = '#fff';
				var htmlBG = $('html').css('background-color');
				var bodyBG = $('body').css('background-color');

				if ( bodyBG != 'transparent' && bodyBG != "rgba(0, 0, 0, 0)") { bgColor = bodyBG; }
				else if ( htmlBG != 'transparent' && htmlBG != "rgba(0, 0, 0, 0)") { bgColor = htmlBG; }
				else { bgColor = '#fff'; }

				if ( $('#jPanelMenu-style-master').length == 0 )
				{
					$('body').append('<style id="jPanelMenu-style-master">body{width:100%}.jPanelMenu,body{overflow-x:hidden}#jPanelMenu-menu{display:block;position:fixed;top:0;'+jP.options.direction+':0;height:100%;z-index:-1;overflow-x:hidden;overflow-y:scroll;-webkit-overflow-scrolling:touch}.jPanelMenu-panel{position:static;'+jP.options.direction+':0;top:0;z-index:2;width:100%;min-height:100%;background:' + bgColor + '}</style>');
				}
			},

			setMenuState: function(open) {
				var position = (open)?'open':'closed';
				$('body').attr('data-menu-position', position);
			},

			getMenuState: function() {
				return $('body').attr('data-menu-position');
			},

			menuIsOpen: function() {
				if ( jP.getMenuState() == 'open' ) return true;
				else return false;
			},

			setMenuStyle: function(styles) {
				$(jP.menu).css(styles);
			},

			setPanelStyle: function(styles) {
				$(jP.panel).css(styles);
			},

			showMenu: function() {
				jP.setMenuStyle({
					display: 'block'
				});
				jP.setMenuStyle({
					'z-index': '1'
				});
			},

			hideMenu: function() {
				jP.setMenuStyle({
					'z-index': '-1'
				});
				jP.setMenuStyle({
					display: 'none'
				});
			},

			enableTransitions: function(duration, easing) {
				var formattedDuration = duration/1000;
				var formattedEasing = jP.getCSSEasingFunction(easing);
				jP.disableTransitions();
				$('body').append('<style id="jPanelMenu-style-transitions">.jPanelMenu-panel{-webkit-transition: all ' + formattedDuration + 's ' + formattedEasing + '; -moz-transition: all ' + formattedDuration + 's ' + formattedEasing + '; -o-transition: all ' + formattedDuration + 's ' + formattedEasing + '; transition: all ' + formattedDuration + 's ' + formattedEasing + ';}</style>');
			},

			disableTransitions: function() {
				$('#jPanelMenu-style-transitions').remove();
			},

			enableFixedTransitions: function(selector, id, duration, easing) {
				var formattedDuration = duration/1000;
				var formattedEasing = jP.getCSSEasingFunction(easing);
				jP.disableFixedTransitions(id);
				$('body').append('<style id="jPanelMenu-style-fixed-' + id + '">' + selector + '{-webkit-transition: all ' + formattedDuration + 's ' + formattedEasing + '; -moz-transition: all ' + formattedDuration + 's ' + formattedEasing + '; -o-transition: all ' + formattedDuration + 's ' + formattedEasing + '; transition: all ' + formattedDuration + 's ' + formattedEasing + ';}</style>');
			},

			disableFixedTransitions: function(id) {
				$('#jPanelMenu-style-fixed-' + id).remove();
			},

			getCSSEasingFunction: function(name) {
				switch ( name )
				{
					case 'linear':
						return name;
						break;

					case 'ease':
						return name;
						break;

					case 'ease-in':
						return name;
						break;

					case 'ease-out':
						return name;
						break;

					case 'ease-in-out':
						return name;
						break;

					default:
						return 'ease-in-out';
						break;
				}
			},

			getJSEasingFunction: function(name) {
				switch ( name )
				{
					case 'linear':
						return name;
						break;

					default:
						return 'swing';
						break;
				}
			},

			openMenu: function(animated) {
				if ( typeof(animated) == "undefined" || animated == null ) { animated = jP.options.animated };
				
				jP.clearTimeouts();

				jP.options.before();
				jP.options.beforeOpen();

				jP.setMenuState(true);

				jP.setPanelStyle({ position: 'relative' });
				
				jP.showMenu();

				var animationChecks = {
					none: (!animated)?true:false,
					transitions: (animated && jP.settings.transitionsSupported)?true:false
				};

				if ( animationChecks.transitions || animationChecks.none ) {
					if ( animationChecks.none ) jP.disableTransitions();
					if ( animationChecks.transitions ) jP.enableTransitions(jP.options.openDuration, jP.options.openEasing);

					var newPanelStyle = {};
					newPanelStyle[jP.options.direction] = jP.options.openPosition;
					jP.setPanelStyle(newPanelStyle);

					if ( jP.settings.shiftFixedChildren )
					{
						$(jP.fixedChildren).each(function(){
							var id = $(this).prop("tagName").toLowerCase() + ' ' + $(this).attr('class'),
								selector = id.replace(' ','.'),
								id = id.replace(' ','-')
							;

							if ( animationChecks.none ) jP.disableFixedTransitions(id);
							if ( animationChecks.transitions ) jP.enableFixedTransitions(selector, id, jP.options.openDuration, jP.options.openEasing);

							var newChildrenStyle = {};
							newChildrenStyle[jP.options.direction] = jP.options.openPosition;
							$(this).css(newChildrenStyle);
						});
					}

					jP.timeouts.afterOpen = setTimeout(function(){
						jP.disableTransitions();
						if ( jP.settings.shiftFixedChildren )
						{
							$(jP.fixedChildren).each(function(){
								var id = $(this).prop("tagName").toLowerCase() + ' ' + $(this).attr('class'),
									id = id.replace(' ','-')
								;

								jP.disableFixedTransitions(id);
							});
						}

						jP.options.after();
						jP.options.afterOpen();
						jP.initiateContentClickListeners();
					}, jP.options.openDuration);
				}
				else {
					var formattedEasing = jP.getJSEasingFunction(jP.options.openEasing);

					var animationOptions = {};
					animationOptions[jP.options.direction] = jP.options.openPosition;
					$(jP.panel).stop().animate(animationOptions, jP.options.openDuration, formattedEasing, function(){
						jP.options.after();
						jP.options.afterOpen();
						jP.initiateContentClickListeners();
					});

					if ( jP.settings.shiftFixedChildren )
					{
						$(jP.fixedChildren).each(function(){
							var childrenAnimationOptions = {};
							childrenAnimationOptions[jP.options.direction] = jP.options.openPosition;
							$(this).stop().animate(childrenAnimationOptions, jP.options.openDuration, formattedEasing);
						});
					}
				}
			},

			closeMenu: function(animated) {
				if ( typeof(animated) == "undefined" || animated == null ) { animated = jP.options.animated };

				jP.clearTimeouts();

				jP.options.before();
				jP.options.beforeClose();

				jP.setMenuState(false);

				var animationChecks = {
					none: (!animated)?true:false,
					transitions: (animated && jP.settings.transitionsSupported)?true:false
				};

				if ( animationChecks.transitions || animationChecks.none ) {
					if ( animationChecks.none ) jP.disableTransitions();
					if ( animationChecks.transitions ) jP.enableTransitions(jP.options.closeDuration, jP.options.closeEasing);

					var newPanelStyle = {};
					newPanelStyle[jP.options.direction] = 0 + jP.settings.positionUnits;
					jP.setPanelStyle(newPanelStyle);

					if ( jP.settings.shiftFixedChildren )
					{
						$(jP.fixedChildren).each(function(){
							var id = $(this).prop("tagName").toLowerCase() + ' ' + $(this).attr('class'),
								selector = id.replace(' ','.'),
								id = id.replace(' ','-')
							;

							if ( animationChecks.none ) jP.disableFixedTransitions(id);
							if ( animationChecks.transitions ) jP.enableFixedTransitions(selector, id, jP.options.closeDuration, jP.options.closeEasing);

							var newChildrenStyle = {};
							newChildrenStyle[jP.options.direction] = 0 + jP.settings.positionUnits;
							$(this).css(newChildrenStyle);
						});
					}

					jP.timeouts.afterClose = setTimeout(function(){
						jP.setPanelStyle({ position: jP.settings.panelPosition });

						jP.disableTransitions();
						if ( jP.settings.shiftFixedChildren )
						{
							$(jP.fixedChildren).each(function(){
								var id = $(this).prop("tagName").toLowerCase() + ' ' + $(this).attr('class'),
									id = id.replace(' ','-')
								;

								jP.disableFixedTransitions(id);
							});
						}

						jP.hideMenu();
						jP.options.after();
						jP.options.afterClose();
						jP.destroyContentClickListeners();
					}, jP.options.closeDuration);
				}
				else {
					var formattedEasing = jP.getJSEasingFunction(jP.options.closeEasing);

					var animationOptions = {};
					animationOptions[jP.options.direction] = 0 + jP.settings.positionUnits;
					$(jP.panel).stop().animate(animationOptions, jP.options.closeDuration, formattedEasing, function(){
						jP.setPanelStyle({ position: jP.settings.panelPosition });

						jP.hideMenu();
						jP.options.after();
						jP.options.afterClose();
						jP.destroyContentClickListeners();
					});

					if ( jP.settings.shiftFixedChildren )
					{
						$(jP.fixedChildren).each(function(){
							var childrenAnimationOptions = {};
							childrenAnimationOptions[jP.options.direction] = 0 + jP.settings.positionUnits;
							$(this).stop().animate(childrenAnimationOptions, jP.options.closeDuration, formattedEasing);
						});
					}
				}
			},

			triggerMenu: function(animated) {
				if ( jP.menuIsOpen() ) jP.closeMenu(animated);
				else jP.openMenu(animated);
			},

			initiateClickListeners: function() {
				$(document).on('click',jP.options.trigger,function(){ jP.triggerMenu(jP.options.animated); return false; });
			},

			destroyClickListeners: function() {
				$(document).off('click',jP.options.trigger,null);
			},

			initiateContentClickListeners: function() {
				if ( !jP.options.closeOnContentClick ) return false;

				$(document).on('click',jP.panel,function(e){
					if ( jP.menuIsOpen() ) jP.closeMenu(jP.options.animated);
				});
				
				$(document).on('touchend',jP.panel,function(e){
					if ( jP.menuIsOpen() ) jP.closeMenu(jP.options.animated);
				});
			},

			destroyContentClickListeners: function() {
				if ( !jP.options.closeOnContentClick ) return false;

				$(document).off('click',jP.panel,null);
				$(document).off('touchend',jP.panel,null);
			},

			initiateKeyboardListeners: function() {
				var preventKeyListeners = ['input', 'textarea'];
				$(document).on('keydown',function(e){
					var target = $(e.target),
					prevent = false;
					$.each(preventKeyListeners, function(){
						if (target.is(this.toString())) { prevent = true; }
					});
					if ( prevent ) { return true; }

					for ( mapping in jP.options.keyboardShortcuts ) {
						if ( e.which == jP.options.keyboardShortcuts[mapping].code )
						{
							var key = jP.options.keyboardShortcuts[mapping];

							if ( key.open && key.close ) { jP.triggerMenu(jP.options.animated); }
							else if ( (key.open && !key.close) && !jP.menuIsOpen() ) { jP.openMenu(jP.options.animated); }
							else if ( (!key.open && key.close) && jP.menuIsOpen() ) { jP.closeMenu(jP.options.animated); }

							return false;
						}
					}
				});
			},

			destroyKeyboardListeners: function() {
				$(document).off('keydown',null);
			},

			setupMarkup: function() {
				$('html').addClass('jPanelMenu');
				$('body > *').not(jP.menu + ', ' + jP.options.excludedPanelContent).wrapAll('<div class="' + jP.panel.replace('.','') + '"/>');
				$(jP.options.menu).clone().attr('id', jP.menu.replace('#','')).insertAfter('body > ' + jP.panel);
			},

			resetMarkup: function() {
				$('html').removeClass('jPanelMenu');
				$('body > ' + jP.panel + ' > *').unwrap();
				$(jP.menu).remove();
			},

			init: function() {
				jP.options.beforeOn();

				jP.initiateClickListeners();
				if ( Object.prototype.toString.call(jP.options.keyboardShortcuts) === '[object Array]' ) { jP.initiateKeyboardListeners(); }

				jP.setjPanelMenuStyles();
				jP.setMenuState(false);
				jP.setupMarkup();

				jP.setMenuStyle({ width: jP.options.openPosition });

				jP.checkFixedChildren();
				jP.setPositionUnits();

				jP.closeMenu(false);

				jP.options.afterOn();
			},

			destroy: function() {
				jP.options.beforeOff();

				jP.closeMenu();
				jP.destroyClickListeners();
				if ( Object.prototype.toString.call(jP.options.keyboardShortcuts) === '[object Array]' ) { jP.destroyKeyboardListeners(); }

				jP.resetMarkup();
				var childrenStyles = {};
				childrenStyles[jP.options.direction] = 'auto';
				$(jP.fixedChildren).each(function(){ $(this).css(childrenStyles); });
				jP.fixedChildren = [];

				jP.options.afterOff();
			}
		};

		return {
			on: jP.init,
			off: jP.destroy,
			trigger: jP.triggerMenu,
			open: jP.openMenu,
			close: jP.closeMenu,
			isOpen: jP.menuIsOpen,
			menu: jP.menu,
			getMenu: function() { return $(jP.menu); },
			panel: jP.panel,
			getPanel: function() { return $(jP.panel); }
		};
	};
})(jQuery);