/*
 * jquery.tools 1.1.2 - The missing UI library for the Web
 *
 * [tools.scrollable-1.1.2]
 *
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * -----
 *
 * File generated: Wed Oct 07 11:03:38 GMT+00:00 2009
 */
(function(b){b.tools=b.tools||{};b.tools.scrollable={version:"1.1.2",conf:{size:5,vertical:false,speed:400,keyboard:true,keyboardSteps:null,disabledClass:"disabled",hoverClass:null,clickable:true,activeClass:"active",easing:"swing",loop:false,items:".items",item:null,prev:".prev",next:".next",prevPage:".prevPage",nextPage:".nextPage",api:false}};var c;function a(o,m){var r=this,p=b(this),d=!m.vertical,e=o.children(),k=0,i;if(!c){c=r}b.each(m,function(s,t){if(b.isFunction(t)){p.bind(s,t)}});if(e.length>1){e=b(m.items,o)}function l(t){var s=b(t);return m.globalNav?s:o.parent().find(t)}o.data("finder",l);var f=l(m.prev),h=l(m.next),g=l(m.prevPage),n=l(m.nextPage);b.extend(r,{getIndex:function(){return k},getClickIndex:function(){var s=r.getItems();return s.index(s.filter("."+m.activeClass))},getConf:function(){return m},getSize:function(){return r.getItems().size()},getPageAmount:function(){return Math.ceil(this.getSize()/m.size)},getPageIndex:function(){return Math.ceil(k/m.size)},getNaviButtons:function(){return f.add(h).add(g).add(n)},getRoot:function(){return o},getItemWrap:function(){return e},getItems:function(){return e.children(m.item)},getVisibleItems:function(){return r.getItems().slice(k,k+m.size)},seekTo:function(s,w,t){if(s<0){s=0}if(k===s){return r}if(b.isFunction(w)){t=w}if(s>r.getSize()-m.size){return m.loop?r.begin():this.end()}var u=r.getItems().eq(s);if(!u.length){return r}var v=b.Event("onBeforeSeek");p.trigger(v,[s]);if(v.isDefaultPrevented()){return r}if(w===undefined||b.isFunction(w)){w=m.speed}function x(){if(t){t.call(r,s)}p.trigger("onSeek",[s])}if(d){e.animate({left:-u.position().left},w,m.easing,x)}else{e.animate({top:-u.position().top},w,m.easing,x)}c=r;k=s;v=b.Event("onStart");p.trigger(v,[s]);if(v.isDefaultPrevented()){return r}f.add(g).toggleClass(m.disabledClass,s===0);h.add(n).toggleClass(m.disabledClass,s>=r.getSize()-m.size);return r},move:function(u,t,s){i=u>0;return this.seekTo(k+u,t,s)},next:function(t,s){return this.move(1,t,s)},prev:function(t,s){return this.move(-1,t,s)},movePage:function(w,v,u){i=w>0;var s=m.size*w;var t=k%m.size;if(t>0){s+=(w>0?-t:m.size-t)}return this.move(s,v,u)},prevPage:function(t,s){return this.movePage(-1,t,s)},nextPage:function(t,s){return this.movePage(1,t,s)},setPage:function(t,u,s){return this.seekTo(t*m.size,u,s)},begin:function(t,s){i=false;return this.seekTo(0,t,s)},end:function(t,s){i=true;var u=this.getSize()-m.size;return u>0?this.seekTo(u,t,s):r},reload:function(){p.trigger("onReload");return r},focus:function(){c=r;return r},click:function(u){var v=r.getItems().eq(u),s=m.activeClass,t=m.size;if(u<0||u>=r.getSize()){return r}if(t==1){if(m.loop){return r.next()}if(u===0||u==r.getSize()-1){i=(i===undefined)?true:!i}return i===false?r.prev():r.next()}if(t==2){if(u==k){u--}r.getItems().removeClass(s);v.addClass(s);return r.seekTo(u,time,fn)}if(!v.hasClass(s)){r.getItems().removeClass(s);v.addClass(s);var x=Math.floor(t/2);var w=u-x;if(w>r.getSize()-t){w=r.getSize()-t}if(w!==u){return r.seekTo(w)}}return r},bind:function(s,t){p.bind(s,t);return r},unbind:function(s){p.unbind(s);return r}});b.each("onBeforeSeek,onStart,onSeek,onReload".split(","),function(s,t){r[t]=function(u){return r.bind(t,u)}});f.addClass(m.disabledClass).click(function(){r.prev()});h.click(function(){r.next()});n.click(function(){r.nextPage()});if(r.getSize()<m.size){h.add(n).addClass(m.disabledClass)}g.addClass(m.disabledClass).click(function(){r.prevPage()});var j=m.hoverClass,q="keydown."+Math.random().toString().substring(10);r.onReload(function(){if(j){r.getItems().hover(function(){b(this).addClass(j)},function(){b(this).removeClass(j)})}if(m.clickable){r.getItems().each(function(s){b(this).unbind("click.scrollable").bind("click.scrollable",function(t){if(b(t.target).is("a")){return}return r.click(s)})})}if(m.keyboard){b(document).unbind(q).bind(q,function(t){if(t.altKey||t.ctrlKey){return}if(m.keyboard!="static"&&c!=r){return}var u=m.keyboardSteps;if(d&&(t.keyCode==37||t.keyCode==39)){r.move(t.keyCode==37?-u:u);return t.preventDefault()}if(!d&&(t.keyCode==38||t.keyCode==40)){r.move(t.keyCode==38?-u:u);return t.preventDefault()}return true})}else{b(document).unbind(q)}});r.reload()}b.fn.scrollable=function(d){var e=this.eq(typeof d=="number"?d:0).data("scrollable");if(e){return e}var f=b.extend({},b.tools.scrollable.conf);d=b.extend(f,d);d.keyboardSteps=d.keyboardSteps||d.size;this.each(function(){e=new a(b(this),d);b(this).data("scrollable",e)});return d.api?e:this}})(jQuery);


/**
 * tools.scrollable 1.1.2 - Scroll your HTML with eye candy.
 *
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/scrollable.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch  : March 2008
 * Date: ${date}
 * Revision: ${revision}
 */
(function($) {

	// static constructs
	$.tools = $.tools || {};

	$.tools.scrollable = {
		version: '1.1.2',

		conf: {

			// basics
			size: 5,
			vertical: false,
			speed: 400,
			keyboard: true,

			// by default this is the same as size
			keyboardSteps: null,

			// other
			disabledClass: 'disabled',
			hoverClass: null,
			clickable: true,
			activeClass: 'active',
			easing: 'swing',
			loop: false,

			items: '.items',
			item: null,

			// navigational elements
			prev: '.prev',
			next: '.next',
			prevPage: '.prevPage',
			nextPage: '.nextPage',
			api: false

			// CALLBACKS: onBeforeSeek, onSeek, onReload
		}
	};

	var current;

	// constructor
	function Scrollable(root, conf) {

		// current instance
		var self = this, $self = $(this),
			 horizontal = !conf.vertical,
			 wrap = root.children(),
			 index = 0,
			 forward;


		if (!current) { current = self; }

		// bind all callbacks from configuration
		$.each(conf, function(name, fn) {
			if ($.isFunction(fn)) { $self.bind(name, fn); }
		});

		if (wrap.length > 1) { wrap = $(conf.items, root); }

		// navigational items can be anywhere when globalNav = true
		function find(query) {
			var els = $(query);
			return conf.globalNav ? els : root.parent().find(query);
		}

		// to be used by plugins
		root.data("finder", find);

		// get handle to navigational elements
		var prev = find(conf.prev),
			 next = find(conf.next),
			 prevPage = find(conf.prevPage),
			 nextPage = find(conf.nextPage);


		// methods
		$.extend(self, {

			getIndex: function() {
				return index;
			},

			getClickIndex: function() {
				var items = self.getItems();
				return items.index(items.filter("." + conf.activeClass));
			},

			getConf: function() {
				return conf;
			},

			getSize: function() {
				return self.getItems().size();
			},

			getPageAmount: function() {
				return Math.ceil(this.getSize() / conf.size);
			},

			getPageIndex: function() {
				return Math.ceil(index / conf.size);
			},

			getNaviButtons: function() {
				return prev.add(next).add(prevPage).add(nextPage);
			},

			getRoot: function() {
				return root;
			},

			getItemWrap: function() {
				return wrap;
			},

			getItems: function() {
				return wrap.children(conf.item);
			},

			getVisibleItems: function() {
				return self.getItems().slice(index, index + conf.size);
			},

			/* all seeking functions depend on this */
			seekTo: function(i, time, fn) {

				if (i < 0) { i = 0; }

				// nothing happens
				if (index === i) { return self; }

				// function given as second argument
				if ($.isFunction(time)) {
					fn = time;
				}

				// seeking exceeds the end
				if (i > self.getSize() - conf.size) {
					return conf.loop ? self.begin() : this.end();
				}

				var item = self.getItems().eq(i);
				if (!item.length) { return self; }

				// onBeforeSeek
				var e = $.Event("onBeforeSeek");

				$self.trigger(e, [i]);
				if (e.isDefaultPrevented()) { return self; }

				// get the (possibly altered) speed
				if (time === undefined || $.isFunction(time)) { time = conf.speed; }

				function callback() {
					if (fn) { fn.call(self, i); }
					$self.trigger("onSeek", [i]);
				}

				if (horizontal) {
					wrap.animate({left: -item.position().left}, time, conf.easing, callback);
				} else {
					wrap.animate({top: -item.position().top}, time, conf.easing, callback);
				}


				current = self;
				index = i;

				// onStart
				e = $.Event("onStart");
				$self.trigger(e, [i]);
				if (e.isDefaultPrevented()) { return self; }


				/* default behaviour */

				// prev/next buttons disabled flags
				prev.add(prevPage).toggleClass(conf.disabledClass, i === 0);
				next.add(nextPage).toggleClass(conf.disabledClass, i >= self.getSize() - conf.size);

				return self;
			},


			move: function(offset, time, fn) {
				forward = offset > 0;
				return this.seekTo(index + offset, time, fn);
			},

			next: function(time, fn) {
				return this.move(1, time, fn);
			},

			prev: function(time, fn) {
				return this.move(-1, time, fn);
			},

			movePage: function(offset, time, fn) {
				forward = offset > 0;
				var steps = conf.size * offset;

				var i = index % conf.size;
				if (i > 0) {
				 	steps += (offset > 0 ? -i : conf.size - i);
				}

				return this.move(steps, time, fn);
			},

			prevPage: function(time, fn) {
				return this.movePage(-1, time, fn);
			},

			nextPage: function(time, fn) {
				return this.movePage(1, time, fn);
			},

			setPage: function(page, time, fn) {
				return this.seekTo(page * conf.size, time, fn);
			},

			begin: function(time, fn) {
				forward = false;
				return this.seekTo(0, time, fn);
			},

			end: function(time, fn) {
				forward = true;
				var to = this.getSize() - conf.size;
				return to > 0 ? this.seekTo(to, time, fn) : self;
			},

			reload: function() {
				$self.trigger("onReload");
				return self;
			},

			focus: function() {
				current = self;
				return self;
			},

			click: function(i) {

				var item = self.getItems().eq(i),
					 klass = conf.activeClass,
					 size = conf.size;

				// check that i is sane
				if (i < 0 || i >= self.getSize()) { return self; }

				// size == 1
				if (size == 1) {
					if (conf.loop) { return self.next(); }

					if (i === 0 || i == self.getSize() -1)  {
						forward = (forward === undefined) ? true : !forward;
					}
					return forward === false  ? self.prev() : self.next();
				}

				// size == 2
				if (size == 2) {
					if (i == index) { i--; }
					self.getItems().removeClass(klass);
					item.addClass(klass);
					return self.seekTo(i, time, fn);
				}

				if (!item.hasClass(klass)) {
					self.getItems().removeClass(klass);
					item.addClass(klass);
					var delta = Math.floor(size / 2);
					var to = i - delta;

					// next to last item must work
					if (to > self.getSize() - size) {
						to = self.getSize() - size;
					}

					if (to !== i) {
						return self.seekTo(to);
					}
				}

				return self;
			},

			// bind / unbind
			bind: function(name, fn) {
				$self.bind(name, fn);
				return self;
			},

			unbind: function(name) {
				$self.unbind(name);
				return self;
			}

		});

		// callbacks
		$.each("onBeforeSeek,onStart,onSeek,onReload".split(","), function(i, ev) {
			self[ev] = function(fn) {
				return self.bind(ev, fn);
			};
		});


		// prev button
		prev.addClass(conf.disabledClass).click(function() {
			self.prev();
		});

		if (self.getSize() <= conf.size) {
			// next button
			next.addClass(conf.disabledClass).click(function() {
				self.next();
			});
		} else {
			// next button
			next.click(function() {
				self.next();
			});
		}




		// prev page button
		nextPage.click(function() {
			self.nextPage();
		});

		if (self.getSize() < conf.size) {
			next.add(nextPage).addClass(conf.disabledClass);
		}


		// next page button
		prevPage.addClass(conf.disabledClass).click(function() {
			self.prevPage();
		});


		// hover
		var hc = conf.hoverClass, keyId = "keydown." + Math.random().toString().substring(10);

		self.onReload(function() {

			// hovering
			if (hc) {
				self.getItems().hover(function()  {
					$(this).addClass(hc);
				}, function() {
					$(this).removeClass(hc);
				});
			}

			// clickable
			if (conf.clickable) {
				self.getItems().each(function(i) {
					$(this).unbind("click.scrollable").bind("click.scrollable", function(e) {
						if ($(e.target).is("a")) { return; }
						return self.click(i);
					});
				});
			}

			// keyboard
			if (conf.keyboard) {

				// keyboard works on one instance at the time. thus we need to unbind first
				$(document).unbind(keyId).bind(keyId, function(evt) {

					// do nothing with CTRL / ALT buttons
					if (evt.altKey || evt.ctrlKey) { return; }

					// do nothing for unstatic and unfocused instances
					if (conf.keyboard != 'static' && current != self) { return; }

					var s = conf.keyboardSteps;

					if (horizontal && (evt.keyCode == 37 || evt.keyCode == 39)) {
						self.move(evt.keyCode == 37 ? -s : s);
						return evt.preventDefault();
					}

					if (!horizontal && (evt.keyCode == 38 || evt.keyCode == 40)) {
						self.move(evt.keyCode == 38 ? -s : s);
						return evt.preventDefault();
					}

					return true;

				});

			} else  {
				$(document).unbind(keyId);
			}

		});

		self.reload();

	}


	// jQuery plugin implementation
	$.fn.scrollable = function(conf) {

		// already constructed --> return API
		var el = this.eq(typeof conf == 'number' ? conf : 0).data("scrollable");
		if (el) { return el; }

		var globals = $.extend({}, $.tools.scrollable.conf);
		conf = $.extend(globals, conf);

		conf.keyboardSteps = conf.keyboardSteps || conf.size;

		this.each(function() {
			el = new Scrollable($(this), conf);
			$(this).data("scrollable", el);
		});

		return conf.api ? el: this;

	};


})(jQuery);


/**
 * jQuery TOOLS plugin :: scrollable.mousewheel 1.0.1
 *
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/scrollable.html#mousewheel
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch  : September 2009
 * Date: ${date}
 * Revision: ${revision}
 *
 *
 * jquery.event.wheel.js - rev 1
 * Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)
 * Liscensed under the MIT License (MIT-LICENSE.txt)
 * http://www.opensource.org/licenses/mit-license.php
 * Created: 2008-07-01 | Updated: 2008-07-14
 */
(function($) {

	$.fn.wheel = function( fn ){
		return this[ fn ? "bind" : "trigger" ]( "wheel", fn );
	};

	// special event config
	$.event.special.wheel = {
		setup: function(){
			$.event.add( this, wheelEvents, wheelHandler, {} );
		},
		teardown: function(){
			$.event.remove( this, wheelEvents, wheelHandler );
		}
	};

	// events to bind ( browser sniffed... )
	var wheelEvents = !$.browser.mozilla ? "mousewheel" : // IE, opera, safari
		"DOMMouseScroll"+( $.browser.version<"1.9" ? " mousemove" : "" ); // firefox

	// shared event handler
	function wheelHandler( event ) {

		switch ( event.type ){

			// FF2 has incorrect event positions
			case "mousemove":
				return $.extend( event.data, { // store the correct properties
					clientX: event.clientX, clientY: event.clientY,
					pageX: event.pageX, pageY: event.pageY
				});

			// firefox
			case "DOMMouseScroll":
				$.extend( event, event.data ); // fix event properties in FF2
				event.delta = -event.detail / 3; // normalize delta
				break;

			// IE, opera, safari
			case "mousewheel":
				event.delta = event.wheelDelta / 120;
				break;
		}

		event.type = "wheel"; // hijack the event
		return $.event.handle.call( this, event, event.delta );
	}


	// version number
	var t = $.tools.scrollable;
	t.plugins = t.plugins || {};
	t.plugins.mousewheel = {
		version: '1.0.1',
		conf: {
			api: false,
			speed: 50
		}
	};

	// scrollable mousewheel implementation
	$.fn.mousewheel = function(conf) {

		var globals = $.extend({}, t.plugins.mousewheel.conf), ret;
		if (typeof conf == 'number') { conf = {speed: conf}; }
		conf = $.extend(globals, conf);

		this.each(function() {

			var api = $(this).scrollable();
			if (api) { ret = api; }

			api.getRoot().wheel(function(e, delta)  {
				api.move(delta < 0 ? 1 : -1, conf.speed || 50);
				return false;
			});
		});

		return conf.api ? ret : this;
	};

})(jQuery);
