/**
 * jQuery.pxEtalage - automated image slider for jQuery
 * written by Michiel Sikma <michiel@wedemandhtml.com>
 * Copyright (C) 2010, PixelDeluxe <http://pixeldeluxe.nl/>
 * All rights reserved.
 * Date: 2010/12/16
 *
 * @author Michiel Sikma
 * @version 0.4
 *
 **/

(function($)
{
	$.fn.pxEtalage = function(options)
	{
		var settings = {
			/* Which effect to use (fade, scroll). */
			effect: "fade",
			/* How long the effect takes to complete. */
			effect_duration: 500,
			
			/* Whether to go wrap the slides around (i.e. go back to 0 after clicking past the end). */
			slide_wrap: false,
			/* Whether to allow automatic sliding or to restrict to user interaction. */
			slide_automation: true,
			/* How long a slide will be seen before moving on to the next. */
			slide_duration: 4000,
			
			/* Which event to listen to for the menu links. */
			menu_event: "mouseenter",
			/* Which event to listen to for the arrows. */
			arrow_event: "click",
			
			/* Actions to perform on animation start. */
			action_in_start: null,
			action_out_start: null,
			/* Actions to perform after the animation finishes. */
			action_in_complete: null,
			action_out_complete: null
		};
		
		/* Perform the plugin code on all elements, then return the jQuery object for chainability. */
		return this.each(function()
		{
			/**
			 * Note that this plugin only works with the proper HTML structure. Here is an example:
			 *
			 * <div class="main">
			 *     <ul class="menu">
			 *         <li><a href="page_a.html">Page A</a></li>
			 *         <li><a href="page_b.html">Page B</a></li>
			 *         <li><a href="page_c.html">Page C</a></li>
			 *         <li><a href="page_d.html">Featured page</a></li>
			 *     </ul>
			 *     <div class="image_wrap">
			 *         <img src="page_a_preview.png" alt="Page A preview" class="slide" />
			 *         <img src="page_b_preview.png" alt="Page B preview" class="slide" />
			 *         <img src="page_c_preview.png" alt="Page C preview" class="slide" />
			 *         <img src="page_d_preview.png" alt="Page D preview" class="slide default" />
			 *     </div>
			 * </div>
			 *
			 * When using arrows instead of a menu of links, the following structure applies:
			 *
			 * <div class="main">
			 *     <div class="arrows">
			 *         <a href="#" class="arrow prev">Previous</a>
			 *         <a href="#" class="arrow next">Next</a>
			 *     </div>
			 *     <div class="image_wrap">
			 *         <img src="page_a_preview.png" alt="Page A preview" class="slide" />
			 *         <img src="page_b_preview.png" alt="Page B preview" class="slide" />
			 *         <img src="page_c_preview.png" alt="Page C preview" class="slide" />
			 *         <img src="page_d_preview.png" alt="Page D preview" class="slide default" />
			 *     </div>
			 * </div>
			 *
			 * The .main div here represents the element on which the $.fn.pxEtalage() method was called.
			 * Its class is arbitrary. .menu and .image_wrap are required, however. The images with
			 * .slide might as well be <div> elements.
			 *
			 **/
			
			/* $main refers to the HTML element on which the $.fn.pxEtalage() method was called. */
			var $main = $(this);
			var a, z;
			
			var onImage = false;
			var clickedButton = false;
			
			if (settings) {
				/* Override default settings. */
				$.extend(settings, options);
				if (!/^fade|scroll$/.test(settings.effect)) {
					window.console && console.warn("The requested effect (%o) cannot be found.", settings.effect);
				}
			}
			
			/* Index all the images and determine their default. */
			var $image_wrap = $(".image_wrap", $main);
			var $images = $(".slide", $image_wrap);
			if ($images.length <= 1) {
				/* If there are no images, bail out. */
				$(".arrows", $main).hide();
				return;
			}
			for (a = 0, z = $images.length; a < z; ++a) {
				/* Number all of the images. */
				$.data($images[a], "n", a);
				if (settings.effect == "scroll") {
					$.data($images[a], "pos", $($images[a]).position());
				}
			}
			var max_z = 5;
			var $default_image = $(".slide.default", $image_wrap);
			if ($default_image.length == 0) {
				$default_image = $($images[0]);
			}
			var default_n = $.data($default_image[0], "n");
			var hide_default = true;
			max_z = Number($default_image.css("zIndex"));
			var $previous_image = $default_image;
			
			var $menu = $(".menu", $main);
			var $arrows = $(".arrows", $main);
			var uses_menu = $menu.length > 0;
			var uses_arrows = $arrows.length > 0;
			if (settings.effect == "fade") {
				$images.fadeTo(0, 0);
				$default_image.fadeTo(0, 1);
			}
			if (settings.effect == "scroll") {
			}
			
			/* Function used to move to the next or previous slide. */
			function adjecent_slide(offset)
			{
				show_slide(get_adjecent_slide_n(offset));
			}
			
			/* Function used to show a particular slide. */
			function show_slide(n)
			{
				if (uses_menu) {
					$menu_links.removeClass("active");
					$($menu_links[n]).addClass("active");
				}
				var $image = $($images[n]);
				if ($previous_image[0] == $image[0]) {
					return;
				}
				
				switch (settings.effect) {
					case "fade":
						max_z += 1;
						$image.css({zIndex: max_z});
						settings.action_in_start != null && settings.action_in_start.apply($image[0]);
						$image.animate({opacity: 1}, {duration: settings.effect_duration, queue: false, complete: settings.action_in_complete});
						if ($previous_image && $previous_image[0] != $image[0]) {
							settings.action_out_start && settings.action_out_start.apply($previous_image[0]);
							$previous_image.animate({opacity: 0}, {duration: settings.effect_duration, queue: false, complete: settings.action_out_complete});
						}
						if (hide_default && $default_image[0] != $image[0]) {
							/* Hide the default image if it hasn't been hidden already. */
							hide_default = false;
							settings.action_out_start && settings.action_out_start.apply($default_image[0]);
							$default_image.animate({opacity: 0}, {duration: settings.effect_duration, queue: false, complete: settings.action_out_complete});
						}
						break;
					case "scroll":
						var pos = $.data($image[0], "pos");
						$image_wrap.animate({marginLeft: -pos.left, marginTop: -pos.top}, {duration: settings.effect_duration, queue: false});
						break;
				}
				$previous_image = $image;
				
				if ($main && settings.slide_automation && jQuery.timer) {
					clickedButton = true;
					onImage = true;
					$main.oneTime(1000, "resume_playing", function()
					{
						clickedButton = false;
						onImage = false;
					});
				}
			}
			
			/* Function used to get the next image in line. */
			function get_adjecent_slide_n(offset)
			{
				if (offset == null) {
					offset = 1;
				}
				var next_n = $.data($previous_image[0], "n") + offset;
				if (next_n > $images.length - 1 && settings.slide_wrap) {
					next_n = 0;
				}
				if (next_n < 0 && settings.slide_wrap) {
					next_n = $images.length - 1;
				}
				if (next_n > $images.length - 1 && !settings.slide_wrap) {
					next_n = $images.length - 1;
				}
				if (next_n < 0 && !settings.slide_wrap) {
					next_n = 0;
				}
				return next_n;
			}
			
			if (uses_menu) {
				/* Link the hover command of the menu items to their corresponding slides. */
				var $menu_links = $("a", $menu);
				var $link;
				for (a = 0, z = $menu_links.length; a < z; ++a) {
					$link = $($menu_links[a]);
					$.data($menu_links[a], "n", a);
					$link[settings.menu_event](function()
					{
						show_slide($.data(this, "n"));
						return false;
					});
					if (a == default_n) {
						$link.addClass("active");
					}
				}
			}
			if (uses_arrows) {
				/* Link the arrows to the next/prev actions. */
				var $arrow_links = $(".arrow", $arrows);
				var $arrow_link;
				for (a = 0, z = $arrow_links.length; a < z; ++a) {
					$arrow_link = $($arrow_links[a]);
					if ($arrow_link.hasClass("prev")) {
						$.data($arrow_links[a], "offset", -1);
					}
					if ($arrow_link.hasClass("next")) {
						$.data($arrow_links[a], "offset", 1);
					}
					$arrow_link[settings.arrow_event](function()
					{
						adjecent_slide($.data(this, "offset"));
						return false;
					});
				}
			}
			
			/* Set up automatic sliding if it is enabled. */
			if (settings.slide_automation) {
				if (jQuery.timer) {
					function start_timer()
					{
						$main.everyTime(settings.slide_duration, "slide_automation", function()
						{
							if (onImage == false) {
								show_slide(get_adjecent_slide_n());
							}
						});
					}
					start_timer();
					/* Make sure sliding is paused when the user hovers over the menu. */
					$menu.mouseenter(function()
					{
						onImage = true;
					});
					$menu.mouseleave(function()
					{
						if (clickedButton == false) {
							onImage = false;
						}
					});
				} else {
					window.console && console.warn("jQuery Timers plugin doesn't seem to be present. It's required for automatic sliding. Download it at http://plugins.jquery.com/project/timers. To hide this warning, set slide_automation to %o.", false);
				}
			}
			
			/* Last check to ensure integrity. */
			if (uses_menu && $menu_links.length > $images.length) {
				window.console && console.warn("Amount of menu links (%o) and images (%o) is not the same.", $menu_links.length, $images.length);
			}
		});
	}
})(jQuery);
