/** InfiniteScroller *	 *	Developped for Alfi *	@author : Michel-Ange K. partikule, 2010 * */InfiniteScroller = new Class({	Extends: Scroller,	options: {		mode: 'horizontal',		nbElements: 4,		fps: 50	},	initialize: function(element, options){		this.setOptions(options);		this.element = document.id(element);		this.docBody = document.id(this.element.getDocument().body);		this.listener = ($type(this.element) != 'element') ?  this.docBody : this.element;		this.timer = null;		this.bound = {			attach: this.attach.bind(this),			detach: this.detach.bind(this),			getCoords: this.getCoords.bind(this)		};		this.buildArea();	},	buildArea:function()	{		this.scroller = this.element.getFirst('div');		// Dupliquate content to scroll infinitely		this.scroller.getChildren().clone().inject(this.scroller);		this.scroller.getChildren().each(function(item, idx){			item.setProperty('id', 'el' + idx);		})		var p = this.scroller.getFirst();		var size = p.getSize();			// Set the container size		var X = size.x * this.options.nbElements;		var Y = size.y * this.options.nbElements;				this.element.setStyles({			'overflow': 'hidden',			'height': (this.options.mode == 'horizontal') ? size.y : Y,			'width': (this.options.mode == 'horizontal') ? X : size.x		});				// Set the child size		var n = this.scroller.getChildren().length;				this.scroller.setStyles({			'height': (this.options.mode == 'horizontal') ? size.y : n * size.y,			'width': (this.options.mode == 'horizontal') ? n * size.x : size.x		});				// Set the sensitive area size		this.options.area = (this.options.mode == 'horizontal') ? X/2 : Y/2;			},	start: function(){		this.listener.addEvents({			mouseenter: this.bound.attach,			mouseleave: this.bound.detach		});	},	stop: function(){		this.listener.removeEvents({			mouseenter: this.bound.attach,			mouseleave: this.bound.detach		});		this.detach();		this.timer = $clear(this.timer);	},	attach: function()	{		this.listener.addEvent('mousemove', this.bound.getCoords);		this.timerOut = $clear(this.timerOut);	},	detach: function(ev)	{//		this.log('ev',this.timer);			this.listener.removeEvent('mousemove', this.bound.getCoords);		this.timer = $clear(this.timer);				this.smoothOut();	},	smoothOut: function(event){		if (!this.timerOut && this.change) this.timerOut = this.smoothOutCalculate.periodical(Math.round(1000 / this.options.fps), this);	},	smoothOutCalculate: function()	{		var	size = this.element.getSize(), 			pos = this.element.getOffsets(),			d = 0,			v = 0,			direction= 1;			var speed = {x:this.change.x * this.options.fps, y:this.change.y * this.options.fps};				var dir = (this.options.mode == 'horizontal') ? 'x' : 'y' ;		if (speed[dir] > 0)		{			// distance = page position - origin			d = this.page[dir] - pos[dir] - (size[dir] / 2);			direction = -1;		}		else if (speed[dir] < 0)			d = (pos[dir] + (size[dir] / 2)) - this.page[dir];					v = d / 15;		this.page[dir] += v * direction;		if (v < 0.5)			this.timerOut = $clear(this.timerOut);		// this.log('x', v);						this.scroll();	},	scroll: function()	{		var size = this.element.getSize(), 			scroll = this.element.getScroll(), 			pos = this.element != this.docBody ? this.element.getOffsets() : {x: 0, y:0}, 			scrollSize = this.element.getScrollSize(), 			change = {x: 0, y: 0};				for (var z in this.page) 		{					if (this.page[z] < (this.options.area + pos[z]) && scroll[z] != 0)				change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity;			else if (this.page[z] + this.options.area > (size[z] + pos[z]) && scroll[z] + size[z] != scrollSize[z])				change[z] = (this.page[z] - size[z] + this.options.area - pos[z]) * this.options.velocity;			else			{				if (this.options.mode == 'horizontal') 				{					// Swith when arriving max right					if (scroll.x == 0) {						this.element.scrollTo(scrollSize.x/2, 0);						break;					}					if (scroll.x == scrollSize.x - size.x)					{						this.element.scrollTo(scroll.x - scrollSize.x/2, 0);						break;					}				}					if (this.options.mode == 'vertical') {										if (scroll.y == 0) {						this.element.scrollTo(0, scrollSize.y/2);						break;					}						if (scroll.y == scrollSize.y - size.y) {						this.element.scrollTo(0, scroll.y - scrollSize.y/2);						break;					}				}			}		}//		log.log('change', change.x + '::' + change.y);				this.change = {x: change.x, y: change.y};		if (change.y || change.x) 			this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]);	},			log: function(key, value, clean) {				if (clean== true)		{			$('debug').set('html', key + ':' + '<b>' + value + '</b><br/>');		}		else		{			$('debug').set('html', $('debug').get('html') + key + ':' + '<b>' + value + '</b><br/>');		}	},	log2: function(key, value, clean) {				$('debug2').setStyles({			// 'font-size' : parseInt(Math.random()/4 * 10) * 30 + 'px'		});				if (clean== true)		{			$('debug2').set('html', key + ':' + '<b>' + value + '</b><br/>');		}		else		{			$('debug2').set('html', $('debug2').get('html') + key + ':' + '<b>' + value + '</b><br/>');		}	}});
