/**
 * @license
 * jQuery Tools @VERSION Tabs- The basics of UI design.
 *
 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
 *
 * http://flowplayer.org/tools/tabs/
 *
 * Since: November 2008
 * Date: @DATE
 */
(function($) {

	// static constructs
	$.tools = $.tools || {version: '@VERSION'};

	$.tools.tabs = {

		conf: {
			tabs: 'li',
			current: 'current',
			onBeforeClick: null,
			onClick: null,
			effect: 'default',
			initialIndex: 0,
			event: 'click',
			rotate: false,

			// 1.2
			history: false
		},

		addEffect: function(name, fn) {
			effects[name] = fn;
		}

	};

	var effects = {

		// simple "toggle" effect
		'default': function(i, done) {
			this.getPanes().hide().eq(i).show();
			done.call();
		},

		/*
			configuration:
				- fadeOutSpeed (positive value does "crossfading")
				- fadeInSpeed
		*/
		fade: function(i, done) {

			var conf = this.getConf(),
				 speed = conf.fadeOutSpeed,
				 panes = this.getPanes();

			if (speed) {
				panes.fadeOut(speed);
			} else {
				panes.hide();
			}

			panes.eq(i).fadeIn(conf.fadeInSpeed, done);
		},

		// for basic accordions
		slide: function(i, done) {
			this.getPanes().slideUp(200);
			this.getPanes().eq(i).slideDown(400, done);
		},

		/**
		 * AJAX effect
		 */
		ajax: function(i, done)  {
			this.getPanes().eq(0).load(this.getTabs().eq(i).attr("href"), done);
		}
	};

	var w;

	/**
	 * Horizontal accordion
	 *
	 * @deprecated will be replaced with a more robust implementation
	 */
	$.tools.tabs.addEffect("horizontal", function(i, done) {

		// store original width of a pane into memory
		if (!w) { w = this.getPanes().eq(0).width(); }

		// set current pane's width to zero
		this.getCurrentPane().animate({width: 0}, function() { $(this).hide(); });

		// grow opened pane to it's original width
		this.getPanes().eq(i).animate({width: w}, function() {
			$(this).show();
			done.call();
		});

	});


	function Tabs(root, paneSelector, conf) {

		var self = this,
			 trigger = root.add(this),
			 tabs = root.find(conf.tabs),
			 panes = paneSelector.jquery ? paneSelector : root.children(paneSelector),
			 current;


		// make sure tabs and panes are found
		if (!tabs.length)  { tabs = root.children(); }
		if (!panes.length) { panes = root.parent().find(paneSelector); }
		if (!panes.length) { panes = $(paneSelector); }


		// public methods
		$.extend(this, {
			click: function(i, e) {

				var tab = tabs.eq(i);

				if (typeof i == 'string' && i.replace("#", "")) {
					tab = tabs.filter("[href*=" + i.replace("#", "") + "]");
					i = Math.max(tabs.index(tab), 0);
				}

				if (conf.rotate) {
					var last = tabs.length -1;
					if (i < 0) { return self.click(last, e); }
					if (i > last) { return self.click(0, e); }
				}

				if (!tab.length) {
					if (current >= 0) { return self; }
					i = conf.initialIndex;
					tab = tabs.eq(i);
				}

				// current tab is being clicked
				if (i === current) { return self; }

				// possibility to cancel click action
				e = e || $.Event();
				e.type = "onBeforeClick";
				trigger.trigger(e, [i]);
				if (e.isDefaultPrevented()) { return; }

				// call the effect
				effects[conf.effect].call(self, i, function() {

					// onClick callback
					e.type = "onClick";
					trigger.trigger(e, [i]);
				});

				// default behaviour
				current = i;
				tabs.removeClass(conf.current);
				tab.addClass(conf.current);

				return self;
			},

			getConf: function() {
				return conf;
			},

			getTabs: function() {
				return tabs;
			},

			getPanes: function() {
				return panes;
			},

			getCurrentPane: function() {
				return panes.eq(current);
			},

			getCurrentTab: function() {
				return tabs.eq(current);
			},

			getIndex: function() {
				return current;
			},

			next: function() {
				return self.click(current + 1);
			},

			prev: function() {
				return self.click(current - 1);
			},

			destroy: function() {
				tabs.unbind(conf.event).removeClass(conf.current);
				panes.find("a[href^=#]").unbind("click.T");
				return self;
			}

		});

		// callbacks
		$.each("onBeforeClick,onClick".split(","), function(i, name) {

			// configuration
			if ($.isFunction(conf[name])) {
				$(self).bind(name, conf[name]);
			}

			// API
			self[name] = function(fn) {
				if (fn) { $(self).bind(name, fn); }
				return self;
			};
		});


		if (conf.history && $.fn.history) {
			$.tools.history.init(tabs);
			conf.event = 'history';
		}

		// setup click actions for each tab
		tabs.each(function(i) {
			$(this).bind(conf.event, function(e) {
				self.click(i, e);
				return e.preventDefault();
			});
		});

		// cross tab anchor link
		panes.find("a[href^=#]").bind("click.T", function(e) {
			self.click($(this).attr("href"), e);
		});

		// open initial tab
		if (location.hash && conf.tabs === "a" && root.find(conf.tabs + location.hash).length) {
			self.click(location.hash);
		} else {
			if (conf.initialIndex === 0 || conf.initialIndex > 0) {
				self.click(conf.initialIndex);
			}
		}

	}


	// jQuery plugin implementation
	$.fn.tabs = function(paneSelector, conf) {

		// return existing instance
		var el = this.data("tabs");
		if (el) {
			el.destroy();
			this.removeData("tabs");
		}

		if ($.isFunction(conf)) {
			conf = {onBeforeClick: conf};
		}

		// setup conf
		conf = $.extend({}, $.tools.tabs.conf, conf);

		this.each(function() {
			el = new Tabs($(this), paneSelector, conf);
			$(this).data("tabs", el);
		});

		return conf.api ? el: this;
	};

}) (jQuery);


/**
 * @license
 * jQuery Tools @VERSION Scrollable - New wave UI design
 *
 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
 *
 * http://flowplayer.org/tools/scrollable.html
 *
 * Since: March 2008
 * Date: @DATE
 */
(function($) {

	// static constructs
	$.tools = $.tools || {version: '@VERSION'};

	$.tools.scrollable = {

		conf: {
			activeClass: 'active',
			circular: false,
			clonedClass: 'cloned',
			disabledClass: 'disabled',
			easing: 'swing',
			initialIndex: 0,
			item: null,
			items: '.items',
			keyboard: true,
			mousewheel: false,
			next: '.next',
			prev: '.prev',
			speed: 400,
			vertical: false,
			wheelSpeed: 0
		}
	};

	// get hidden element's width or height even though it's hidden
	function dim(el, key) {
		var v = parseInt(el.css(key), 10);
		if (v) { return v; }
		var s = el[0].currentStyle;
		return s && s.width && parseInt(s.width, 10);
	}

	function find(root, query) {
		var el = $(query);
		return el.length < 2 ? el : root.parent().find(query);
	}

	var current;

	// constructor
	function Scrollable(root, conf) {

		// current instance
		var self = this,
			 fire = root.add(self),
			 itemWrap = root.children(),
			 index = 0,
			 vertical = conf.vertical;

		if (!current) { current = self; }
		if (itemWrap.length > 1) { itemWrap = $(conf.items, root); }

		// methods
		$.extend(self, {

			getConf: function() {
				return conf;
			},

			getIndex: function() {
				return index;
			},

			getSize: function() {
				return self.getItems().size();
			},

			getNaviButtons: function() {
				return prev.add(next);
			},

			getRoot: function() {
				return root;
			},

			getItemWrap: function() {
				return itemWrap;
			},

			getItems: function() {
				return itemWrap.children(conf.item).not("." + conf.clonedClass);
			},

			move: function(offset, time) {
				return self.seekTo(index + offset, time);
			},

			next: function(time) {
				return self.move(1, time);
			},

			prev: function(time) {
				return self.move(-1, time);
			},

			begin: function(time) {
				return self.seekTo(0, time);
			},

			end: function(time) {
				return self.seekTo(self.getSize() -1, time);
			},

			focus: function() {
				current = self;
				return self;
			},

			addItem: function(item) {
				item = $(item);

				if (!conf.circular)  {
					itemWrap.append(item);
				} else {
					itemWrap.children("." + conf.clonedClass + ":last").before(item);
					itemWrap.children("." + conf.clonedClass + ":first").replaceWith(item.clone().addClass(conf.clonedClass));
				}

				fire.trigger("onAddItem", [item]);
				return self;
			},


			/* all seeking functions depend on this */
			seekTo: function(i, time, fn) {

				// ensure numeric index
				if (!i.jquery) { i *= 1; }

				// avoid seeking from end clone to the beginning
				if (conf.circular && i === 0 && index == -1 && time !== 0) { return self; }

				// check that index is sane
				if (!conf.circular && i < 0 || i > self.getSize() || i < -1) { return self; }

				var item = i;

				if (i.jquery) {
					i = self.getItems().index(i);

				} else {
					item = self.getItems().eq(i);
				}

				// onBeforeSeek
				var e = $.Event("onBeforeSeek");
				if (!fn) {
					fire.trigger(e, [i, time]);
					if (e.isDefaultPrevented() || !item.length) { return self; }
				}

				var props = vertical ? {top: -item.position().top} : {left: -item.position().left};

				index = i;
				current = self;
				if (time === undefined) { time = conf.speed; }

				itemWrap.animate(props, time, conf.easing, fn || function() {
					fire.trigger("onSeek", [i]);
				});

				return self;
			}

		});

		// callbacks
		$.each(['onBeforeSeek', 'onSeek', 'onAddItem'], function(i, name) {

			// configuration
			if ($.isFunction(conf[name])) {
				$(self).bind(name, conf[name]);
			}

			self[name] = function(fn) {
				$(self).bind(name, fn);
				return self;
			};
		});

		// circular loop
		if (conf.circular) {

			var cloned1 = self.getItems().slice(-1).clone().prependTo(itemWrap),
				 cloned2 = self.getItems().eq(1).clone().appendTo(itemWrap);

			cloned1.add(cloned2).addClass(conf.clonedClass);

			self.onBeforeSeek(function(e, i, time) {


				if (e.isDefaultPrevented()) { return; }

				/*
					1. animate to the clone without event triggering
					2. seek to correct position with 0 speed
				*/
				if (i == -1) {
					self.seekTo(cloned1, time, function()  {
						self.end(0);
					});
					return e.preventDefault();

				} else if (i == self.getSize()) {
					self.seekTo(cloned2, time, function()  {
						self.begin(0);
					});
				}

			});

			// seek over the cloned item
			self.seekTo(0, 0, function() {});
		}

		// next/prev buttons
		var prev = find(root, conf.prev).click(function() { self.prev(); }),
			 next = find(root, conf.next).click(function() { self.next(); });

		if (!conf.circular && self.getSize() > 1) {

			self.onBeforeSeek(function(e, i) {
				setTimeout(function() {
					if (!e.isDefaultPrevented()) {
						prev.toggleClass(conf.disabledClass, i <= 0);
						next.toggleClass(conf.disabledClass, i >= self.getSize() -1);
					}
				}, 1);
			});
		}

		// mousewheel support
		if (conf.mousewheel && $.fn.mousewheel) {
			root.mousewheel(function(e, delta)  {
				if (conf.mousewheel) {
					self.move(delta < 0 ? 1 : -1, conf.wheelSpeed || 50);
					return false;
				}
			});
		}

		if (conf.keyboard)  {

			$(document).bind("keydown.scrollable", function(evt) {

				// skip certain conditions
				if (!conf.keyboard || evt.altKey || evt.ctrlKey || $(evt.target).is(":input")) { return; }

				// does this instance have focus?
				if (conf.keyboard != 'static' && current != self) { return; }

				var key = evt.keyCode;

				if (vertical && (key == 38 || key == 40)) {
					self.move(key == 38 ? -1 : 1);
					return evt.preventDefault();
				}

				if (!vertical && (key == 37 || key == 39)) {
					self.move(key == 37 ? -1 : 1);
					return evt.preventDefault();
				}

			});
		}

		// initial index
		if (conf.initialIndex) {
			self.seekTo(conf.initialIndex, 0, function() {});
		}
	}


	// jQuery plugin implementation
	$.fn.scrollable = function(conf) {

		// already constructed --> return API
		var el = this.data("scrollable");
		if (el) { return el; }

		conf = $.extend({}, $.tools.scrollable.conf, conf);

		this.each(function() {
			el = new Scrollable($(this), conf);
			$(this).data("scrollable", el);
		});

		return conf.api ? el: this;

	};


})(jQuery);

/**
 * @license
 * jQuery Tools 1.2.4 Slideshow - Extend it.
 *
 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
 *
 * http://flowplayer.org/tools/tabs/slideshow.html
 *
 * Since: September 2009
 * Date:    Sun Aug 15 08:16:31 2010 +0000
 */
(function($) {

	var tool;

	tool = $.tools.tabs.slideshow = {

		conf: {
			next: '.forward',
			prev: '.backward',
			disabledClass: 'disabled',
			autoplay: false,
			autopause: true,
			interval: 3000,
			clickable: true,
			api: false
		}
	};

	function Slideshow(root, conf) {

		var self = this,
			 fire = root.add(this),
			 tabs = root.data("tabs"),
			 timer,
			 hoverTimer,
			 startTimer,
			 stopped = false;


		// next / prev buttons
		function find(query) {
			var el = $(query);
			return el.length < 2 ? el : root.parent().find(query);
		}

		var nextButton = find(conf.next).click(function() {
			tabs.next();
		});

		var prevButton = find(conf.prev).click(function() {
			tabs.prev();
		});


		// extend the Tabs API with slideshow methods
		$.extend(self, {

			// return tabs API
			getTabs: function() {
				return tabs;
			},

			getConf: function() {
				return conf;
			},

			play: function() {

				// do not start additional timer if already exists
				if (timer) { return; }

				// onBeforePlay
				var e = $.Event("onBeforePlay");
				fire.trigger(e);

				if (e.isDefaultPrevented()) { return self; }

				stopped = false;

				// construct new timer
				timer = setInterval(tabs.next, conf.interval);

				// onPlay
				fire.trigger("onPlay");

				tabs.next();
			},

			pause: function() {

				if (!timer && !startTimer) { return self; }

				// onBeforePause
				var e = $.Event("onBeforePause");
				fire.trigger(e);
				if (e.isDefaultPrevented()) { return self; }

				timer = clearInterval(timer);
				startTimer = clearInterval(startTimer);

				// onPause
				fire.trigger("onPause");
			},

			// when stopped - mouseover won't restart
			stop: function() {
				self.pause();
				stopped = true;
			}

		});

		// callbacks
		$.each("onBeforePlay,onPlay,onBeforePause,onPause".split(","), function(i, name) {

			// configuration
			if ($.isFunction(conf[name]))  {
				self.bind(name, conf[name]);
			}

			// API methods
			self[name] = function(fn) {
				return self.bind(name, fn);
			};
		});


		/* when mouse enters, slideshow stops */
		if (conf.autopause) {
			var els = tabs.getTabs().add(nextButton).add(prevButton).add(tabs.getPanes());

			els.hover(function() {
				self.pause();
				hoverTimer = clearInterval(hoverTimer);

			}, function() {
				if (!stopped) {
					hoverTimer = setTimeout(self.play, conf.interval);
				}
			});
		}

		if (conf.autoplay) {
			startTimer = setTimeout(self.play, conf.interval);
		} else {
			self.stop();
		}

		if (conf.clickable) {
			tabs.getPanes().click(function()  {
				tabs.next();
			});
		}

		// manage disabling of next/prev buttons
		if (!tabs.getConf().rotate) {

			var cls = conf.disabledClass;

			if (!tabs.getIndex()) {
				prevButton.addClass(cls);
			}
			tabs.onBeforeClick(function(e, i)  {
				if (!i) {
					prevButton.addClass(cls);
				} else {
					prevButton.removeClass(cls);

					if (i == tabs.getTabs().length -1) {
						nextButton.addClass(cls);
					} else {
						nextButton.removeClass(cls);
					}
				}
			});
		}
	}

	// jQuery plugin implementation
	$.fn.slideshow = function(conf) {

		// return existing instance
		var el = this.data("slideshow");
		if (el) { return el; }

		conf = $.extend({}, tool.conf, conf);

		this.each(function() {
			el = new Slideshow($(this), conf);
			$(this).data("slideshow", el);
		});

		return conf.api ? el : this;
	};

})(jQuery);
