// Element.Rotate - Will rotate content for you
// Originally written By: Eric Anderson <eric@afaik.us>
// Bug fixed in SEQUENCE by Ben J. Milander 
// 1/17/09

Element.Rotate = Class.create();
Object.extend(Element.Rotate, {
	RANDOM:   '_random',
	SEQUENCE: '_sequence'
});
Object.extend(Element.Rotate.prototype, {
	initialize: function(element, elements, options) {
		this.element = $(element);
		this._initElement();
		default_duration = 4;
		this.options = {
			frequency:         15,
			transitionType:    Element.Rotate.SEQUENCE,
			hideEffect:        Effect.Fade,
			hideEffectOptions: {duration: default_duration},
			showEffect:        Effect.Appear,
			showEffectOptions: {duration: default_duration}
		};
		Object.extend(this.options, options);
		userFinish = this.options.hideEffectOptions.afterFinish ||
			function(){};
		this.options.hideEffectOptions.afterFinish = function(effect) {
			userFinish();
			Element.remove(effect.element);
		};
		if( !elements ) {
			alert('No elements specified');
			return;
		} else {
			this.elements = elements;
		}
		this.elements = this.elements.collect(this._imageize.bind(this));
		this.elements.each(function(e) {e.preloadImgs()});
		this.start();
	},
	start: function() {
		this.timer = setInterval(this.transition.bind(this),
			this.options.frequency * 1000);
			this.current = this.elements[0];
	},
	stop: function() {
		if( this.timer )
			clearInterval(this.timer);
		this.timer = null;
	},
	transition: function() {
		// Cover work area with clone
		clone = this.element.firstChild.cloneNode(true);
		this.element.appendChild(clone);
		Position.absolutize(clone);
		Position.clone(this.element.firstChild, clone);
		//		this.current = clone;

		// Put next element in DOM tree
		nextElementMethod = this.options.transitionType+'NextElement';
		this.current = this[nextElementMethod](this.current);
		Element.remove(this.element.firstChild);
		new Insertion.Top(this.element, this.current);

		// Init effects to transition one to the other
		this.options.showEffect(this.element.firstChild, this.options.showEffectOptions);
		this.options.hideEffect(clone, this.options.hideEffectOptions);
	},
	_initElement: function() {
		e = this.element;
		this.element = document.createElement('div');
		e.parentNode.insertBefore(this.element, e);
		this.element.appendChild(e);
	},
	_each: function(iterator) {
		this.elements._each(iterator);
	},
	_randomNextElement: function(current) {
		while((next = this.elements.random()) == current) {}
		return next;
	},
	
/*	This function takes current image as argument, locates ints index and increments to the next image and returns it.
	If it is the last one, it returns the first
	Ben J. Milander 1/17/09
*/	_sequenceNextElement: function(current) {
		currentIndex = this.elements.indexOf(current);
		if( currentIndex == -1 )
			return this.elements[0];
		if(currentIndex == this.elements.length-1) {
			return this.elements[0];
		} else {
			return this.elements[currentIndex+1];
			}
	},
	_imageize: function(content) {
		if( content.match(/\.(?:jpg|png|gif)$/) ) {
			return '<img src="'+content+'" />';
		}
		return content;
	}
});
Object.extend(Element.Rotate.prototype, Enumerable);

Array.prototype.random = function() {
	return this[Math.ceil(Math.random()*this.length)-1];
}

Prototype.ImageTag = '<img.*?src\=\"([^\"]+)\"[^\>]*\>';
Object.extend(String, {
	_imgCache: [],
	unloadImgCache: function() {
		String._imgCache.clear();
	}
});
Object.extend(String.prototype, {
	// Mostely borrowed from Prototype.js String.prototype.extractScripts
	extractImgs: function() {
		var matchAll = new RegExp(Prototype.ImageTag, 'img');
		var matchOne = new RegExp(Prototype.ImageTag, 'im');
		return (this.match(matchAll) || []).map(function(imageTag) {
			return (imageTag.match(matchOne) || ['', ''])[1];
		});
	},
	preloadImgs: function() {
		this.extractImgs().each(function(src) {
			img = new Image();
			img.src = src;
			String._imgCache.push(img);
		});
	}
});

Event.observe(window, 'unload', String.unloadImgCache, false);
