
var Jp_Slider = new Class({
	Implements: [Options, Events],
	container: null,
	innerContainer: null,
	triggers: [],
	targets: [],
	slideFx: null,
	currentTarget: null,
	initialState: true, //set to true until the state (the target) changes (any call to goTo())
	timerId: null,
	options: {
		duration: 1500,
		fastDuration: 250, //duration upon user action
		property: 'top',
		link: 'cancel',
		transition: Fx.Transitions.Expo.easeOut,
		updateUrl: true,
		goToFirstOnEmpty: true, //If there's no hash in the url, or if the target is empty, go to the first target
		period: 0, //go to next every x ms. 0 to disable
		infinite: false //targets will be duplicate so that elements are pushed to the end when scrolling from the last element to the first one
		/*
		onTargetChange: $empty
		onTargetUpdated: $empty
		onEmptyTarget: $empty
		*/
	},
	/**
	 * if trigger is left empty, targets will be the container children
	 */
	initialize: function(triggers, container, options) {
		this.setOptions(options);
		this.triggers = triggers || [];
		this.container = $(container);
		
		if (!this.container) return;
		
		this.prepare();
	},
	prepare: function() {
		this.container.addClass('jp-slider');
		
		var containerChildren = this.container.getChildren();
		if (!this.innerContainer) {
			this.innerContainer = new Element('div', {'class': 'jp-slider-inner-container'});
			containerChildren.each(function(e) {
				e.injectInside(this.innerContainer);
			}, this);
			this.innerContainer.injectInside(this.container);
			
			this.slideFx = new Fx.Tween(this.innerContainer, {
				duration: this.options.duration,
				property: this.options.property,
				link: this.options.link,
				transition: this.options.transition,
				onComplete: function() {
					this.fireEvent('targetUpdated');
				}.bind(this)
			});
		}
		
		if (this.triggers.length == 0) {
			containerChildren.each(function(target) {
				this.addTarget(target);
			}, this);
		}
		else {
			this.triggers.each(function(e) {
				var href = e.get('href');
				if (href.indexOf('#') == 0 && href.length > 1) {
					var targetId = href.replace(/^#/, '');
					var target = $(targetId);

					e.addEvent('click', function(evt, targetId) {
						if (!this.options.updateUrl) {
							evt.stop();
						}
						this.pause();
						this.goTo(targetId, 'fast');
					}.bindWithEvent(this, [targetId]));
					
					this.addTarget(target);
				}
			}, this);
		}
		
		if (this.options.updateUrl) {
			this.checkLocation(true);
			this.checkLocation.periodical(250, this);
		}
		else if (this.options.goToFirstOnEmpty) {
			this.goTo(this.targets[0], false);
		}
		
		if (this.options.period > 0) {
			this.start();
			
			this.container.addEvent('mouseenter', function() {
				this.pause();
			}.bindWithEvent(this));
			this.container.addEvent('mouseleave', function() {
				this.start();
			}.bindWithEvent(this));
		}
	},
	addTarget: function(target) {
		if (target) {
			var targetId = target.get('id');
			if (this.options.updateUrl && targetId) {
				target.set('id', 'jp-slider-' + target.get('id'));
			}
			this.targets.push(target);
		}
	},
	goTo: function(target, animate) {
		if (typeof target == 'string' && target.indexOf('jp-slider-') != 0 && this.options.updateUrl) {
			target = 'jp-slider-' + target;
		}
		target = $(target);
		if (target) {
			this.fireEvent('targetChange', this);
			this.currentTarget = target;
			if (this.triggers) {
				this.triggers.each(function(e) {
					var targetId = e.get('href').replace(/^#/, '');
					if (targetId == this.currentTarget.get('id')) {
						e.addClass('on');
					}
					else {
						e.removeClass('on');
					}
				}, this);
			}
			var top = 0;
			var containerChildren = this.innerContainer.getChildren();
			for (var targetIndex = 0; targetIndex < containerChildren.length; targetIndex++) {
				if (containerChildren[targetIndex] == target) {
					break;
				}
				top -= parseInt(containerChildren[targetIndex].getSize().y);
				top -= parseInt(containerChildren[targetIndex].getStyle('margin-bottom'));
			}
			var duration = this._getDuration(animate);
			if (duration > 0 && !this.initialState) {
				this.slideFx.setOptions({duration: duration});
				this.slideFx.start(top + 'px');
			}
			else {
				this.slideFx.set(top + 'px');
			}
			this.initialState = false;
		}
	},
	next: function(animate) {
		this.goTo(this.getNext(), animate);
	},
	previous: function(animate) {
		this.goTo(this.getPrevious(), animate);
	},
	getNext: function() {
		for (var i = 0; i < this.targets.length; i++) {
			if (this.targets[i] == this.currentTarget) {
				return i + 1 < this.targets.length ? this.targets[i + 1] : this.targets[0];
			}
		}
		return this.targets[0];
	},
	getPrevious: function() {
		for (var i = 0; i < this.targets.length; i++) {
			if (this.targets[i] == this.currentTarget) {
				return i - 1 >= 0 ? this.targets[i - 1] : this.targets[this.targets.length - 1];
			}
		}
		return this.targets[this.targets.length - 1];
	},
	checkLocation: function(animate) {
		var location = window.location.toString();
		if (location.indexOf('#') >= 0) {
			var target = location.replace(/[^#]+#/, '');
			if (target && 'jp-slider-' + target != this.currentTarget.get('id')) {
				this.goTo(target, animate);
			}
		}
		else {
			var gotTarget = false;
			if (this.currentTarget.get('id') && (this.currentTarget.get('id') != this.targets[0].get('id') || !this.options.goToFirstOnEmpty)) {
				this.fireEvent('emptyTarget', this);
				if (this.options.goToFirstOnEmpty) {
					this.goTo(this.targets[0], animate);
					gotTarget = true;
				}
			}
			if (!gotTarget) {
				this.currentTarget = null;
			}
		}
	},
	pause: function() {
		$clear(this.timerId);
		this.timerId = null;
	},
	start: function() {
		this.timerId = this.next.periodical(this.options.period, this, ['cruise']);
	},
	_getDuration: function(key) {
		switch (key) {
			case false:
			case 0:
				return 0;
			case 'cruise':
				return this.options.duration;
			case 'fast':
			default:
				return this.options.fastDuration;
		}
	}
});
