var Moo3DCarousel = new Class({
	Implements: [Events, Options],
	options: {
		containerPosition: 'relative',
		margin: 10,
		centerOffset: { x:0 , y:0 },
		xRadius: 300,
		yRadius: 50,
		rotateDuration: 500,
		fx: { link: 'cancel' },
		ratioMin: 0.4,
		offsetAngle: 0,
		zIndex: 100,
		powerExponent: 0.85,
		mouseWheel: true,
		autoRun: true,
		interval: 3000,
		stopOver: true,
		trigo: true
	},
	_container: null,
	_elements: [],
	_sizeMax: {x:0, y:0},
	_currentIndex: 0,
	_center: {x:0, y:0},
	_evFunct: {},
	_periodical: null,
	_autorun: false,
	initialize: function(parent, options) {
		parent = document.id(parent);
		this.setOptions(options);
		this._container = new Element('div', { 'class': 'Moo3DCarouselOverlay'})
		.setStyles({
			'position': this.options.containerPosition,
			'z-index': this.options.zIndex
		}).inject(parent);
		this._evFunct = {
			wheel: function(ev) { ev.stop(); this[(ev.wheel == 1) ? 'goNext': 'goPrevious'](); }.bind(this),
			winResize: function(ev) { this.init(); }.bind(this),
			mouseEnter: function(ev) { $clear(this._periodical); this.fireEvent('stop'); this._autorun = false; }.bind(this),
			mouseLeave: function(ev) {
				$clear(this._periodical);
				this._periodical = this.goNext.periodical(this.options.interval, this);
				this.fireEvent('start');
				this._autorun = true;
			}.bind(this)
		};
		if ( this.options.mouseWheel )
			this._container.addEvent('mousewheel', this._evFunct.wheel );
		window.addEvent('resize', this._evFunct.winResize );
		if (this.options.autoRun) {
			this._evFunct.mouseLeave();
			if ( this.options.stopOver) {			
				this._container.addEvents({
					'mouseenter' : this._evFunct.mouseEnter,
					'mouseleave' : this._evFunct.mouseLeave
				});
			}
		}
	},
	addElement: function(elem, size) {
		elem = document.id(elem);
		elem.inject(this._container);
		this._elements.push(elem);
		var imgEl = ( elem.get('tag') == 'img' ) ? elem : elem.getElement('img');
		imgEl.setStyle('position', 'absolute');
		size = size || {};
		size.x = imgEl.getSize().x || size.x || imgEl.getProperty('width').toInt();
		//size.x = size.x || imgEl.getProperty('width').toInt() || imgEl.getSize().x;
		size.y = imgEl.getSize().y || size.y || imgEl.getProperty('height').toInt();
		//size.y = size.y || imgEl.getProperty('height').toInt() || imgEl.getSize().y;
		elem.store("Moo3DCarousel:size", size);
		this._sizeMax = {
			x: Math.max(size.x, this._sizeMax.x),
			y: Math.max(size.y, this._sizeMax.y)
		};
		elem.store("Moo3DCarousel:fx", new Fx.Morph(imgEl, $extend({duration: this.options.rotateDuration}), this.options.fx) );
		this.init();
		return this;
	},
	getSize: function() {
		return {
			x: this._sizeMax.x + 2 * ( this.options.margin + this.options.xRadius),
			y: this._sizeMax.y + 2 * ( this.options.margin + this.options.yRadius)
		};
	},
	init: function(index) {
		this._currentIndex = index || this._currentIndex;
		this._center = {
			x: (this._container.getSize().x / 2) + this.options.centerOffset.x,
			y: this.options.centerOffset.y + this.options.yRadius
		};
		this._container.setStyle('height', this.getSize().y );
		var l = this._elements.length;
		for ( var i=0; i<l; i++ ) {
			var elem = this._elements[i];
			var imgEl = ( elem.get('tag') == 'img' ) ? elem : elem.getElement('img');
			var index = ( i + l - this._currentIndex ) % l;
			var teta  = this._getTeta( index );
			var styles = this._getStyles(elem, teta);
			imgEl.setStyles(styles);
		}
		this.fireEvent('init');
		return this;
	},
	_getTeta: function(index) {
		index = index % this._elements.length;
		var teta = (index / this._elements.length) * 2 * Math.PI;
		teta = (teta + Math.PI) % (2 * Math.PI) - Math.PI;
		teta = ((teta > 0) ? 1 : -1) * Math.PI * Math.pow( Math.abs(teta) / Math.PI , this.options.powerExponent);
		return teta;
	},
	_getStyles: function(elem, teta) {
		var size   = elem.retrieve('Moo3DCarousel:size', elem.getSize() );
		var sCoeff = (1-this.options.ratioMin) / 2;
		sCoeff = 1 +  sCoeff * (Math.cos(teta)-1) ;
		var out = {
			width: (size.x * sCoeff).toInt(),
			height: (size.y * sCoeff).toInt()
		};
		$extend( out , {
			'z-index': (this.options.zIndex + sCoeff * 2 * this._elements.length).toInt()
		});
		$extend( out, {
			left: (this._center.x + this.options.xRadius * Math.sin(teta + this.options.offsetAngle) - out.width/2).toInt(),
			top: (this._center.y + this.options.yRadius * Math.cos(teta + this.options.offsetAngle)).toInt()
		});
		return out;
	},
	focus: function(elem) {
		elem = document.id(elem);
		var index = this._elements.indexOf(elem);
		if ( index != -1 ) {
			this.goTo(index);
		}
		return this;
	},
	goPrevious: function() {
		return this.goTo( this._currentIndex - (this.options.trigo ? -1 : 1) );
	},
	goNext: function() {
		return this.goTo( this._currentIndex + (this.options.trigo ? -1 : 1) );
	},
	goTo: function(index) {
		this.init();
		this._currentIndex = index % this._elements.length;
		var l = this._elements.length;
		for ( var i=0; i<l; i++ ) {
			var elem = this._elements[i];
			var fx = elem.retrieve("Moo3DCarousel:fx");
			var index = ( i + l - this._currentIndex ) % l;
			var teta  = this._getTeta( index );
			var styles = this._getStyles(elem, teta);
			fx.start(styles);
		}
		if ( this._autorun ) {
			$clear(this._periodical);
			this._periodical = this.goNext.periodical(this.options.interval, this);
		}
		this.fireEvent('rotateStart', this);
		this.fireEvent('rotateEnd', this ,this.options.rotateDuration);
		return this;
	},
	count: function() {
		return this._elements.length;
	},
	toElement: function() {
		return this._container;
	},
	getFocused: function() {
		var l =  this._elements.length;
		return this._elements[ ((this._currentIndex + l) % l) ];
	}
});
Element.implement({
	moo3DCarousel: function(options) {
		var children = this.getChildren(), moo3DCarousel = new Moo3DCarousel(this, options);
		children.each( function(el) {
			moo3DCarousel.addElement(el);
		});
		return this;
	}
});
window.addEvent('load',function(){
  var mCar = new Moo3DCarousel('images',{mouseWheel: false,stopOver: true});
  $('images').getElements('img').each(function(el,idx){
    mCar.addElement(el);
    el.addEvent('click',function(){mCar.goTo(idx)});
    el.addEvent('mouseover',function(e){
      if(el.getStyle('z-index')==103) el.setStyle('cursor','pointer');
      else el.setStyle('cursor','');
    });
  });
});
