// Element.Rotate - Will rotate content for you
// Written By: Eric Anderson <eric@afaik.us>
// License: Public Domain, do what you want

Element.Rotate = Class.create();
Object.extend(Element.Rotate, {
	RANDOM:   '_random',
	SEQUENCE: '_sequence'
});
Object.extend(Element.Rotate.prototype, {
	initialize: function(targets, elements, links, options) {
	  this.targets = targets;
		this.links = links;
		this._initElements(targets);	
		default_duration = 2;
		this.options = {
			frequency:         5,
			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);
	},
	stop: function() {
		if( this.timer )
			clearInterval(this.timer);
		this.timer = null;
	},
	transition: function() {
		// Cover work area with clone
		this.target = this._sequenceNextTarget();
		clone = this.target.firstChild.cloneNode(true);
		this.target.appendChild(clone);
		Position.absolutize(clone);
		Position.clone(this.target.firstChild, clone);

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

		// Init effects to transition one to the other
		this.options.showEffect(this.target.firstChild, this.options.showEffectOptions);
		this.options.hideEffect(clone, this.options.hideEffectOptions);
	},
	
	_initElements: function(targets) {
		for(var i=0;i<targets.length;i++){
			this.targets[i] = $(targets[i]);
		  e = this.targets[i];
			this.targets[i] = document.createElement('div');
			e.parentNode.insertBefore(this.targets[i], e);
			this.targets[i].appendChild(e);
		}
	},
	_each: function(iterator) {
		this.elements._each(iterator);
	},
	_randomNextElement: function(current) {
		while((next = this.elements.random()) == current) {}
		return next;
	},
	_sequenceNextElement: function(current) {
		current = this.elements.indexOf(current);
		if (current == -1)
			return this.elements[0];
		return current == (this.elements.length-1) ? this.elements[0] : this.elements[current+1];
	},
	
	_sequenceNextTarget: function() {
		current = this.targets.indexOf(this.target);
		if (current == -1)
			return this.targets[0];
		return current == (this.targets.length-1) ? this.targets[0] : this.targets[current+1];
	},
	
	_imageize: function(content) {
	  url = this.links[this.elements.indexOf(content)];
		// UPDATED: assume images, or update the matcher for rails assets
		//if( content.match(/\.(?:jpg|png|gif)$/) ) {
			return '<a href="'+url+'"><img src="'+content+'" border="0" /></a>';
		//}
		//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);
