$A = function(iterable, start, length){
	if (Browser.Engine.trident && $type(iterable) == 'collection'){
		start = start || 0;
		if (start < 0) start = iterable.length + start;
		length = length || (iterable.length - start);
		var array = [];
		for (var i = 0; i < length; i++) array[i] = iterable[start++];
		return array;
	}
	start = (start || 0) + ((start < 0) ? iterable.length : 0);
	var end = ((!$chk(length)) ? iterable.length : length) + start;
	return Array.prototype.slice.call(iterable, start, end);
};

(function(){
	var natives = [Array, Function, String, RegExp, Number];
	for (var i = 0, l = natives.length; i < l; i++) natives[i].extend = natives[i].implement;
})();

window.extend = document.extend = function(properties){
	for (var property in properties) this[property] = properties[property];
};

window[Browser.Engine.name] = window[Browser.Engine.name + Browser.Engine.version] = true;

window.ie = window.trident;
window.ie6 = window.trident4;
window.ie7 = window.trident5;

Class.empty = $empty;

//legacy .extend support

Class.prototype.extend = function(properties){
	properties.Extends = this;
	return new Class(properties);
};

Array.implement({

	copy: function(start, length){
		return $A(this, start, length);
	}

});

Array.alias({erase: 'remove', combine: 'merge'});

Function.extend({

	bindAsEventListener: function(bind, args){
		return this.create({'bind': bind, 'event': true, 'arguments': args});
	}

});

Function.empty = $empty;

Hash.alias({getKeys: 'keys', getValues: 'values', has: 'hasKey', combine: 'merge'});
var Abstract = Hash;

Element.extend = Element.implement;

Elements.extend = Elements.implement;

Element.implement({

	getFormElements: function(){
		return this.getElements('input, textarea, select');
	},

	replaceWith: function(el){
		el = $(el);
		this.parentNode.replaceChild(el, this);
		return el;
	},

	removeElements: function(){
		return this.dispose();
	}

});

Element.alias({'dispose': 'remove', 'getLast': 'getLastChild'});

Element.implement({

	getText: function(){
		return this.get('text');
	},

	setText: function(text){
		return this.set('text', text);
	},

	setHTML: function(){
		return this.set('html', arguments);
	},

	getHTML: function(){
		return this.get('html');
	},

	getTag: function(){
		return this.get('tag');
	}
});

Element.implement({
	getSize: function() {
		return {size: {x: this.offsetWidth, y: this.offsetHeight}, x: this.offsetWidth, y: this.offsetHeight};
	}

});

Event.keys = Event.Keys;

Element.implement({

	setOpacity: function(op){
		return this.set('opacity', op);
	}

});

Object.toQueryString = Hash.toQueryString;

var XHR = new Class({

	Extends: Request,

	options: {
		update: false
	},

	initialize: function(url, options){
		this.parent(options);
		this.url = url;
	},

	request: function(data){
		return this.send(this.url, data || this.options.data);
	},

	send: function(url, data){
		if (!this.check(arguments.callee, url, data)) return this;
		return this.parent({url: url, data: data});
	},

	success: function(text, xml){
		text = this.processScripts(text);
		if (this.options.update) $(this.options.update).empty().set('html', text);
		this.onSuccess(text, xml);
	},

	failure: function(){
		this.fireEvent('failure', this.xhr);
	}

});

var Ajax = XHR;

JSON.Remote = new Class({

	options: {
		key: 'json'
	},

	Extends: Request.JSON,

	initialize: function(url, options){
		this.parent(options);
		this.onComplete = $empty;
		this.url = url;
	},

	send: function(data){
		if (!this.check(arguments.callee, data)) return this;
		return this.parent({url: this.url, data: {json: Json.encode(data)}});
	},

	failure: function(){
		this.fireEvent('failure', this.xhr);
	}

});

Fx.implement({

	custom: function(from, to){
		return this.start(from, to);
	},

	clearTimer: function(){
		return this.cancel();
	},

	stop: function(){
		return this.cancel();
	}

});

Fx.Base = Fx;

Fx.Style = function(element, property, options){
	return new Fx.Tween(element, $extend({property: property}, options));
};

Element.implement({

	effect: function(property, options){
		return new Fx.Tween(this, $extend({property: property}, options));
	}

});

Fx.Styles = Fx.Morph;

Element.implement({

	effects: function(options){
		return new Fx.Morph(this, options);
	}

});

Native.implement([Element, Document], {

	getElementsByClassName: function(className){
		return this.getElements('.' + className);
	},

	getElementsBySelector: function(selector){
		return this.getElements(selector);
	}

});

Elements.implement({

	filterByTag: function(tag){
		return this.filter(tag);
	},

	filterByClass: function(className){
		return this.filter('.' + className);
	},

	filterById: function(id){
		return this.filter('#' + id);
	},

	filterByAttribute: function(name, operator, value){
		return this.filter('[' + name + (operator || '') + (value || '') + ']');
	}

});

var $E = function(selector, filter){
	return ($(filter) || document).getElement(selector);
};

var $ES = function(selector, filter){
	return ($(filter) || document).getElements(selector);
};

var Json = JSON;

JSON.toString = JSON.encode;
JSON.evaluate = JSON.decode;

Cookie.set = function(key, value, options){
	return new Cookie(key, options).write(value);
};

Cookie.get = function(key){
	return new Cookie(key).read();
};

Cookie.remove = function(key, options){
	return new Cookie(key, options).dispose();
};

if (Fx && Fx.Scroll) {
    Fx.Scroll.implement({

            scrollTo: function(y, x){
                    return this.start(y, x);
            }

    });
}


var MooRevolver = new Class({
	initialize: function(element, options){
		this.setOptions({
			"pad":80,
			"yRadius":-80,
			"centerY":100,
			"border":0,
			"arrowLeft":null,
			"arrowRight":null,
			"fxDuration": 500,
			"fxTransition": Fx.Transitions.Sine.easeInOut,
			"fade":false,
			"minScale":0.5
		}, options);
				
		if($(element)){
			if($(this.options.arrowLeft)) {
				$(this.options.arrowLeft).addEvent("click", (function(e){
					new Event(e).stop();
					this.getPrevious();
				}).bind(this));
			}
				
			if($(this.options.arrowRight)) {
				$(this.options.arrowRight).addEvent("click", (function(e){
					new Event(e).stop();
					this.getNext();
				}).bind(this));
			}
			
			this.processing = false;
			this.containerSize = $(element).getSize();
			this.xRadius = (this.containerSize.x / 2) - this.options.pad;
			this.yRadius = this.options.yRadius;
			this.centerX = (this.containerSize.x / 2);
			this.centerY = this.options.centerY;
			this.minScale = this.options.minScale;
			
			this.items = $(element).getChildren();			
			this.totalItems = this.items.length;
			
			if($(this.options.descriptions)) {
				this.descriptions = $(this.options.descriptions).getChildren();
				if(this.descriptions.length != this.totalItems) {
					alert('Descriptions should match Items!');
				}
			}
			
			this.points = [];
			this.positions = [];
			this.sizes = [];
			this.zIndexes = [];
			this.opacities = [];
						
			for(var i = 0; i < this.totalItems; i++){					
				this.points.push(i);
				var pt = this.getTriplePoint(this.points[i]);
				
				this.items[i].setStyles({
					"left": pt.x,
					"bottom": pt.y
				});
				
				this.processItem(i, this.points[i]);
				this.processDescription(i, this.points[i]);
			}
			
			this.reposition();
			
		} else {
			return;
		}
	},
	
	getNext: function(){
		if (!this.processing) {
			this.processing = true;
			this.rotate(true);
		}
	},
	
	getPrevious: function(){
		if (!this.processing) {
			this.processing = true;
			this.rotate(false);
		}
	},
	
	rotate: function(forward){
		if(!this.processing) return;

		if(forward){
			this.items.push(this.items.shift());
			if(this.descriptions) {
				this.descriptions.push(this.descriptions.shift());
			}
		} else {
			this.items.unshift(this.items.pop());
			if(this.descriptions) {
				this.descriptions.unshift(this.descriptions.pop());
			}
		}
		
		var fxArray = [];
		
		for(var i = 0; i < this.totalItems; i++){
			var myEffects = this.items[i].effects({"duration": this.options.fxDuration, "transition": this.options.fxTransition});
			fxArray.push(myEffects);
			if(this.options.fade) {
				myEffects.start({"opacity": this.opacities[i], "bottom": this.positions[i].y, "left": this.positions[i].x, "width": this.sizes[i].x, "height": this.sizes[i].y});
			} else {
				myEffects.start({"bottom": this.positions[i].y, "left": this.positions[i].x, "width": this.sizes[i].x, "height": this.sizes[i].y});
			}
			this.items[i].setStyle("z-index", this.zIndexes[i]);

			if(this.descriptions) {				
				var descriptionFx = this.descriptions[i].effects({"duration": this.options.fxDuration, "transition": this.options.fxTransition});
				fxArray.push(descriptionFx);
				descriptionFx.start({"opacity": i == 0 ? 1 : 0});
			}
		}
		
		this.processing = false;
		/*
		var g = new Group(null);
		g.initialize.apply(g, fxArray);
		g.addEvent("onComplete", (function(){ this.processing = false; }).bind(this));
		*/
	},
	
	reposition: function() {
		for (var _l = 0; _l < this.totalItems; _l++) {		
			var pt = this.getTriplePoint(this.points[_l]);
			this.positions.push({x: pt.x - ((this.items[_l].getSize().x + this.options.border) / 2), y: pt.y});
			
			this.items[_l].setStyles({
				"left": this.positions[_l].x,
				"bottom": this.positions[_l].y
			});
		}
	},
	
	getTriplePoint: function(_d) {
		var _x = this.centerX;
		/*
		if(_d > 0 && _d < this.totalItems / 2) {
			_x += this.xRadius * Math.min(2, _d);
		} else if(_d > 0 && _d >= this.totalItems / 2) {
			_x -= this.xRadius * Math.min(2, this.totalItems - _d);
		}
		*/
		if(_d == 1) {
			_x += this.xRadius;
		} else if (_d != 0 && _d == this.totalItems - 1) {
			_x -= this.xRadius;
		}
		var _y = this.centerY + this.yRadius;
		if(_d > 1 && _d < this.totalItems - 1) {
			_y += 40;
		}
		return {x : _x, y : _y};
	},
	
	processItem: function(_i, deg) {
		var size = 0;      
		var visible = true;
		
		if (deg == 0) {
			size = 1;
		} else if (deg == 1 || deg == this.totalItems - 1) {
			size = this.minScale;
		}
		
		if(visible) {
			this.scaleItem(_i, size);
			this.items[_i].setStyle("z-index", (size * 100).round());
			this.zIndexes.push((size * 100).round());
		}
	},
	
	processDescription: function(_i, deg) {
		var visible = false;
		if (deg == 0) {
			visible = true;
		}
		
		this.descriptions[_i].setStyle("opacity", visible ? 100 : 0);
	},
	
	scaleItem: function(_i, percentage) {
		var _x = ((this.items[_i].getSize().x + this.options.border) * percentage);
		var _y = ((this.items[_i].getSize().y + this.options.border) * percentage);
		
		this.sizes.push({x: _x, y: _y});
		
		percentage = percentage >= this.minScale ? 1.0 : 1;
		
		this.opacities.push(percentage);
	
		this.items[_i].setStyles({
			"width": _x,
			"height": _y,
			"opacity": this.options.fade ? percentage : 1
		});
	}
});

MooRevolver.implement(new Options);


