(function($){
	$.fn.threesixty = function(options) {
		var opts = $.extend($.fn.threesixty.defaults, options);
		return $(this).each(function(){
			$this = $(this);
			
			if (undefined == $this.attr('src')) $this.attr('src', opts.images[0]);
			
			swap = $.fn.threesixty.swap;
		
			var t0 = 0;
			var t1 = 0;
		
			var x0 = 0;
			var x1 = 0;
		
			var dx = 0;
			var dt = 0;
			var deltax = 0;
			
			var index = 0;
		
			var time = new Date();
		
			var images = new Array();
			for (var i=0;i < opts.images.length;i++){
				images[i] = new Image();
				images[i].src = opts.images[i];
			}
			
			var distance;
			if (false != opts.distance) {
				distance = opts.distance;
			} else {
				distance = Math.ceil(parseInt($this.width()) / images.length / 3);
			}
			
			var spinner;
		
			$this.mousedown(function(e) {
				clearInterval(spinner);
				$('html').mousemove(function(e) {
					track(e);
					e.preventDefault();
				});
				e.preventDefault();
			});
		
			$('html').bind('mouseup mouseleave', function(e) {
				$('html').unbind('mousemove');
				clearstate();
				pause();
			});
			
			function init(e){
				t1 = time.getTime();
				x1 = e.pageX;
			}
		
			function track(e){
				t0 = t1;
				t1 = time.getTime();
				x0 = x1;
				x1 = e.pageX;
				update();
			}
		
			function update(){
			   dx = x1-x0;
			   dt = t1-t0;
			   move();
			}
		
			function clearstate(){
				deltax = 0;
				x0 = x1 = t0 = t1 = dx = dt = 0;
			}
		
			function move(){
				deltax += Math.abs(dx);
				if (deltax > distance){
					if (dx < 0) {
						next();
					} else {
						prev();
					}
				}
			}

			var n = true; // flags for effiency onNext/onPrev
			var p = true;
			
			function next(){
				p = true;
				index++;
				if (index == images.length) {
					index = 0;
				}
				swap($this, images[index].src);
				deltax = deltax % distance;
				if(n && opts.onNext){
					opts.onNext();
					n = false;
				}
			}
			
			function prev(){
				n = true;
				index--;
				if (index < 0) {
					index = images.length-1
				}
				swap($this, images[index].src);
				deltax = deltax % distance;
				if(p && opts.onPrev){
					opts.onPrev();
					p = false;
				}
			}
			
			function pause(){
				if(opts.onPause){
					opts.onPause();
				}
				n = p = true;
			}
			
			// API
			function spin() {
				var ii = 0;
				clearInterval(spinner)
				spinner = setInterval(function() {
					next();
					ii++;
					if (ii >= images.length){
						pause();
						clearInterval(spinner);
					}
				},85);
			}
			
			var api = {
				spin: spin,
				next: next,
				prev: prev
			};
			
			$this.data('threesixty',api);
		});
	};

	$.fn.threesixty.swap = function(el, url){
		el.attr('src', url);
	};

	$.fn.threesixty.defaults = {
		images : false,
		distance : false,
		onNext : false,
		onPrev : false,
		onPause : false
	};
})(jQuery);