/*

 * jQuery Mosaic Shuffle Plugin

 * http://ngoar.com/jquery/mosaicshuffle/

 *   Inspired by jQuery Cycle Lite Plugin

 *   http://malsup.com/jquery/cycle/lite/

 * Copyright (c) 2010 V. Donchenko

 * Version: 1.0 (17/05/2010)

 * Dual licensed under the MIT and GPL licenses:

 * http://www.opensource.org/licenses/mit-license.php

 * http://www.gnu.org/licenses/gpl.html

 * Requires: jQuery v1.2.3 or later

 */

	

;(function($) {



	var ver = '1.2.1'; //with hardcoded 4 calls of "go()" function



$.fn.mosaicshuffle = function(options) {

    return this.each(function() {

        options = options || {};

        if (this.cycleTimeout) clearTimeout(this.cycleTimeout);



        var $container = $(this);



        var opts = $.extend({}, $.fn.mosaicshuffle.defaults, options || {}, $.metadata ? $container.metadata() : $.meta ? $container.data() : {});

        opts.before = opts.before ? [opts.before] : [];

        opts.after = opts.after ? [opts.after] : [];

        opts.after.unshift(function(){ opts.busy=0; });

        		        

        var $slides = opts.slideExpr ? $(opts.slideExpr, this) : $container.children();



        if (opts.items < 1)

        	opts.items = 1;



        if (opts.rotate < 1)

        	opts.rotate = 1;

        

        var $visibleSlides = $slides.slice(0,opts.items);

        var $invisibleSlides = $slides.slice(opts.items);

        if ($invisibleSlides.size() == 0) {

            if (window.console && window.console.log)

                window.console.log('terminating; too few items to shuffle: ' + $invisibleSlides.size());

            return;

        }

        

        if ( opts.rotate > $visibleSlides.size() || opts.rotate > $invisibleSlides.size())

        	opts.rotate = $visibleSlides.size() > $invisibleSlides.size() ? $invisibleSlides.size() : $visibleSlides.size();

        

        $visibleSlides.each(function() {

            var $el = $(this);

            $el.css({opacity:1,display:'block'});

        });

        $invisibleSlides.each(function() {

            var $el = $(this);

            $el.css({opacity:0,display:'none'});

        });



		



        if (opts.fadeOutSpeed) {

            if (opts.fadeOutSpeed.constructor == String)

                opts.fadeOutSpeed = {slow: 1200, fast: 400}[opts.fadeOutSpeed] || 800;

        }

        if (opts.fadeInSpeed) {

            if (opts.fadeInSpeed.constructor == String)

                opts.fadeInSpeed = {slow: 1200, fast: 400}[opts.fadeInSpeed] || opts.fadeOutSpeed;

        }

        if (opts.delay) {

            if (opts.delay.constructor == String)

                opts.delay = {'long': 4800, 'short': 800}[opts.delay] || 2400;

        }

        

        

        opts.interval = opts.delay + opts.fadeInSpeed + opts.fadeOutSpeed;



		opts.visibleSlides = $visibleSlides.size();

		opts.invisibleSlides = $invisibleSlides.size();

		



		opts.animating=[];

	    opts.visibleSwaps=[];

	    opts.invisibleSwaps=[];

		

		for (i=0;i<opts.rotate;i++) {

			opts.animating[i] = 0;

			$.fn.mosaicshuffle.shuffle(opts,i);

		}

		this.cycleTimeout=new Array();



	str = "";

        if (opts.delay) {

		for (i=0;i<opts.rotate;i++){

		str+= "offset=opts.delay+opts.timeOffset*"+i+";this.cycleTimeout["+i+"] = setTimeout(function() {go($container,opts,"+i+")},offset);\n";
		}
		eval(str);

        }

        

 

    });

   

};





function defineIndexOf(arrName){

	arrName.indexOf = function(obj, start) { 

	     for (var i = (start || 0), j = this.length; i < j; i++) { 

	         if (this[i] == obj) { return i; } 

	     } 

	     return -1; 

	} 



}





$.fn.mosaicshuffle.shuffle = function(opts,pos) {

	opts.visibeSwapOffset = Math.floor(Math.random() * opts.visibleSlides);

    opts.invisibeSwapOffset = Math.floor(Math.random() * opts.invisibleSlides);



    opts.visibleSwap = opts.visibeSwapOffset;

    opts.invisibleSwap = opts.invisibeSwapOffset + opts.visibleSlides;



    

	var i = pos ? pos : 0;

	opts.visibleSwaps[i] = -1;

	var rnd = Math.floor(Math.random() * opts.visibleSlides);

	if (!opts.visibleSwaps.indexOf) {

		defineIndexOf(opts.visibleSwaps);

	} 



	while (opts.visibleSwaps.indexOf(rnd) != -1) {

		rnd = Math.floor(Math.random() * opts.visibleSlides);

	}

	opts.visibleSwaps[i] = rnd;



	if (!opts.invisibleSwaps.indexOf) {

		defineIndexOf(opts.invisibleSwaps);

	} 



	opts.invisibleSwaps[i] = -1;



	var rnd = Math.floor(Math.random() * opts.invisibleSlides)

			+ opts.visibleSlides;

	

	while (opts.invisibleSwaps.indexOf(rnd) != -1) {

		rnd = Math.floor(Math.random() * opts.invisibleSlides)

				+ opts.visibleSlides;

	}

	opts.invisibleSwaps[i] = rnd;



};		







function go($container,opts,pos) {





    if (opts.animating[pos]) return;



    opts.animating[pos] = 1;

	

	$.fn.mosaicshuffle.shuffle(opts,pos);

 

	var afterSwap = function() {

		opts.animating[pos] = 0;

        if (opts.delay)

            $container.cycleTimeout = setTimeout(

		            function() {

                		go($container,opts,pos);

                	}, opts.delay);

		

	};

    

    var doSwap = function() {

    	swap($container,opts,pos);

    	$.fn.mosaicshuffle.custom($container,pos,false,opts,afterSwap);

    }; 

    

	$.fn.mosaicshuffle.custom($container,pos,true,opts,doSwap,pos);





};



function slides($container,opts) {

	return opts.slideExpr ? $(opts.slideExpr, $container) : $container.children();

}

	

function visibleSwapNode($container,opts,pos) {

    var $slides = slides($container,opts);

	return $($slides.get(opts.visibleSwaps[pos]))	

}



function invisibleSwapNode($container,opts,pos) {

    var $slides = slides($container,opts);

	return $($slides.get(opts.invisibleSwaps[pos]))	

}





function swap($container,opts,pos) {

    var $slides = slides($container,opts);



	var $src = visibleSwapNode($container,opts,pos);

	var $dst = invisibleSwapNode($container,opts,pos);

	

	var new_src = $dst.clone(true);

	var new_dst = $src.clone(true);



	$src.replaceWith(new_src);

	$dst.replaceWith(new_dst);



    $slides = opts.slideExpr ? $(opts.slideExpr, this) : $container.children();



	$src = null;

	$dst = null;

}





$.fn.mosaicshuffle.custom = function($container,pos,beforeSwap,opts,cb) {

    var $v = visibleSwapNode($container,opts,pos);

    var $i = invisibleSwapNode($container,opts,pos);

    

    if( beforeSwap ) {

    	$v.css({opacity:1});

    	$v.animate({opacity:0}, opts.fadeOutSpeed, opts.easeOut, cb );

    } else {

    	$v.css({opacity:0,display:'block'});

    	$v.animate({opacity:1}, opts.fadeInSpeed, opts.easeOut, cb );

    	$i.css({opacity:0,display:'none'});

    }

};





$.fn.mosaicshuffle.ver = function() { return ver; };



$.fn.mosaicshuffle.defaults = {

	items:		   9,			

    delay:         3200, 

    fadeOutSpeed:  1200,  

    fadeInSpeed:   1200,

    rotate:        4,

    timeOffset:   500,

    slideExpr:     null  

};



})(jQuery);
