/**
 * Mac OS X users will be familiar with the poof animation that occurs when
 * application icons are removed from the dock. The animation looks nice, is
 * unobtrusive, and provides a clear indication of the function being performed.
 *
 * Based off the jQuery Poof Effect by Kreg Wallace
 * http://www.kombine.net/news/jquery-poof-effect/
 *
 * @author Keith Baker <keithtbaker@gmail.com>
 * @copyright Copyright (C) 2008, Keith Baker
 * @license MIT
 *
*/

var Poof = new Class({
	Implements: [Options, Events, Chain],

	/**
	 * defaultOptions
	 * Options used in typical implementations
	 *
	 * imagePoof:			the path to the image (relative to the page it will be on)
	 * elAnimation:		the element containing the top-down vertical reel animation
	 * elRemove:			the elements to be removed on click
	 * frameCount: 		number of frames in the sprite animation
	 * frameHeight:		height of poof frames in pixels
	 * frameWidth:		width of poof frames in pixels
	 * frameDuration:	set duration of each frame (in milliseconds)
	 */
	defaultOptions: {
		'imagePoof'			: 'images/poof.png',
		'elAnimation'		: 'poofAnimation',
		'elRemove'			: '.deleteme',
		'frameCount'		: 5,
		'frameHeight'		: 32,
		'frameWidth'		: 32,
		'frameDuration'	: 100
	},

	/**
	 * initialize
	 * Initialize an instance of the Poof class
	 */
	initialize: function(options){
		// Set runtime options
		this.setOptions($merge(this.defaultOptions, options));

		// Create Poof Div
		var poofDiv = new Element('div', {
				'id': this.options.elAnimation,
				'styles': {
					'background': 'transparent url(' + this.options.imagePoof + ') no-repeat 0 0',
					'cursor': 'pointer',
					'display': 'none',
					'height' : this.options.frameHeight,
					'position': 'absolute',
					'width' : this.options.frameWidth,
					'z-index':1000000
				}
		}).inject($(document.body));

		// Activate elements
		this.activate(this.options.elRemove);
	},

	/**
	 * activate
	 * Activate elements for removal
	 */
	activate: function(els){
		$$(els).each(function(el){
			el.addEvent('click', function(){
				this.poof(el);
			}.bind(this));
		}.bind(this));
	},

	/**
	 * absolutelyCenter
	 * Absolutely center one element over another element
	 */
	absolutelyCenter: function(bottom, top){
		var bottomCenterX = ((bottom.getSize().x.toInt() / 2) + bottom.getPosition().x).toInt();
		var bottomCenterY = ((bottom.getSize().y.toInt() / 2) + bottom.getPosition().y).toInt();
		var topX = bottomCenterX - (top.getSize().x.toInt() / 2).toInt();
		var topY = bottomCenterY - (top.getSize().y.toInt() / 2).toInt();
		top.setStyles({'top': topY, 'left': topX});
	},

	/**
	 * poof
	 * Make the element go *poof*
	 */
	poof: function(el){
		var target = (arguments.length > 1) ? arguments[1] : null;

		// make this element disappear
		el.morph({'duration': (this.options.frameDuration * this.options.frameCount) / 2}).set('styles', {'opacity': 0.1});

		// position the animation
		$(this.options.elAnimation).set('styles', {'display': 'block'});
		this.absolutelyCenter((target != null) ? target : el, $(this.options.elAnimation));

		// run the animation
		var fxChain = new Array();
		for(i = 0; i < this.options.frameCount; i++) {
			fxChain[i] = function(){
				$(this.options.elAnimation).set('styles', {'background-position': '0px ' + (0 - ((this.options.frameCount - this.$chain.length) * this.options.frameHeight)) + 'px'});
				new Fx.Morph($(this.options.elAnimation), {'duration': this.options.frameDuration, 'onComplete': function(){this.callChain()}.bind(this)}).start();
			}.bind(this);

			if (i == (this.options.frameCount - 1)){
				// kill this element
				fxChain[i+1] = function(){
					((target != null) ? target : el).destroy();
					$(this.options.elAnimation).set('styles', {'display': 'none', 'background-position': '0 0'});
					this.callChain();
				}.bind(this);
			}
		}
		this.chain.apply(this, fxChain);
		this.callChain();
	}
});


