(function($){
	defaults = {
		width: 600,
		imgPrev: null,
		imgNext: null
	};
	
	$flow = function( e,o ) {
		this.options = $.extend({}, defaults, o || {} );
		this.clip = e.wrap("<div></div>").parent().addClass("jflow-clip");
		this.container = this.clip.wrap("<div></div>").parent().addClass("jflow-container");
		this.items = e.find("li").addClass('jflow-item');
		this.list = e.addClass("jflow-list");
		this.nextButton = $("<div></div>").addClass("jflow-next").bind("click",this.next).appendTo(this.container);
		if( this.options.imgNext != null ) {
			$("<img/>").attr("src",this.options.imgNext).addClass("jflow-next-img").appendTo(this.nextButton);
		}
		
		this.prevButton = $("<div></div>").addClass("jflow-prev").bind("click",this.prev).appendTo(this.container);
		if( this.options.imgPrev != null ) {
			$("<img/>").attr("src",this.options.imgPrev).addClass("jflow-prev-img").appendTo(this.prevButton);
		}

		this.position = 0;
		this.visibleCount = 1;
		
		$(window).bind("resize.jflow", function() {
			$(".jflow-list").each(function(i,e){
				$(e).data('jflow').resize();
			});
		}).bind("load.jflow", function() {
			$(".jflow-list").each(function(i,e){
				$(e).data('jflow').setwidth();
			});
		});
		
		this.setup();

		return this;
	}
	
	$.extend( $flow.prototype, {
		setwidth: function() {
			this.blockWidth = this.items.width();
			this.resize();
		},
		
		resize: function() {
			var c = this.clip, l= this.list;
			var sideWidth = Math.ceil((c.width() - this.blockWidth) / 2);
			this.visibleCount = 2 * Math.round( c.width() / this.blockWidth / 2 ) + 1;
			this.leftOffset = - Math.floor((this.visibleCount * this.blockWidth - c.width()) /2); 
			this.list.css({
				left: this.leftOffset+"px",
				width: this.blockWidth*(this.visibleCount+2)+"px"
			});
			this.nextButton.css({width:sideWidth+"px"});
			this.prevButton.css({width:sideWidth+"px"});
			var minElem = this.position - Math.floor(this.visibleCount /2);
			var maxElem = this.position + Math.floor(this.visibleCount /2);
			l.empty();
			for( var i=minElem; i<=maxElem; i++ ) {
				l.append( this.get(i) );
			}
		},

		setup: function() {
			var is = this.items, l=this.list, c=this.clip;
			c.css({overflowX:'hidden'});
			l.css({position: 'relative'});
			is.css({
				display:'block',
				float:'left'
			}).each(function(i,e) {
				$(e).addClass("jflow-item-"+i);
			});
		},
		
		prev: function() {
			var jflow = $(this).parent().find(".jflow-list").data("jflow");
			jflow.move( jflow.position - 1 );
		},
		
		next: function() {
			var jflow = $(this).parent().find(".jflow-list").data("jflow");
			jflow.move( jflow.position + 1 );
		},
		
		move: function( pos ) {
			var p = this.position, il = this.items, l = this.list;
			var addedOffset = Math.max(Math.floor( this.visibleCount / 2 ),1);
			if( p < pos ) { // next
				var self = this;
				l.append( this.get(pos + addedOffset ) )
					.animate({
						'left':this.leftOffset - this.blockWidth+"px"
					},{ 
						complete:function() {
							l.find("li:first").remove();
							l.css('left',self.leftOffset+"px");
						}
					});
			} else { // prev
				l.prepend( this.get(pos-addedOffset) ).css('left', this.leftOffset-this.blockWidth+"px")
					.animate({left: this.leftOffset+"px"},{
						complete:function() {
							l.find("li:last").remove();
						}
					});
			}
			this.position = pos;
		},
		
		get: function(pos) {
			var i = this.items;
			var spot = pos % i.length;
			spot = spot < 0 ? spot + i.length : spot;
			return $(i.get(spot)).clone();
		}
	});

	$.fn.flow = function( o ) {
		return this.each(function(i, e) {
			e = $(e);
			return e.data("jflow",new $flow(e,o) );
		});
	};
})(jQuery);
