/********************************************************************************
*                                                                               *
*       yyacum : Yyacum yet another carousel using mootools (1.2)	        *
*                                                                               *
*       Author :  poudro - http://scripts.poudro.org                            *
*                                                                               *
*       Open Source MIT Licence                                                 *
*                                                                               *
*********************************************************************************/

var yyacum = new Class ({
	Implements : Options,

	options: {
		speed: 1,
		maxSpeed: 5,
		imgClass: 'yyacum',
		direction: 'horizontal',
		clickable: true,
		inputArray: [],
		dispose: false,
		imgAnchors: false,
		imgAnchorsStartOpac: 0.7,
		legend: false
	},

	initialize: function(contDiv, options) {
		var i;
		this.setOptions(options);

		this.contDiv = $(contDiv);
		this.contDiv.setStyle('overflow','hidden');
		this.contDivWidth = this.contDiv.getCoordinates().width;
		this.contDivHeight = this.contDiv.getCoordinates().height;

		this.cloneDiv = [];
		this.cloneDiv[0] = new Element('div', {'styles':{'display':'block','position':'absolute','left':0,'top':0}}).inject(this.contDiv);

		if(this.options.legend)
			this.legend = new Element('div',{'styles':{'position':'absolute','color':'white','background-color':'black','padding':10,'opacity':0.75}});
		
		switch (this.options.direction) {
			case 'vertical':
				this.divDim1='width';	
				this.divDim2='height';
				this.divPos='top';
				this.contDivRefCoord = this.contDivHeight;
				break;
			default:
				this.divDim1='height';	
				this.divDim2='width';
				this.divPos='left';
				this.contDivRefCoord = this.contDivWidth;
				break;
		}
		this.cloneDiv[0].setStyle(this.divDim1,this.contDivHeight);

		this.ourLeft = 0;
		this.divWidth = 0;

		if (this.options.inputArray.length != 0)
			this.injectImgViaAssets();
		else
			this.injectImgViaTags();
	},
	
	moveOpts: function() {
		if (this.options.speed<0)
			this.sign = -1;
		else
			this.sign = 1;
		this.timeStep=10000*this.divWidth/(Math.abs(this.options.speed)*this.contDivRefCoord);
	},
	
	drawCarousel: function () {
		var i,nextPos;
		this.nextMove = {};
		this.numClones = 2+Math.ceil(this.contDivRefCoord/this.divWidth);
		for (i=1; i<this.numClones; ++i) 
			this.cloneDiv[i] = this.cloneDiv[0].clone().setStyle(this.divPos,this.cloneDiv[i-1].getCoordinates(this.contDiv)[this.divPos]+this.divWidth).inject(this.contDiv);

		this.innerImages = $$('#'+ this.contDiv.id + ' img'); 
		if (this.options.imgAnchors)
			this.innerImages.each(function(image){image.set('opacity',this.options.imgAnchorsStartOpac)},this);
		this.innerImages.set('morph',{link:'cancel'});

		this.moveOpts();
		this.cloneFx = new Fx.Elements(this.cloneDiv,{duration:this.timeStep,transition:'linear',link:'cancel'});
		this.setFxToPos();
		if (this.options.clickable)
			this.onClickDo();
		if (this.options.imgAnchors)
			this.contDiv.addEvents({
				'mousemove': function(ev){
					$clear(this.carousel_p);
					var target = $(ev.target);
					var index = this.innerImages.indexOf(target);
					this.innerImages.morph({opacity:this.options.imgAnchorsStartOpac});
					if (index != -1) {
						this.innerImages[index].morph({opacity:1});
					}
					this.cloneFx.pause();
					if (this.options.legend&&(target.match('img'))&&(this.legends.get(target.src)!=''))
						this.legend.set('html',this.legends.get(target.src)).setStyles({'top':ev.page.y+15,'left':ev.page.x+15}).inject(document.body);
					if (this.options.legend&&this.legends.get(target.src)=="")
						this.legend.dispose();
				}.bind(this),
				'mouseleave': function(){
					this.innerImages.morph({opacity:this.options.imgAnchorsStartOpac});
					if (this.options.legend)
						this.legend.dispose();
					this.cloneFx.resume().chain(function(){this.moveCarousel()}.bind(this));
				}.bind(this),
				'click': function(ev){
					var target = $(ev.target);
					if (target.match('img')&&(this.anchors.get(target.src)!=''))
						window.location.href = this.anchors.get(target.src);
				}.bind(this)
			});
		this.moveCarousel();
	},
	
	moveCarousel: function(){
		this.setFxStartPos();
		this.cloneFx.start(this.nextMove);
		this.carousel_p = (function () {
			this.setFxStartPos();
			this.cloneFx.start(this.nextMove);
		}).periodical(this.timeStep, this);
	},

	setFxStartPos: function(){
		for (i=0; i<this.numClones; ++i) 
			this.cloneDiv[i].setStyle(this.divPos,(i-1)*this.divWidth);	
	},
	
	setFxToPos: function(){
		var nextPos;
		for (i=0; i<this.numClones; ++i) {
			nextPos = (i-1+this.sign)*this.divWidth;
			if (this.options.direction=='vertical')
				this.nextMove[i] = {'top': nextPos};
			else
				this.nextMove[i] = {'left': nextPos};
		}
	},
	
	changeOpts: function(){
		if (this.carousel_p)
			this.carousel_p = $clear(this.carousel_p);
		this.cloneFx.cancel();

		var currentLocation = this.cloneDiv[0].getCoordinates(this.divCont)[this.divPos];
		this.moveOpts();
		this.setFxToPos();
		this.cloneFx.options.duration = Math.abs(this.timeStep*(currentLocation-(this.sign-1)*this.divWidth)/(this.sign*this.divWidth));
		this.cloneFx.start(this.nextMove).chain(function(){this.cloneFx.options.duration = this.timeStep; this.moveCarousel();}.bind(this));
	},
	
	injectImgViaTags: function() {
		this.imagesLoaded_p = (function () {
			var i,h,w,toAdd;

			this.loaded = 0;
			$each(document.images, function(img,ind) {
				if (document.images[ind].complete)
					++this.loaded;
			}, this);

			if (this.loaded==document.images.length) {
				$clear(this.imagesLoaded_p); 
				this.images = $$('img.'+this.options.imgClass);
				this.anchors = new Hash();
				this.legends = new Hash();
				if (this.images.length != 0) {
					for (i=0; i<this.images.length; ++i) {
						var imageCoords = this.getImageCoords(this.images[i],i);
						if (this.options.imgAnchors)
							this.anchors.set(this.images[i].src,this.images[i].getParent());
						if (this.options.legend)
							this.legends.set(this.images[i].src,this.images[i].alt);
						new Asset.image(this.images[i].src)
								 .inject(this.cloneDiv[0]).setStyles({'position':'absolute', 'height':imageCoords.h, 'width':imageCoords.w, 'left':0})
								 .setStyle(this.divPos,this.ourLeft);
						this.grow(imageCoords.toAdd);
						if (this.options.dispose)
							this.images[i].destroy();
					}
					this.drawCarousel();
				}
			}
		}).periodical(50,this);					
	},
	
	injectImgViaAssets: function () {
		var asset_images = [];
		new Asset.images(this.options.inputArray, {
			onProgress: function (ind) {
				asset_images[ind]=this;				
			},
			
			onComplete: (function () {
				asset_images.each(function(image,ind){
					var imageCoords = this.getImageCoords(image,ind);
					image.inject(this.cloneDiv[0]).setStyles({'position':'absolute', 'height':imageCoords.h, 'width':imageCoords.w, 'left':0}).setStyle(this.divPos,this.ourLeft);	
					this.grow(imageCoords.toAdd);
				},this)
				this.drawCarousel();				
			}).bind(this)
		});
	},
					
	getImageCoords: function(image,ind) {				
		var h,w,toAdd;
		if (this.options.direction=='vertical') {
			w=this.contDivWidth;
			h=w*image.height/image.width;	
			toAdd=h;
		} else {
			h=this.contDivHeight;
			w=h*image.width/image.height;	
			toAdd=w;
		}
		return {'w':w, 'h':h, 'toAdd':toAdd};
	},
	
	grow: function(toAdd) {
		this.cloneDiv[0].setStyle(this.divDim2,this.divWidth+toAdd);
		this.divWidth = this.cloneDiv[0].getCoordinates(this.contDiv)[this.divDim2];
		this.cloneDiv[0].setStyle(this.divPos,-this.divWidth);
		this.ourLeft += toAdd;
	},
	
	onClickDo: function(){
		this.contDiv.addEvent('click', function(ev) {
			ev = new Event(ev).stop();
			var l,r;
			l=this.contDiv.getCoordinates()[this.divPos];
			r=l+this.contDivRefCoord;
			if (this.options.direction=='vertical')
				this.options.speed=(2*(ev.client.y-l)/(r-l)-1)*this.options.maxSpeed;
			else
				this.options.speed=(2*(ev.client.x-l)/(r-l)-1)*this.options.maxSpeed;
			this.changeOpts();
		}.bind(this));
	}		
});
