// 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 = 2;
		this.options = {
			frequency:         10,
			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];		// Need to initialize this.current for proper operation of SEQUENCE mode.
	},
	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 its 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);

