(function($) {
 
   $.fn.imageshuffle = function(settings) {
     var config = {'queue_size': 5};
	 
     if (settings) $.extend(config, settings);
	 
	 
	 var container = $(this).eq(0);
	 var holder = $('<div id="imageholder" style="display:none;"></div>').appendTo(container);
	 
	 var positions = config.positions;
	 
	 var active_array = new Array();
	 
	 var image_queue = {
		queue: new Array(),
		cursor: 0,
		add: function(o){
			this.queue.push(o);
		},
		forward_cursor: function(){
			this.cursor = ((this.cursor+1) >= this.queue.length) ? 0 : (this.cursor+1);
		},
		next: function(){
			var temp = this.queue[this.cursor];
			this.forward_cursor();
			return temp;
		},
		shuffleslice: function(){
			this.queue.sort(function() {return 0.5 - Math.random()});
			this.queue.sort(function() {return 0.5 - Math.random()});
			this.queue.sort(function() {return 0.5 - Math.random()});
			this.queue.sort(function() {return 0.5 - Math.random()});
			this.queue.sort(function() {return 0.5 - Math.random()});
			if(this.queue.length >= config.queue_size){
				this.queue = this.queue.slice(0,config.queue_size);
			}
		}
		
	 }
	 
	 methods = {
		// animate the images to their next positions
		animate_objects : function(o) {
			var css = o.data('css');
			var start = o.data('start');
			var end = o.data('end');
			var speed = o.data('speed');

			o.css(start).animate(css,speed,function(){o.css(end);});
		},
		spool_forward : function(o) {
			var css = o.data('css');
			var start = o.data('start');
			var end = o.data('end');
			var speed = o.data('speed');
			
			o.css(start).css(css).css(end);
		},
		initialise_image_data : function() {
			for(var i = 0; i < config.images.length; i++){
				image_queue.add($('<img src="'+config.images[i]+'" />').appendTo(holder));
			}
			image_queue.shuffleslice();
		},
		assign_new_data : function(o,index) {
			o.data('css',positions[index].css);
			o.data('start',positions[index].start);
			o.data('end',positions[index].end);
			o.data('speed',positions[index].speed);
			o.data('index',index);
		},
		assign_initial_data : function(o) {
			o.data('css',positions[0].css);
			o.data('start',positions[0].start);
			o.data('end',positions[0].end);
			o.data('speed',positions[0].speed);
			o.data('index',0);
		},
		index_out_of_bounds : function(index) {
			if(index >= config.positions.length) return true;
			return false;
		},
		get_next_index : function(o) {			
			var newindex = o.data('index')+1;
			return this.index_out_of_bounds(newindex) ? 0 : newindex;
		},
		run_spooler : function(){
			for(var i = 0; i < positions.length; i++){
				for(var i = 0; i < active_array.length; i++) {
					var temp = this.get_next_index(active_array[i]);
					if(!temp){				
						active_array.splice(i,1);
					} else {
						this.assign_new_data(active_array[i],temp);
						methods.spool_forward(active_array[i]);
					}
				}
				var newdata = image_queue.next().clone().appendTo(container);
				this.assign_initial_data(newdata);
				active_array.push(newdata);
				methods.spool_forward(newdata);
			}
		},
		run_animation : function(){
			var dropindex;
			for(var i = 0; i < active_array.length; i++) {
				var temp = this.get_next_index(active_array[i]);
				if(!temp){
						dropindex = i;		
				} else {
					this.assign_new_data(active_array[i],temp);
					methods.animate_objects(active_array[i]);
				}
				
			}
			active_array[dropindex].remove();				
			active_array.splice(dropindex,1);
			var newdata = image_queue.next().clone().appendTo(container);
			this.assign_initial_data(newdata);
			active_array.push(newdata);
			methods.animate_objects(newdata);
		}
		
	 }
 
 
     this.each(function() {
		methods.initialise_image_data();
		methods.run_spooler();
		setInterval (function(){
			methods.run_animation();
		}, 5000 );
     });
 
     return this;
 
   };
 
 })(jQuery);
