/*  Carousel version 1.0
 *  (c) 2010 Outpost Design
 *
 *  SVN FILE: $Id: carousel.js 3297 2010-12-01 22:35:01Z michaelklauss $
 *
 *  EXAMPLE Usage:
 * 
 *  var myCarousel;
 *  Event.observe(window,'load',function() {
 *      myCarousel = carousel({
 *          'containerId':'stage',
 *          'itemWidth':100,
 *          'visibleSlots':5,
 *          'offset':50,
 *          'step':2
 *      });
 *  });
 *------------------------------------------------------------------------*/

var carousel = function( args ) {
	var obj = {
		container: null,
		items    : [],
		slots    : [],
		lock     : false,
		handle   : null,
		initialize: function(args) {
			// update default options
			var h = $H(args);
			h.each(function(item) {
				if( typeof(this.options[item.key]) != 'undefined' ) {
					this.options[item.key] = item.value ;
				}
			}.bind(this));
			// set container element
			if(this.options.containerId !== null) {
				this.container = $(this.options.containerId);
			}
			// select item elements
			if(this.options.itemSelector !== null) {
				this.items = $A(this.container.select(this.options.itemSelector));
			} else {
				this.items = $A(this.container.childElements());
			}
			// define our slots
			var startleft = -(this.options.itemWidth * this.options.step)+this.options.offset;
			var end = (this.options.visibleSlots + (this.options.step*2));
			if(this.options.offset !== 0) {
				end++;
				startleft -= this.options.itemWidth;
			}
			this.slots = $A($R(0,(end-1)));
			if((this.items.length+1)>this.options.visibleSlots && 
					this.slots.length>this.items.length) {
				this.paditems();
			}
			for(i=0; i < this.slots.length; i++) {
				var lft = startleft + (i*this.options.itemWidth);
				this.slots[i] = {
					'left': lft,
					'idx': i
				};
			}
			if(this.options.offset !== 0) {
				var tmp = this.options.step;
				this.options.step = 1;
				this.rotate('back');
				this.options.step = tmp;
			}
			this.rotate('back');
			this.render();
			this.attachui();
		},
		paditems: function() {
			var loops = Math.ceil(this.slots.length/this.items.length);
			var tmpItems = this.items;
			j=0;
			while(j<loops) {			
				var tmp=[];
				for(i=0;i<tmpItems.length;i++) {
					var newNode = tmpItems[i].cloneNode(true);
					this.container.insert({'bottom':newNode});
					tmp.push(newNode);
				}
				this.items = this.items.concat(tmp);
				j++;
			}
		},
		attachui: function() {
			if(this.items.length<this.options.visibleSlots) {
				return;
			}
			['next','back'].each(function(item) {
				var action = function(evt) {
					evt.stop();
					this[item]();
				}.bindAsEventListener(this);
				$$(this.options[item]).each(function(item) {
					item.stopObserving();
					item.observe('click',action);
					item.appear();
				});
			}.bind(this));
		},
		back: function() {
			this.move('back');
		},
		next: function() {
			this.move('next');
		},
		move: function(dir) {
			if(this.lock){return;}
			this.lock = true;
			var batch = [];
			for(i=0;i<this.slots.length;i++) {
				var n = this.options.itemWidth * this.options.step;
				var increment = (dir=='back')? n : -(n) ;
				var div = this.items[this.slots[i].idx];
				var pos = increment + this.slots[i].left;
				batch.push(
					new Effect.Move(div,{'sync': true, 'x':pos, 'y':0, 'mode':'absolute'})
				);
			}
			this.rotate(dir);
			new Effect.Parallel(batch, { 
				duration: this.options.speed,
				afterFinish:function() {
					this.render();
					this.lock = false;
				}.bind(this)
			});
		},
		rotate: function(dir) {
			for(j=0;j<this.options.step;j++) {
				for(i=0;i<this.slots.length;i++) {
					if(dir=='next') {
						this.slots[i].idx += 1;
						if(this.slots[i].idx >= this.items.length) {
							this.slots[i].idx = 0;
						}
					} else {			
						this.slots[i].idx += -(1);
						if(this.slots[i].idx<0) {
							this.slots[i].idx = (this.items.length-(1));
						}
					}
				}
			}
		},
		render: function() {
			for(i=0;i<this.items.length;i++) {			
				this.items[i].setStyle({'position':'absolute','left':'-9000px'});
			}
			for(i=0;i<this.slots.length;i++) {			
				var div = this.items[this.slots[i].idx];
				if(!div){ break; }
				div.setStyle({'position':'absolute','left':(this.slots[i].left+'px')});
			}
		},
		autoMove: function(seconds) {
			if(!seconds){
				interval = 5000;
			} else {
				interval = seconds * 1000; 
			}
			this.handle = setInterval(function(){
				this.move('next');	
			}, interval);				
		},
		options: {
			containerId:   null,  // id of slide container element
			itemSelector:  null,  // expression for selecting items (if something other than all children is required)
			itemWidth:	   null,  // width in pixels of an item in the carousel
			speed:         0.5,   // speed of the transition in seconds
			offset:        0,     // pixel offset for rendering items in the container
			step:          1,     // how many items move at a time
			visibleSlots:  0,     // how many items are visible within our container
			next:          '[class="carouselNext"]',  // expression for selecting elements to use as click trigger for next slide
			back:          '[class="carouselBack"]'   // expression for selecting elements to use as click trigger for back slide
		},
		version: function() {
			return '1.0';
		}
	};
	obj.initialize(args);
	return obj;
};
