window.FloScroller = new (function($) {
	var postop = undefined;
	var width = undefined;
	var poslist = [];
	var order = [];
	var hovered = undefined;
	var delay = undefined;
	var busy = false;
	this.ready = function(){};
	this.init = function(area) {
		var self = this, $area=$(area);
		var $lis = $area.find("ul li");
		$lis.each(function() {
			var $this = $(this);
			var pos = $this.position();
			if (postop == undefined)
				postop = pos.top;
			if (pos.top == postop)
				poslist[poslist.length] = pos.left;
			order[order.length] = $this;
		});
		var i = 0;
		width = poslist[1]-poslist[0];
		$lis.each(function() {
			var $this = $(this);
			if (i >= poslist.length) {
				$this.css({float: "none", position: "absolute", "left": (poslist[0] - width)+"px", "top": postop+"px"});
			} else {
				$this.css({float: "none", position: "absolute", "left": poslist[i]+"px", "top": postop+"px"});
			}
			i++;
			$this.hover(function(){ self.hover($this); }, function(){ self.hover(undefined) });
		});
		$area.mousemove(function(){ self.moved(); });
	};
	this.hover = function(el){ hovered = el; };
	this.moved = function(){
		if (delay != undefined)
			window.clearTimeout(delay);
		var self=this;
		delay = window.setTimeout(function(){ self.scrollTo(hovered); }, 1000);
	};
	this.scrollTo = function(elm, dir){
		if (!busy) {
			var i;
			// Find block required to move and direction
			if (elm == undefined) {
				if (dir == 1) { i = 0; } // scroll right?
				else if (dir == -1) { i = 2; } // scroll left?
				else return false;
				elm = order[i];
			} else {
				i=0;
				while(i<order.length && order[i][0]!=elm[0]) i++;
				if (i>=order.length) return false;
				if (dir==undefined) {
					if(i<1) dir=1; // scroll right
					else dir = -1; // scroll left
				}
			}
			// Prepare scroll list
			var movelist = [];
			var phantoms = [];
			var movelen = Math.abs(i-1);
			if (movelen == 0) return true;
			var from = Math.min(0, -movelen*dir), to = Math.max(poslist.length, poslist.length-movelen*dir)-1;
			var realfrom = dir>0 ? from : to-poslist.length+1, realto = dir>0 ? from+poslist.length-1 : to;
			//alert("from="+from+"; to="+to+"; realfrom="+realfrom+"; realto="+realto);
			var used = new Array(order.length);
			for(var j=from; j<=to; j++) {
				var it = j<0 ? ( j+Math.ceil(Math.abs(j) / order.length)*order.length ) : ( j-Math.floor(j / order.length)*order.length );
				var el;
				el = order[it];
				if(j<realfrom || j>realto) {
					var p = el.parent();
					el = el.clone();
					p.append(el);
					phantoms[phantoms.length] = el;
				} else
					used[it] = true;
				var pos = poslist[0]+j*width;
				el.css({left: pos+"px"});
				movelist[movelist.length] = el[0];
			}
			var neworder = [];
			for(var j=realfrom,k=0; k<order.length; k++,j++) {
				var it = j<0 ? ( j+Math.ceil(Math.abs(j) / order.length)*order.length ) : ( j-Math.floor(j / order.length)*order.length );
				neworder[neworder.length] = order[it];
				if(!used[it]) order[it].css({left: (-width)+"px"});
			}
			// Run animation!
			busy = true;
			var len = movelen*width, self = this;
			$(movelist).animate({left: (dir<0?"-":"+")+"="+len}, 500, function() { 
				$(phantoms).remove();
				order = neworder;
				if (busy) {
					self.ready(elm);
					busy = false;
				}
			});
			return true;
		} else {
			return false;
		}
	};
})(jQuery);
