/*
Author:
	Gilles Hooghe, <ghooghe [at] gmail.com>
Class
	Boing
Options:
	wrapperSelector: wrapper element containing images to play with
*/ 
var Boing = new Class({
	
	options: {
		duration: 3000,
		wrapperSelector: '#boing div'
	},

	initialize: function(options) {
		this.setOptions(options);

		this.buildLibrary();
		this.setupImages();
	},

	/* Parse the images contained inside the wrapperSelector element */
	buildLibrary: function() {
		this.library = {};
		this.library.images = $$(this.options.wrapperSelector + ' img');
		this.library.imagesPositions = $A();
		this.library.imageEffects = $A();
	},
	
	/* Prepare and position images */
	setupImages: function() {
		// Setup wrapper
		var wrapper = $E(this.options.wrapperSelector);
		wrapper.setStyle('position', 'relative');
		
		this.wrapperCoord = wrapper.getCoordinates();

		this.library.images.each(function(image, idx) {
			image.setStyle('position', 'absolute');
			image.setStyle('opacity', 0);
				
			// Position image
			this.positionImage(idx);
		}, this);
		
		// Start periodical fx
		this.periodicalEffect.periodical((this.options.duration * 2) / this.library.images.length, this);
	},
	
	positionImage: function(index) {
		var image = this.library.images[index];
		var imageCoord = $pick(this.library.imagesPositions[index], this.getCoordinates(image));
		
		var running = true;
		var increm = 0;
		while (increm < 10 && running) {
			var randomCoord = this.getRandomCoord(image);	
			if (! this.overlap(randomCoord.left, randomCoord.top, imageCoord.width, imageCoord.height)) {
				// Set image position
				image.setStyle('left', randomCoord.left + 'px');
				image.setStyle('top', randomCoord.top + 'px');
				
				// Refresh stored coordinates
				this.library.imagesPositions[index] = this.getCoordinates(image);
				
				running = false;
			}
			increm++; // Avoid infinite cycle
		}
	},
	
	/* Will an image positionned with these coordinates overlap another one? */
	overlap: function(left, top, width, height) {
		var overlap = false;
		
		this.library.imagesPositions.each(function(existingImageCoord, idx) {
			if (! overlap && ((left <= existingImageCoord.right && (left + width) >= existingImageCoord.left) && 
				top <= existingImageCoord.bottom && (top + height) >= existingImageCoord.top)) {
				overlap = true;
				return overlap;
			}
		}, this);
		
		return overlap;
	},
	
	getRandomCoord: function(image) {
		var coordinates = {};
		
		var imageCoord = this.getCoordinates(image);
		coordinates.left = $random(0, this.wrapperCoord.width - imageCoord.width);
		coordinates.top = $random(0, this.wrapperCoord.height - imageCoord.height);
		
		return coordinates;
	},
	
	/* Return coordinates relative to parent */
	getCoordinates: function(element) {
		var el = $(element);
		var absCoords = el.getCoordinates();
		var parent = el.getParent();
		var parCoords = parent.getCoordinates();
		
		var coords = {};
		coords.width = absCoords.width;
		coords.height = absCoords.height;
		coords.left = absCoords.left - parCoords.left;
		coords.right = absCoords.right - parCoords.left;
		coords.top = absCoords.top - parCoords.top;
		coords.bottom = absCoords.bottom - parCoords.top;
		
		return coords;
	},
	
	periodicalEffect: function() {
		if ($defined(this.library.currentEffectIndex) && this.library.currentEffectIndex < this.library.images.length - 1) {
			this.library.currentEffectIndex++;
			this.library.showHide = this.library.showHide == 1 ? 0 : 1;
		} else {
			this.library.currentEffectIndex = 0;
			this.library.showHide = this.library.images[this.library.currentEffectIndex].getStyle('opacity') == 1 ? 0 : 1;
		}
	
		// Reshuffle image position while hidden
		if (this.library.showHide == 1) {
			this.positionImage(this.library.currentEffectIndex);
		}
		
		// Launch effect
		var el = this.library.images[this.library.currentEffectIndex];

			this.library.imageEffects[this.library.currentEffectIndex] = $pick(this.library.imageEffects[this.library.currentEffectIndex], new Fx.Style(el, 'opacity', { duration: this.options.duration } ));
			this.library.imageEffects[this.library.currentEffectIndex].start(this.library.showHide);
		
	}

});

Boing.implement(new Chain, new Options, new Events);


