/*!
 * jQuery mestriaSlider
 *
 * Version 0.7
 * Copyright José Almeida, http://joseafga.com.br
 * Licence GNU/GPL version 2, http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 */

(function($) {
	var defaults = {
		interval : 5000, // time for changing slides (milliseconds)
		sTimeOut : null,
		tSpeed : 500, // transition speed (milliseconds)
		sTransition : ['fade', 'fade'], // type of slide transition, array: first index corresponds to the entry of the slide, second to exit
		cTransition : ['slide', 'slide'], // type of caption transition, array: first index corresponds to the entry of the caption, second to exit
		parallel : false, // exit and entrance of the next slide simultaneously
		preload : true, // preload images before execution
		current : 0, // can be used to select the initial slide - 0=first, 1=second ...
		running : true, // if false starts paused
		mOverPause : true, // when mouse is over the slide animation pause
		mOutPlay : true, // when mouse is out the slide animation play
		interactPause : false, // when the slide is changed in a manner not automatically animation pause, mOutPlay will not resume the animation, play function is necessary for this
		useNav : true, // if you don't want thumbnails put false
		autoNav : true // automatically creates the thumbnails
	};
	
	$.fn.mestriaSlider = function(opts){
		
		var mestriaSliders = [];
		
		this.each(function(){
			// if element does not have an instance of plugin
			if (!jQuery.hasData(this)) {
		    	var ms = $.extend({
		    		$this : $(this),
		    		$items : $(this).children().first().children(),
		    		$captions : [],
			    	$nav : $(this).children().last(),
					_toQueue : null, // stores the last action
					_interacted : false,
					init : function() {						
						// execute thumbnails options
						if (ms.useNav) {
							if (ms.autoNav) {
								// add thumbnails
								var thumbsSrc = '';
								ms.$items.each(function(i, elem) {
									thumbsSrc += ('<div class="thumb"><img src="' + $(elem).find('img').attr('src') + '" alt="thumb" /></div>');
								});
								ms.$nav.append(thumbsSrc);
							}
							// function when click on thumbnails
							ms.$nav.children().click(function() {
								ms.jumpTo($(this).index());
							});
						}
						// distributes captions for respective items
						ms.$items.each(function(i, elem) {
							var $child = $(elem).children('.caption');
							if ($child.length) ms.$captions[i] = $child;
							else ms.$captions[i] = null;
						});
						// add mouse over/out event
						ms.$items.hover(function() {
							if (ms.mOverPause) ms.pause();
						}, function() {
							if (ms.mOutPlay) ms._run('_play');
						});
						// preload images
						if (ms.preload) {
							ms.$this.append('<div class="loading" />');
							$(window).load(function(){
								ms.$this.children('.loading').fadeOut();
								ms._run('_showSlide');
							});
						} else {
							ms._run('_showSlide');
						}
					},
					play : function() {
						ms._interacted = false;
						ms._run('_play');
					},
					pause : function() {
						// if animation is not in progress pauses, else is enqueued
						if (!ms.running) ms._run('_pause');
						else ms._toQueue = '_pause';
					},
					// execute some functions automatically and passed by user, and not forget the next action
					_run : function(action) {
						action = (typeof action !== 'undefined') ? action : null;
						// retrieves action queued
						if (action === null) {
							if (ms._toQueue !== null) {
								action = ms._toQueue;
								ms._toQueue = null;
							}
							else action = '_play';
						}
						var actions  = {
							_play : function() {
								actions._pause();
								if (!(ms.interactPause && ms._interacted))
									// change slides in "interval" milliseconds
									ms.sTimeOut = setTimeout(function() {
										if (!ms.running) { 
											ms.running = true;
											actions._showSlide();
										}
									}, ms.interval);
							},
							_pause : function() {
								clearTimeout(ms.sTimeOut); // clears current time of changing slides
								ms.running = false;
							},
							_showSlide : function() {
								if (ms.$items.eq(ms.current).is(':hidden')){
									if (ms.useNav) ms.activeThumb(true);
									// show slide
									ms.transitions._execute(ms.sTransition[0], ms.$items.eq(ms.current), function() {
										ms.transitions._execute(ms.cTransition[0], ms.$captions[ms.current], function() {
											ms._run();
										});
									});
								} else {
									if (ms.running) {
										ms.jumpTo(ms.current + 1, true);
									}
								}
							},
							_hideSlide : function(to) {
								if (ms.current == to) return actions._play();
								actions._pause();
								ms.running = true;
								function callback() {
									if (ms.useNav) ms.activeThumb(false);
									// go to next slide
									ms.current = to;
									actions._showSlide();
								}
								// hide slide
								ms.transitions._execute(ms.cTransition[1], ms.$captions[ms.current], function(){
									ms.transitions._execute(ms.sTransition[1], ms.$items.eq(ms.current), function(){
										if (!ms.parallel) callback();
									});
									if (ms.parallel) callback();
								});
							}
						};
						return (typeof action === 'number') ? actions._hideSlide(action) : actions[action]();
					},					
					transitions : {
						_execute : function(transition, $el, callback) {
							if (transition == 'random')
								transition = this._getRandom(['fade', 'slide']);
							if ($el != null)
								this[transition]($el, callback);
							else callback();
						},
						// get a random effect for transition
						_getRandom : function(effects) {
							return effects[Math.floor(Math.random() * effects.length)];
						},
						fade : function($el, callback) {
							// show/hide element
							if ($el.is(':hidden')) {
								$el.fadeIn(ms.tSpeed, callback);
							} else {
								$el.fadeOut(ms.tSpeed, callback);
							}
						},
						slide : function($el, callback) {
							// show/hide element
							if ($el.is(':hidden')) {
								$el.slideDown(ms.tSpeed, callback);
							} else {
								$el.slideUp(ms.tSpeed, callback);
							}
						}
					},
					// Boolean on: inform if enable (true) or disable (false) the thumbnail, useful for complex animations
					activeThumb: function(on) {
						ms.$nav.children().eq(ms.current).toggleClass('active');
					},
					// Integer to: slide that will appear
					// Boolean noQueue: run immediately
					jumpTo : function(to, noQueue) {
						noQueue = noQueue || false;
						if(!noQueue) ms._interacted = true;
						// fixes the number of the current slide to the range of items
						to = (to >= ms.$items.length) ? 0 : (to < 0) ? ms.$items.length - 1 : to;
						// if animation is not in progress it is executed, else is enqueued
						if (ms.current != to){
							if (!ms.running || noQueue) ms._run(to);
							else ms._toQueue = to;
						}
					},
					next : function() {
						ms.jumpTo(ms.current + 1);
					},
					prev : function() {
						ms.jumpTo(ms.current - 1);
					}
		    	}, defaults , opts || {});
		    	// store plugin object in element.
		    	ms.$this.data('mestriaSlider', ms);
		    	// run
		    	ms.init();
			} else {
				// retrieves the previously stored data
				ms = $(this).data('mestriaSlider');
			}
			mestriaSliders.push(ms);
		});
		
		// returns the plugin object
		return (mestriaSliders.length === 1) ? mestriaSliders[0] : mestriaSliders;
	};	
})(jQuery);

