/**
 * ProcessWire Panels
 * 
 * Alternative to modal windows. Creates iframe panels that load URLs. 
 * Clicking outside the panel closes it. By default, panels load the requested 
 * URL on mouseover of the a.pw-panel toggle link, unless the pw-panel-reload 
 * class is specified (in which case it loads on click).
 * 
 * Copyright 2016 by Ryan Cramer
 * License: MPL 2.0
 * 
 * REQUIREMENTS
 * ============
 * Include the panel.js and panel.css files in the request. 
 * jQuery is required. jQuery UI is strongly recommended but not required.
 * So far tested only in PW admin themes, but should work outside them too.
 * 
 * BASIC USAGE
 * ===========
 * Give any link a "pw-panel" class and it will open in a left-side panel:
 * 
 *   <a class='pw-panel' href='/path/'>Click to open panel</a>
 * 
 * If clickable element is not an <a> tag, give "data-href" attr containing the URL the panel should open: 
 * 
 *   <span class='pw-panel' data-href='/path/'>Click to open panel</span>
 * 
 * To make a panel open on the right rather than the left, append "pw-panel-right" to the class attribute. 
 * 
 *   <a class='pw-panel pw-panel-right' ...
 * 
 * To specify that the panel should reload the page every time it is opened, append "pw-panel-reload" class.
 * Note that this also makes the panel load the URL on "click" of the a.pw-panel link, rather than "mouseover".
 * 
 *   <a class='pw-panel pw-panel-reload' ...
 * 
 * To specify the target width of the panel use the "data-panel-width" attribute (default width is 50%): 
 * 
 *   <a class='pw-panel' data-panel-width='60%' ... (you may also specify value in "px" if preferred)
 *   
 *     
 * TABBED USAGE
 * ============
 * To specify the text that should appear in the tab connected to the panel provide "data-tab-text" attribute:
 * 
 *   <a class='pw-panel' data-tab-text='Panel Title' ... 
 *     
 * To specify an icon, use "data-tab-icon" attribute with font-awesome icon name (excluding the "fa-" part):
 * 
 *   <a class='pw-panel' data-tab-icon='sitemap' ... 
 * 
 * To specify the offset of the tab from top or bottom, specify "data-tab-offset" attribute. Positive integer 
 * indicates offset from top, whereas negative integer indicates offset from bottom. 
 * 
 *   <a class='pw-panel' data-tab-offset='200' ... 
 * 
 * To specify that a tab should appear even when the panel is closed (on left or right side of screen),
 * append the "pw-panel-tab" class. This serves as an alternative to the toggle link. 
 * 
 *   <a class='pw-panel pw-panel-tab' ...
 *   
 * 
 * REFERENCE
 * =========
 * 
 * CSS Classes for panel toggle element: 
 *   pw-panel: Required for anything that triggers a panel to open.
 *   pw-panel-right: Makes panel open on right side rather than left.
 *   pw-panel-reload: Makes panel reload URL it shows every time panel is opened. 
 *   pw-panel-tab: Specify that a tab should appear for a closed panel (on left or right side of screen).
 *   pw-panel-links: Specify that links in panel should open in panel rather than parent window. 
 *     
 * Data Attributes for panel toggle element:
 *   data-panel-id: ID of element to serve as the panel content (if not using a URL). 
 *   data-panel-width: Width of panel in "px" or "%", i.e. "500px" or "50%" (default=55%).
 *   data-tab-text: Text to appear in the panel's tab.
 *   data-tab-icon: Icon name to display in panel's tab (excluding the "fa-" part).
 *   data-tab-offset: Integer tab offset in px from top of bottom of screen (negative number for bottom offset). 
 *   data-href: Use to specify panel URL when element is something other than <a>.
 *   
 *     
 * 
 */
var pwPanels = {

	/**
	 * Quantity of panels initialized
	 * 
	 */
	qty: 0,
	
	/**
	 * Initialize pwPanels, to be called at document.ready
	 *
	 */
	init: function() {
		
		var url = window.location.href;
		
		if(url.indexOf('pw_panel=1') > -1) {
			// initialize inside of a panel
			$(document).on('mouseover', 'a', function() {
				// make links target the parent window
				var $a = $(this);
				var target = $a.attr('target');
				if(typeof target == "undefined" || target.length == 0) {
					$a.attr('target', '_parent');
				}
			});
			
		} else if(url.indexOf('pw_panel=2') > -1) {
			// don't initialize anything (.pw-panel-links class option)
			
		} else {
			// initialize a page with panels in it
			$('.pw-panel').each(function() {
				var $toggler = $(this);
				pwPanels.addPanel($toggler);
			});
		}
	},
	
	/**
	 * Add a new panel 
	 * 
	 * @param toggler Element that toggles the panel
	 * 
	 */
	addPanel: function($toggler) {
		
		var panelURL = $toggler.attr('data-href');
		var panelID = $toggler.attr('data-panel-id');
		var panelContainerID = 'pw-panel-container-' + (++pwPanels.qty);
		
		// allow for use of data-href or href attribute that references URL to load in panel
		if(typeof panelURL == 'undefined' || !panelURL.length) panelURL = $toggler.attr('href');

		if(typeof panelURL != 'undefined' && panelURL.length) {
			var hash = '';
			if(panelURL.indexOf('#') > -1) {
				var parts = panelURL.split('#');
				panelURL = parts[0];
				hash = '#' + parts[1];
			}
			panelURL += (panelURL.indexOf('?') > -1 ? '&' : '?') + 'modal=panel&pw_panel=';

			if($toggler !== null && $toggler.hasClass('pw-panel-links')) {
				panelURL += '2'; // don't update target of links in panel
			} else {
				panelURL += '1'; // update target of links in panel
			}
			panelURL += hash;
		}
		
		var $icon = $('<i />')
			.attr('class', 'pw-panel-icon fa fa-angle-double-left');
		
		var $span = $('<small />').attr('class', 'ui-button-text')
			.append($icon);
		
		var $btn = $('<a />')
			.attr('class', 'pw-panel-button pw-panel-button-closed ui-button ui-state-default')
			.attr('href', panelURL)
			.on('click', pwPanels.buttonClickEvent)
			.on('mouseover', pwPanels.buttonMouseoverEvent)
			.on('mouseout', pwPanels.buttonMouseoutEvent)
			.append($span);
		
		var $panel = $('<div />')
			.attr('id', panelContainerID)
			.attr('class', 'pw-panel-container pw-panel-container-closed')
			.append($btn);
		
		$('body').append($panel);
		
		if(typeof panelID != 'undefined' && panelID.length) {
			// loading an in-page element rather than a URL
			$('#' + panelID).hide().addClass('pw-panel-element'); // class assigned to in-page element
			$panel.addClass('pw-panel-container-element').attr('data-panel-id', panelID);
		}

		// panel toggler
		if($toggler !== null) {
			pwPanels.initToggler($toggler, $btn, $panel);
		} else {
			$panel.addClass('pw-panel-left');
		}
	},

	/**
	 * Initialize the toggler element, plus $btn and $panel with options from toggler element
	 * 
	 * @param $toggler
	 * @param $btn
	 * @param $panel
	 * 
	 */
	initToggler: function($toggler, $btn, $panel) {

		var panelSide = $toggler.hasClass('pw-panel-right') ? 'right' : 'left';
		var text = $toggler.attr('data-tab-text');
		var icon = $toggler.attr('data-tab-icon');
		var offset = $toggler.attr('data-tab-offset');
		var panelWidth = $toggler.attr('data-panel-width');
		var btnPos = panelSide == 'right' ? 'left' : 'right';
		var btnExtraPx = 1;

		$panel.addClass('pw-panel-tab pw-panel-' + panelSide);
		$panel.attr('data-href', $btn.attr('href'));
		if($toggler.hasClass('pw-panel-reload')) $panel.addClass('pw-panel-reload');

		if(typeof offset != "undefined") {
			offset = parseInt(offset);
			if(offset > -1) {
				// positive number indicates offset from top
				$btn.css('top', offset + 'px');
			} else {
				// negative number indicates offset from bottom
				$btn.css('top', 'auto');
				$btn.css('bottom', Math.abs(offset) + 'px');
			}
		}

		if(typeof text != "undefined" && text.length) {
			var $btnText = $btn.children('.ui-button-text');
			var $text = $("<span />").text(text);
			$btnText.html('<span>' + $text.text() + '</span>');
			$btn.addClass('pw-panel-button-text');
			btnExtraPx = 7;
			//$btn.css(btnPos, (-1 * ($btn.height() + 7)) + 'px');
			//$btn.css('top', parseInt($btn.css('top')) + ($btn.width()) + 'px');
		}
	
		if(typeof icon != "undefined" && icon.length) {
			var $icon = $('<i />').addClass('fa fa-fw fa-' + icon);
			var $text = $btn.children('.ui-button-text');
			if($btn.hasClass('pw-panel-button-text')) {
				$text.prepend($icon);
			} else {
				$text.empty().append($icon);
				$btn.css(btnPos, (-1 * ($btn.outerWidth())) + 'px');
			}
		}
		
		if(typeof panelWidth != 'undefined' && panelWidth.length) {
			$panel.css('width', panelWidth)
			$panel.css(panelSide, '-' + panelWidth);
		}
		
		if(panelSide == 'right') {
			// align button to right edge
			//$btn.css('left', (-1 * (btnExtraPx + $btn.height())) + 'px');
		} else {
			// align button to left edge
			$btn.css('right', (-1 * (btnExtraPx + $btn.height())) + 'px');
		}

		if(!$toggler.hasClass('pw-panel-tab')) {
			// if toggler doesn't specify that a tab/button should show, hide our $btn element
			$btn.addClass('pw-panel-button-hidden');
		}

		// delegate events from toggler to pw-panel-button
		$toggler.click(function() {
			$btn.click();
			return false;
		}).on('mouseover', function() {
			$btn.mouseover();
		}).on('mouseout', function() {
			$btn.mouseout();
		});
	},

	/**
	 * Populate the panel content (iframe if using URL) and return it
	 * 
	 */
	initPanelContent: function($panel) {
		
		var $content = $panel.find('.pw-panel-content');
		var panelID = $panel.attr('data-panel-id');
		
		if($content.length) {
			return $content;
		} else if(typeof panelID != "undefined") {
			var $panelTarget = $('#' + panelID);
			// var $btn = $panel.find('.pw-panel-button').addClass(panelID + '-pw-panel-button'); // if needed for external trigger
			if($panelTarget.length) {
				$content = $('<div />').addClass('pw-panel-content').css('overflow', 'auto');
				$panel.append($content);
				$content.append($panelTarget);
				$panelTarget.show();
				$panelTarget.trigger('pw-panel-init');
			}
		} else {
			$content = $('<iframe />')
				.addClass('pw-panel-content')
				.attr('src', $panel.attr('data-href'));
			$panel.append($content);
		}
		
		return $content;
	}, 

	/**
	 * Event called on window resize
	 * 
	 */
	windowResizeEvent: function() {
		$(".pw-panel-container-init").each(function() {
			var $panel = $(this);
			if($panel.hasClass('pw-panel-container-open')) return;
			var panelWidth = $panel.width();
			var px = (-1 * panelWidth) + 'px';
			if($panel.hasClass('pw-panel-right')) {
				$panel.css('right', px);
			} else {
				$panel.css('left', px);
			}
		});
	},

	/**
	 * Event called on panel button click 
	 * 
	 * @returns {boolean}
	 * 
	 */
	buttonClickEvent: function() {

		var $btn = $(this);
		var $panel = $btn.closest('.pw-panel-container');
		var $panelContent = $panel.find('.pw-panel-content');
		var isOpen = $panel.hasClass('pw-panel-container-open');
		var isLoaded = $panel.hasClass('pw-panel-container-loaded');
		var panelWidth = $panel.width();
		var panelSide = $panel.hasClass('pw-panel-right') ? 'right' : 'left';
		var hasJQUI = typeof jQuery.ui != "undefined";

		function animateFinished() {
			$panel.toggleClass('pw-panel-container-open pw-panel-container-closed');
			$btn.toggleClass('pw-panel-button-open pw-panel-button-closed');
		}
	
		if($('.pw-panel-container-init').length == 0) {
			// attach window resize event only if no panels have been opened before
			// so that we attach it only if needed, and not more than once
			$(window).resize(pwPanels.windowResizeEvent);
		}

		if(isOpen) {

			// close the panel
			
			var px = (-1 * panelWidth) + 'px';
			
			if(hasJQUI) {
				if(panelSide == 'left') {
					$panel.animate({left: px}, 150, animateFinished);
				} else {
					$panel.animate({right: px}, 150, animateFinished);
				}
			} else {
				$panel.css(panelSide, px);
				animateFinished();
			}

			$('body').css('overflow', '');
			
			$("#pw-panel-shade").fadeOut('fast', function() {
				$(this).remove();
			});
			
			$btn.fadeOut('fast', function() {
				$btn.removeClass('ui-state-active');
				$btn.fadeIn('fast');
			});
			
			if(hasJQUI && panelSide == 'left') $panel.resizable('destroy');
			
			if($panel.hasClass('pw-panel-reload')) {
				// force it to create new iframe on every load
				$panel.find('iframe.pw-panel-content').remove();
			}
			
			// trigger panel-closed event
			$(document).trigger('pw-panel-closed', $panel);

		} else {

			// open the panel
			
			if($panel.hasClass('pw-panel-reload') || !isLoaded) {
				// tell the panel to load or reload, since mouseover even didn't
				pwPanels.initPanelContent($panel);
			}
			
			if(hasJQUI) {
				if(panelSide == 'left') {
					$panel.animate({left: 0}, 150, animateFinished);
				} else {
					$panel.animate({right: 0}, 150, animateFinished);
				}
			} else {
				$panel.css(panelSide, 0);
				animateFinished();
			}

			// shade the parent window
			var $shade = $("<div id='pw-panel-shade'>&nbsp;</div>");
			$panel.before($shade).fadeIn('fast');

			// prevent scrolling in parent window
			$('body').css('overflow', 'hidden');

			// if shade is clicked, exit the panel
			$shade.click(function() {
				var $panel = $('.pw-panel-container-open');
				if(!$panel.length) return false;
				$panel.find('.pw-panel-button').click();
			});

			// enable panel to be resized
			// note: resizing only works with left aligned panel
			if(hasJQUI && panelSide == 'left') $panel.resizable({
				handles: 'e',
				start: function(event, ui) {
					// the overlay helps prevent the resizable from losing "grip"
					var $overlay = $('<div />').addClass('pw-panel-resizable-overlay').css({
						position: 'absolute',
						top: 0,
						left: 0,
						width: '100%',
						height: '100%',
						zIndex: 1001, 
						display: 'hidden'
					});
					$panel.append($overlay);
				}, 
				stop: function(event, ui) {
					// pwPanels.lastTabWidth = ui.size.width;
					$('.pw-panel-resizable-overlay').remove();
				}
			});
		
			// indicate that this panel has been opened and is initialized
			$panel.addClass('pw-panel-container-init');
			
			// trigger panel-opened event
			$(document).trigger('pw-panel-opened', $panel);
		}

		return false;
	},

	/**
	 * Event called on panel button mouseover
	 * 
	 */
	buttonMouseoverEvent: function() {

		var $btn = $(this);
		var $panel = $btn.closest('.pw-panel-container');

		$btn.removeClass('ui-state-active').addClass('ui-state-hover');
		
		if($panel.hasClass('pw-panel-container-loaded')) return;
		$panel.addClass('pw-panel-container-loaded');
		
		if(!$panel.hasClass('pw-panel-reload')) {
			// make panel content load on mouseover 
			pwPanels.initPanelContent($panel);
		}
	},

	/**
	 * Event called on panel button mouseout
	 * 
	 */
	buttonMouseoutEvent: function() {

		var $btn = $(this);
		var $panel = $btn.closest('.pw-panel-container');

		if($panel.hasClass('pw-panel-container-open')) $btn.addClass('ui-state-active');
	}

}

jQuery(document).ready(function() {
	pwPanels.init();
});
