
var Jp_Showcase = new Class({
	Implements: [Options, Events],
	cases: [],
	link: null,
	current: null,
	fadeInFx: null,
	fadeOutFx: null,
	timeoutId: null,
	skipFirstLoop: false,
	options: {
		delay: 6000, //time the case will be shown
		duration: 1500, //cruise speed
		fastDuration: 250, //duration upon user action
		activeClass: 'on',
		stopOnMouseOver: true,
		fadeImageOnly: true, //whether to fade the whole li, or just the image
		loop: true,
		classToHide: null,
		startFadingSimultaneously: true, //should fading in and fading out be simultaneous?
		randomize: false,
		fadeOnStart: false
		/*
		onFadedOut: $empty
		onFadedIn: $empty
		onUpdate: $empty
		*/
	},
	initialize: function(cases, options) {
		this.setOptions(options);
		if (typeof cases == 'string') {
			var ul = $(cases);
			if (!ul) return;
			this.cases = ul.getElements('li');
		}
		else {
			this.cases = cases;
		}
		if (!this.cases || !this.cases.length) return;
		
		this.prepare();
		if (this.options.loop) {
			this.start();
		}
	},
	prepare: function() {
		this.cases[0].getParent().addClass('jp-showcase');
		
		if (this.options.randomize) {
			this.cases.shuffle();
		}
		
		this.current = this.cases[0];
		
		for (var i = 0; i < this.cases.length; i++) {
			if (i > 0 || this.options.fadeOnStart) {
				var target = this.options.fadeImageOnly ? this.cases[i].getElement('img') : this.cases[i];
				var options = {
						duration: 0,
						property: 'opacity'
				};
				new Fx.Tween(target, options).set(0);
			}
			if (this.options.stopOnMouseOver) {
				this.cases[i].addEvent('mouseenter', function(evt, element) {
					this.pause();
				}.bindWithEvent(this, this.cases[i]));
				this.cases[i].addEvent('mouseleave', function(evt) {
					this.resume();
				}.bindWithEvent(this));
			}
			if (this.options.classToHide) {
				this.cases[i].removeClass(this.options.classToHide);
			}
		}
		
		this.current.addClass(this.options.activeClass);
		
		if (this.options.fadeOnStart) {
			this.fadeIn(this.current);
			this.skipFirstLoop = true;
		}
	},
	start: function() {
		this.options.loop = true;
		this.current = this.cases[0];
		this.resume();
	},
	resume: function() {
		if (this.skipFirstLoop) {
			this.skipFirstLoop = false;
			return;
		}
		if (this.options.loop) {
			this.timeoutId = (function() {
//				this.fireEvent('next');
				this.next('cruise');
			}.bind(this)).delay(this.options.delay, this);
		}
	},
	/**
	 * animate is cruise|fast|false and relates to the duration of
	 * the animation (duration, fastDuration, and none). Default to fast.
	 */
	goTo: function(element, animate) {
		if (element && element != this.current) {
			//swap images
			this.pause();
			this._fadeOut(animate);
			this.current = element;
			this.fireEvent('update');
			if (this.options.startFadingSimultaneously) {
				this._fadeIn(animate);
			}
		}
	},
	next: function(animate) {
		var target = this.cases[0];
		for (var i = 0; i <= this.cases.length; i++) {
			if (this.cases[i] == this.current) {
				if (i + 1 < this.cases.length) {
					target = this.cases[i + 1];
				}
				break;
			}
		}
		this.goTo(target, animate);
	},
	previous: function(animate) {
		var target = this.cases[this.cases.length - 1];
		for (var i = 0; i <= this.cases.length; i++) {
			if (this.cases[i] == this.current) {
				if (i > 0) {
					target = this.cases[i - 1];
				}
				break;
			}
		}
		this.goTo(target, animate);
	},
	_getDuration: function(key) {
		switch (key) {
			case false:
			case 0:
				return 0;
			case 'cruise':
				return this.options.duration;
			case 'fast':
			default:
				return this.options.fastDuration;
		}
	},
	_fadeOut: function(animate) {
		var duration = this._getDuration(animate);
		var target = this.options.fadeImageOnly ? this.current.getElement('img') : this.current;
		var options = {
			duration: duration,
			property: 'opacity',
			onComplete: function(animate) {
				this.fadeOutFx = null;
				this.fireEvent('fadedOut');
				if (!this.options.startFadingSimultaneously) {
					this._fadeIn(animate);
				}
			}.bindWithEvent(this, [animate])
		};
		this.fadeOutFx = new Fx.Tween(target, options).start(0);
	},
	_fadeIn: function(animate) {
		var duration = this._getDuration(animate);
		var target = this.options.fadeImageOnly ? this.current.getElement('img') : this.current;
		var options = {
			duration: duration,
			property: 'opacity',
			onComplete: function(animate) {
				this.fadeInFx = null;
				this.fireEvent('fadedIn');
				this.resume();
			}.bindWithEvent(this)
		};
		this.fadeInFx = new Fx.Tween(target, options).start(1);
	},
	pause: function() {
		if (this.timeoutId) {
			$clear(this.timeoutId);
		}
		this.setCurrentImage();
	},
	setCurrentImage: function() {
		if (this.fadeOutFx) {
			this.fadeOutFx.cancel();
			this.fadeOutFx.set(this.fadeInFx ? 0 : 1);
			this.fadeOutFx = null;
		}
		if (this.fadeInFx) {
			this.fadeInFx.cancel();
			this.fadeInFx.set(1);
			this.fadeInFx = null;
		}
	}
});

