
if (Prototype.Browser.WebKit) {
	Prototype.Browser.WebKitVersion = parseFloat(navigator.userAgent.match(/AppleWebKit\/([\d\.\+]*)/)[1]);
	Prototype.Browser.Safari2 = (Prototype.Browser.WebKitVersion < 420)
}
if (Prototype.Browser.IE) {
	Prototype.Browser.IEVersion = parseFloat(navigator.appVersion.split(';')[1].strip().split(' ')[1]);
	Prototype.Browser.IE6 = Prototype.Browser.IEVersion == 6;
	Prototype.Browser.IE7 = Prototype.Browser.IEVersion == 7
}
Prototype.falseFunction = function () {
	return false
};
Prototype.trueFunction = function () {
	return true
};
var UI = {
	Abstract: {},
	Ajax: {}
};
Object.extend(Class.Methods, {
	extend: Object.extend.methodize(),
	addMethods: Class.Methods.addMethods.wrap(function (a, b) {
		if (!b) return this;
		if (!b.hasOwnProperty('methodsAdded')) return a(b);
		var c = b.methodsAdded;
		delete b.methodsAdded;
		a(b);
		c.call(b, this);
		b.methodsAdded = c;
		return this
	}),
	addMethod: function (a, b) {
		var c = {};
		c[a] = b;
		return this.addMethods(c)
	},
	method: function (a) {
		return this.prototype[a].valueOf()
	},
	classMethod: function () {
		$A(arguments).flatten().each(function (a) {
			this[a] = (function () {
				return this[a].apply(this, arguments)
			}).bind(this.prototype)
		},
		this);
		return this
	},
	undefMethod: function (a) {
		this.prototype[a] = undefined;
		return this
	},
	removeMethod: function (a) {
		delete this.prototype[a];
		return this
	},
	aliasMethod: function (a, b) {
		this.prototype[a] = this.prototype[b];
		return this
	},
	aliasMethodChain: function (a, b) {
		b = b.camelcase();
		this.aliasMethod(a + "Without" + b, a);
		this.aliasMethod(a, a + "With" + b);
		return this
	}
});
Object.extend(Number.prototype, {
	snap: function (a) {
		return parseInt(a == 1 ? this: (this / a).floor() * a)
	}
});
Object.extend(String.prototype, {
	camelcase: function () {
		var a = this.dasherize().camelize();
		return a.charAt(0).toUpperCase() + a.slice(1)
	},
	makeElement: function () {
		var a = new Element('div');
		a.innerHTML = this;
		return a.down()
	}
});
Object.extend(Array.prototype, {
	empty: function () {
		return ! this.length
	},
	extractOptions: function () {
		return this.last().constructor === Object ? this.pop() : {}
	},
	removeAt: function (a) {
		var b = this[a];
		this.splice(a, 1);
		return b
	},
	remove: function (a) {
		var b;
		while ((b = this.indexOf(a)) != -1) this.removeAt(b);
		return a
	},
	insert: function (a) {
		var b = $A(arguments);
		b.shift();
		this.splice.apply(this, [a, 0].concat(b));
		return this
	}
});
Element.addMethods({
	getScrollDimensions: function (a) {
		return {
			width: a.scrollWidth,
			height: a.scrollHeight
		}
	},
	getScrollOffset: function (a) {
		return Element._returnOffset(a.scrollLeft, a.scrollTop)
	},
	setScrollOffset: function (a, b) {
		a = $(a);
		if (arguments.length == 3) b = {
			left: b,
			top: arguments[2]
		};
		a.scrollLeft = b.left;
		a.scrollTop = b.top;
		return a
	},
	getNumStyle: function (a, b) {
		var c = parseFloat($(a).getStyle(b));
		return isNaN(c) ? null: c
	},
	appendText: function (a, b) {
		a = $(a);
		b = String.interpret(b);
		a.appendChild(document.createTextNode(b));
		return a
	}
});
document.whenReady = function (a) {
	if (document.loaded) a.call(document);
	else document.observe('dom:loaded', a)
};
Object.extend(document.viewport, {
	getScrollOffset: document.viewport.getScrollOffsets,
	setScrollOffset: function (a) {
		Element.setScrollOffset(Prototype.Browser.WebKit ? document.body: document.documentElement, a)
	},
	getScrollDimensions: function () {
		return Element.getScrollDimensions(Prototype.Browser.WebKit ? document.body: document.documentElement)
	}
});
(function () {
	UI.Options = {
		methodsAdded: function (a) {
			a.classMethod($w(' setOptions allOptions optionsGetter optionsSetter optionsAccessor '))
		},
		setOptions: function (a) {
			if (!this.hasOwnProperty('options')) this.options = this.allOptions();
			this.options = Object.extend(this.options, a || {})
		},
		allOptions: function () {
			var a = this.constructor.superclass,
			ancestor = a && a.prototype;
			return (ancestor && ancestor.allOptions) ? Object.extend(ancestor.allOptions(), this.options) : Object.clone(this.options)
		},
		optionsGetter: function () {
			addOptionsAccessors(this, arguments, false)
		},
		optionsSetter: function () {
			addOptionsAccessors(this, arguments, true)
		},
		optionsAccessor: function () {
			this.optionsGetter.apply(this, arguments);
			this.optionsSetter.apply(this, arguments)
		}
	};
	function addOptionsAccessors(d, e, f) {
		e = $A(e).flatten();
		if (e.empty()) e = Object.keys(d.allOptions());
		e.each(function (b) {
			var c = (f ? 'set': 'get') + b.camelcase();
			d[c] = d[c] || (f ?
			function (a) {
				return this.options[b] = a
			}: function () {
				return this.options[b]
			})
		})
	}
})();
UI.Carousel = Class.create(UI.Options, {
	options: {
		direction: "horizontal",
		previousButton: ".previous_button",
		nextButton: ".next_button",
		container: ".container",
		scrollInc: "auto",
		disabledButtonSuffix: '_disabled',
		overButtonSuffix: '_over'
	},
	initialize: function (c, d) {
		this.setOptions(d);
		this.element = $(c);
		this.id = this.element.id;
		this.container = this.element.down(this.options.container).firstDescendant();
		this.elements = this.container.childElements();
		this.previousButton = this.options.previousButton == false ? null: this.element.down(this.options.previousButton);
		this.nextButton = this.options.nextButton == false ? null: this.element.down(this.options.nextButton);
		this.posAttribute = (this.options.direction == "horizontal" ? "left": "top");
		this.dimAttribute = (this.options.direction == "horizontal" ? "width": "height");
		this.elementSize = this.computeElementSize();
		this.nbVisible = this.currentSize() / this.elementSize;
		var e = this.options.scrollInc;
		if (e == "auto") e = Math.floor(this.nbVisible);
		[this.previousButton, this.nextButton].each(function (a) {
			if (!a) return;
			var b = (a == this.nextButton ? "next_button": "previous_button") + this.options.overButtonSuffix;
			a.clickHandler = this.scroll.bind(this, (a == this.nextButton ? -1 : 1) * e * this.elementSize);
			a.observe("click", a.clickHandler).observe("mouseover", function () {
				a.addClassName(b)
			}.bind(this)).observe("mouseout", function () {
				a.removeClassName(b)
			}.bind(this))
		},
		this);
		this.updateButtons()
	},
	destroy: function ($super) { [this.previousButton, this.nextButton].each(function (a) {
			if (!a) return;
			a.stopObserving("click", a.clickHandler)
		},
		this);
		this.element.remove();
		this.fire('destroyed')
	},
	fire: function (a, b) {
		b = b || {};
		b.carousel = this;
		return this.element.fire('carousel:' + a, b)
	},
	observe: function (a, b) {
		this.element.observe('carousel:' + a, b.bind(this));
		return this
	},
	stopObserving: function (a, b) {
		this.element.stopObserving('carousel:' + a, b);
		return this
	},
	checkScroll: function (a, b) {
		if (a > 0) a = 0;
		else {
			var c = this.elements.last().positionedOffset()[this.posAttribute] + this.elementSize;
			var d = this.currentSize();
			if (a + c < d) a += d - (a + c);
			a = Math.min(a, 0)
		}
		if (b) this.container.style[this.posAttribute] = a + "px";
		return a
	},
	scroll: function (a) {
		if (this.animating) return this;
		var b = this.currentPosition() + a;
		b = this.checkScroll(b, false);
		a = b - this.currentPosition();
		if (a != 0) {
			this.animating = true;
			this.fire("scroll:started");
			var c = this;
			this.container.morph("opacity:0.5", {
				duration: 0.2,
				afterFinish: function () {
					c.container.morph(c.posAttribute + ": " + b + "px", {
						duration: 0.4,
						delay: 0.2,
						afterFinish: function () {
							c.container.morph("opacity:1", {
								duration: 0.2,
								afterFinish: function () {
									c.animating = false;
									c.updateButtons().fire("scroll:ended", {
										shift: a / c.currentSize()
									})
								}
							})
						}
					})
				}
			})
		}
		return this
	},
	scrollTo: function (a) {
		if (this.animating || a < 0 || a > this.elements.length || a == this.currentIndex() || isNaN(parseInt(a))) return this;
		return this.scroll((this.currentIndex() - a) * this.elementSize)
	},
	updateButtons: function () {
		this.updatePreviousButton();
		this.updateNextButton();
		return this
	},
	updatePreviousButton: function () {
		var a = this.currentPosition();
		var b = "previous_button" + this.options.disabledButtonSuffix;
		if (this.previousButton.hasClassName(b) && a != 0) {
			this.previousButton.removeClassName(b);
			this.fire('previousButton:enabled')
		}
		if (!this.previousButton.hasClassName(b) && a == 0) {
			this.previousButton.addClassName(b);
			this.fire('previousButton:disabled')
		}
	},
	updateNextButton: function () {
		var a = this.currentLastPosition();
		var b = this.currentSize();
		var c = "next_button" + this.options.disabledButtonSuffix;
		if (this.nextButton.hasClassName(c) && a != b) {
			this.nextButton.removeClassName(c);
			this.fire('nextButton:enabled')
		}
		if (!this.nextButton.hasClassName(c) && a == b) {
			this.nextButton.addClassName(c);
			this.fire('nextButton:disabled')
		}
	},
	computeElementSize: function () {
		return this.elements.first().getDimensions()[this.dimAttribute]
	},
	currentIndex: function () {
		return - this.currentPosition() / this.elementSize
	},
	currentLastPosition: function () {
		if (this.container.childElements().empty()) return 0;
		return this.currentPosition() + this.elements.last().positionedOffset()[this.posAttribute] + this.elementSize
	},
	currentPosition: function () {
		return this.container.getNumStyle(this.posAttribute)
	},
	currentSize: function () {
		return this.container.parentNode.getDimensions()[this.dimAttribute]
	},
	updateSize: function () {
		this.nbVisible = this.currentSize() / this.elementSize;
		var b = this.options.scrollInc;
		if (b == "auto") b = Math.floor(this.nbVisible);
		[this.previousButton, this.nextButton].each(function (a) {
			if (!a) return;
			a.stopObserving("click", a.clickHandler);
			a.clickHandler = this.scroll.bind(this, (a == this.nextButton ? -1 : 1) * b * this.elementSize);
			a.observe("click", a.clickHandler)
		},
		this);
		this.checkScroll(this.currentPosition(), true);
		this.updateButtons().fire('sizeUpdated');
		return this
	}
});
UI.Ajax.Carousel = Class.create(UI.Carousel, {
	options: {
		elementSize: -1,
		url: null
	},
	initialize: function ($super, d, e) {
		if (!e.url) throw ("url option is required for UI.Ajax.Carousel");
		if (!e.elementSize) throw ("elementSize option is required for UI.Ajax.Carousel");
		$super(d, e);
		this.endIndex = 0;
		this.hasMore = true;
		this.updateHandler = this.update.bind(this);
		this.updateAndScrollHandler = function (a, b, c) {
			this.update(b, c);
			this.scroll(a)
		}.bind(this);
		this.runRequest.bind(this).defer({
			parameters: {
				from: 0,
				to: Math.ceil(this.nbVisible) - 1
			},
			onSuccess: this.updateHandler
		})
	},
	runRequest: function (a) {
		this.requestRunning = true;
		new Ajax.Request(this.options.url, Object.extend({
			method: "GET"
		},
		a));
		this.fire("request:started");
		return this
	},
	scroll: function ($super, a) {
		if (this.animating || this.requestRunning) return this;
		var b = ( - a) / this.elementSize;
		if (this.hasMore && b > 0 && this.currentIndex() + this.nbVisible + b - 1 > this.endIndex) {
			var c = this.endIndex + 1;
			var d = Math.ceil(c + this.nbVisible - 1);
			this.runRequest({
				parameters: {
					from: c,
					to: d
				},
				onSuccess: this.updateAndScrollHandler.curry(a).bind(this)
			});
			return this
		} else $super(a)
	},
	update: function (a, b) {
		this.requestRunning = false;
		this.fire("request:ended");
		if (!b) b = a.responseJSON;
		this.hasMore = b.more;
		this.endIndex = Math.max(this.endIndex, b.to);
		this.elements = this.container.insert({
			bottom: b.html
		}).childElements();
		return this.updateButtons()
	},
	computeElementSize: function () {
		return this.options.elementSize
	},
	updateSize: function ($super) {
		var a = this.nbVisible;
		$super();
		if (Math.floor(this.nbVisible) - Math.floor(a) >= 1 && this.hasMore) {
			if (this.currentIndex() + Math.floor(this.nbVisible) >= this.endIndex) {
				var b = Math.floor(this.currentIndex() + Math.floor(this.nbVisible) - this.endIndex);
				this.runRequest({
					parameters: {
						from: this.endIndex + 1,
						to: this.endIndex + b
					},
					onSuccess: this.updateHandler
				})
			}
		}
		return this
	},
	updateNextButton: function ($super) {
		var a = this.currentLastPosition();
		var b = this.currentSize();
		var c = "next_button" + this.options.disabledButtonSuffix;
		if (this.nextButton.hasClassName(c) && a != b) {
			this.nextButton.removeClassName(c);
			this.fire('nextButton:enabled')
		}
		if (!this.nextButton.hasClassName(c) && a == b && !this.hasMore) {
			this.nextButton.addClassName(c);
			this.fire('nextButton:disabled')
		}
	}
});

