// mooStack v0.1 by Martino di Filippo
//
// you're free to do whatever you want with this code
// but please in case you modify it, send me a copy at
// puntodifuga@gmail.com. Thanks, I hope this helps you!

Stack = new Class({

	Implements: [Events, Options],
	
	options: {
		scattering: 50,
		speed: 700,
		wrapperStyles: {},
		onChange: $empty
	},
	
	initialize: function(container, options) {
		this.container = $(container);
		this.setOptions(options);
		this.current = 0;
		this.currentOrder;
		this.reindexing = false;
		this.rightEdge = 0;
		this.stack = this.container.getChildren();
		
		this.container.setStyle('position', 'absolute');
		
		var wrapper = new Element('div', {
			'class': 'stackWrapper',
			'styles': {
				'position': 'absolute'
			}
		});
		wrapper.setStyles(this.options.wrapperStyles);

		var index = 0, z = this.stack.length * 2;

		this.stack.each((function(el){
			el.setStyle('z-index', z--);
			wrapper.clone()
				.setStyles({
					'height': el.getSize().y,
					'margin-top': $random(0, this.options.scattering),
					'margin-left': $random(0, this.options.scattering),
					'width': el.getSize().x,
					'z-index': z--
				})
				.store('stack:index', index++)
				.wraps(el);
			
			if(this.rightEdge < el.scrollWidth)
				this.rightEdge = el.scrollWidth;
		}).bind(this));

		wrapper.dispose();

		this.stack = this.container.getChildren();
		this.rightEdge += this.options.scattering;
		
		this.stack[0].addEvent('click', this.swap.bind(this));
		this.update();
	},
	
	goTo: function(index) {
		if($type(index) == 'element')
			index = $pick(index.retrieve('stack:index'), index.parent.retrieve('stack:index'));

		if($type(index) != 'number')
			return this;

		if(this.current == index)
			return this;
		
		var forward = this.current < index ? index - this.current : this.stack.length - this.current + index;
		var backward = this.current > index ? this.current - index : this.current + this.stack.length - index;
		return this.swapMany((Math.abs(forward) <= Math.abs(backward)) ? forward : -backward);
	},
	
	reindex: function() {
		var z = this.stack.length * 2;
		this.stack.each(function(wrapper){
			wrapper.getChildren()[0].setStyle('z-index', z--);
			wrapper.setStyle('z-index', z--);
		});

		return this;
	},
	
	swap: function(direction) {
		var current = this.stack[0];

		switch(direction) {
			case 'prev':
				var next = this.stack.getLast();
				this.stack.erase(next);
				this.stack = [next].extend(this.stack);
				break;
			case 'next':
			default:
				direction = 'next';
				var next = this.stack[1];
				this.stack.erase(current).push(current);
		}

		current.removeEvents('click');
		next.addEvent('click', this.swap.bind(this));

		if(this.reindexing)
			$clear(this.reindexing);

		this.reindexing = this.reindex.delay((this.options.speed / 2).toInt(), this);

		var out = [$random((-this.options.scattering * 2).toInt(), 0), $random(this.rightEdge, this.rightEdge + (this.options.scattering * 2))];
		var final = [$random(0, this.options.scattering), $random(0, this.options.scattering)]

		new Fx.Morph(direction == 'next' ? current : next, { duration: (this.options.speed / 2).toInt(), link: 'chain' }).start({
			'margin-top': out[0],
			'margin-left': out[1]
		}).start({
			'margin-top': final[0],
			'margin-left': final[1]
		});
		
		this.update();
		this.fireEvent('onChange', this.current);

		return this;
	},

	swapMany: function(many) {
		direction = many < 0 ? 'prev' : 'next';
		many = Math.abs(many);

		while(many--)
			this.swap(direction);

		return this;
	},
	
	toElement: function() {
		return this.container;
	},

	update: function() {
		this.currentOrder = this.stack.map(function(el){ return el.retrieve('stack:index'); });
		this.current = this.currentOrder[0];
	}
});
