
var Jp_Showcase = new Class({
	Implements: [Options, Events],
	cases: [],
	link: null,
	current: 0,
	fadeInFx: null,
	fadeOutFx: null,
	timeoutId: null,
	options: {
		delay: 6000, //time the case will be shown
		duration: 500,
		property: 'opacity',
		activeClass: 'on',
		stopOnMouseOver: true,
		fadeImageOnly: true, //whether to fade the whole li, or just the image
		loop: true,
		linkToUpdate: null,
		classToHide: null,
		startFadingSimultaneously: true, //should fading in and fading out be simultaneous?
		randomize: false
	},
	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) return;
		this.options.linkToUpdate = $(this.options.linkToUpdate);
		
		this.prepare();
		if (this.options.loop) {
			this.start();
		}
	},
	prepare: function() {
		if (this.options.randomize) {
			this.cases.shuffle();
		}
		for (var i = 0; i < this.cases.length; i++) {
			if (i > 0) {
				var target = this.options.fadeImageOnly ? this.cases[i].getElement('img') : this.cases[i];
				new Fx.Tween(target, this.options).set(0);
			}
			if (this.options.stopOnMouseOver) {
				this.cases[i].addEvent('mouseenter', function(evt, index) {
					this.pause();
					this.goTo(index);
				}.bindWithEvent(this, [i]));
				this.cases[i].addEvent('mouseleave', function(evt) {
					this.resume();
				}.bindWithEvent(this));
			}
			if (this.options.classToHide) {
				this.cases[i].removeClass(this.options.classToHide);
			}
		}
		
		this.cases[this.current].addClass(this.options.activeClass);
		
		this.addEvent('next', this.onNext.bindWithEvent(this));
		this.addEvent('fadedOut', this.onFadedOut.bindWithEvent(this));
		this.addEvent('fadedIn', this.onFadedIn.bindWithEvent(this));
		if (!this.options.startFadingSimultaneously) {
			this.addEvent('fadedOut', this.fadeIn.bindWithEvent(this));
		}
	},
	start: function() {
		this.options.loop = true;
		this.current = 0;
		this.resume();
	},
	resume: function() {
		if (this.options.loop) {
			this.timeoutId = (function() {
				this.fireEvent('next');
			}.bind(this)).delay(this.options.delay, this);
		}
	},
	pause: function() {
		if (this.timeoutId) {
			$clear(this.timeoutId);
		}
		if (this.fadeInFx) {
			this.fadeInFx.cancel();
			this.fadeInFx.set(this.fadeOutFx ? 0 : 1);
			this.fadeInFx = null;
		}
		if (this.fadeOutFx) {
			this.fadeOutFx.cancel();
			this.fadeOutFx.set(1);
			this.fadeOutFx = null;
		}
	},
	goTo: function(index) {
		var target = this.options.fadeImageOnly ? this.cases[this.current].getElement('img') : this.cases[this.current];
		new Fx.Tween(target, this.options).set(0);
		this.update(index);
		var target = this.options.fadeImageOnly ? this.cases[this.current].getElement('img') : this.cases[this.current];
		new Fx.Tween(target, this.options).set(1);
	},
	onNext: function() {
		if (this.cases.length <= 1) return;
		//fade out
		var target = this.options.fadeImageOnly ? this.cases[this.current].getElement('img') : this.cases[this.current];
		target.setStyle('z-index', 2);
		var options = {};
		$extend(options, this.options);
		options.onComplete = function() {
			this.fireEvent('fadedOut');
		}.bindWithEvent(this);
		var currentOpacity = target.getStyle('opacity');
		this.fadeOutFx = new Fx.Tween(target, options).start(currentOpacity, 0);
		
		if (this.options.startFadingSimultaneously) {
			this.fadeIn();
		}
	},
	onFadedOut: function() {
		this.update();
		this.fadeOutFx = null;
	},
	onFadedIn: function() {
		this.fadeInFx = null;
		this.resume();
	},
	fadeIn: function() {
		//fade in the next image
		var next = this.options.startFadingSimultaneously ? this.current + 1 : this.current;
		next = next >= this.cases.length ? 0 : next;
		var target = this.options.fadeImageOnly ? this.cases[next].getElement('img') : this.cases[next];
		target.setStyle('z-index', 1);
		var options = {};
		$extend(options, this.options);
		options.onComplete = function() {
			this.fireEvent('fadedIn');
		}.bindWithEvent(this);
		var currentOpacity = target.getStyle('opacity');
		this.fadeInFx = new Fx.Tween(target, options).start(currentOpacity, 1);
	},
	update: function(current) {
		this.cases[this.current].removeClass(this.options.activeClass);
		this.current = this.current + 1 >= this.cases.length ? 0 : this.current + 1;
		if (current != null) {
			this.current = current;
		}
		this.cases[this.current].addClass(this.options.activeClass);
		this.updateLink();
	},
	updateLink: function() {
		if (!this.options.linkToUpdate) return;
		
		var as = this.cases[this.current].getElements('a');
		if (as.length) {
			this.options.linkToUpdate.set('href', as.get('href'));
		}
	}
});

