﻿/*
* jQuery Carousel Plugin v1.0
* http://richardscarrott.co.uk/posts/view/jquery-carousel-plugin
*
* Copyright (c) 2010 Richard Scarrott
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Requires jQuery v1.4+
*
*/

// prototypal inheritance
if (typeof Object.create !== 'function') {
	Object.create = function (o) {
		function F() { }
		F.prototype = o;
		return new F();
	};
}

(function ($) {
	// ie alias
	var headache = $.browser.msie && $.browser.version.substr(0, 1) < 9;

	// carousel
	var Carousel = {
		settings: {
			itemsPerPage: 1,
			itemsPerTransition: 1,
			noOfRows: 1,
			pagination: true,
			nextPrevLinks: true,
			speed: 'normal',
			easing: 'swing',
			interval: 4000
		},
		init: function (el, options) {
			if (!el.length) { return false; }
			this.options = $.extend({}, this.settings, options);
			this.itemIndex = 0;
			this.container = el;
			this.runner = this.container.find('ul');
			this.items = this.runner.children('li');
			this.noOfItems = this.items.length;
			this.setRunnerWidth();
			if (this.noOfItems <= this.options.itemsPerPage) { return false; } // bail if there are too few items to paginate
			this.insertMask();
			this.noOfPages = Math.ceil((this.noOfItems - this.options.itemsPerPage) / this.options.itemsPerTransition) + 1;
			if (this.options.pagination) { this.insertPagination(); }
			this.insertControls();
			this.items.show(); 	// only the 1st is visible initially, in case JS is disabled and we never get to create the mask
			this.play();
		},
		insertMask: function () {
			this.runner.wrap('<div class="mask" />');
			this.mask = this.container.find('div.mask');

			// set mask height so items can be of varying height
			var maskHeight = this.runner.outerHeight(true);
			this.mask = this.container.find('div.mask');
			this.mask.height(maskHeight);
		},
		setRunnerWidth: function () {
			this.noOfItems = Math.round(this.noOfItems / this.options.noOfRows);
			var width = this.items.outerWidth(true) * this.noOfItems;
			this.runner.width(width);
		},
		insertPagination: function () {
			var i, links = [];
			this.paginationLinks = $('<ol class="pagination-links" />');
			for (i = 0; i < this.noOfPages; i++) {
				links[i] = '<li><a href="#item-' + i + '">' + (i + 1) + '</a></li>';
			}
			this.paginationLinks
				.append(links.join(''))
				.appendTo(this.container)
				.find('a')
					.bind('click.carousel', $.proxy(this, 'paginationHandler'));
		},
		paginationHandler: function (e) {
			this.pause(); 	// stop automatically switching slides
			this.itemIndex = e.target.hash.substr(1).split('-')[1] * this.options.itemsPerTransition;
			this.animate();
			return false;
		},
		nextItem: function () {
			this.itemIndex = this.itemIndex + this.options.itemsPerTransition;
			this.animate();
			return false;
		},
		prevItem: function () {
			this.itemIndex = this.itemIndex - this.options.itemsPerTransition;
			this.animate();
			return false;
		},
		updateBtnStyles: function () {
			if (this.options.pagination) {
				this.paginationLinks
					.children('li')
						.removeClass('current')
						.eq(Math.ceil(this.itemIndex / this.options.itemsPerTransition))
							.addClass('current');
			}

			if (this.options.nextPrevLinks) {
				this.nextLink
					.add(this.prevLink)
						.removeClass('disabled');
				if (this.itemIndex === (this.noOfItems - this.options.itemsPerPage)) {
					this.nextLink.addClass('disabled');
				}
				else if (this.itemIndex === 0) {
					this.prevLink.addClass('disabled');
				}
			}
		},
		animate: function () {
			var nextItem, pos;
			// check whether there are enough items to animate to
			if (this.itemIndex > (this.noOfItems - this.options.itemsPerPage)) {
				//ADC this.itemIndex = this.noOfItems - this.options.itemsPerPage; // go to last panel - items per transition
				this.itemIndex = 0; // ADC - loop
			}
			if (this.itemIndex < 0) {
				this.itemIndex = 0; // go to first
			}
			nextItem = this.items.eq(this.itemIndex);
			pos = nextItem.position();

			if (headache) {
				this.runner
					.stop()
					.animate({ left: -pos.left }, this.options.speed, this.options.easing);
			}
			else {
				this.mask
					.stop()
					.animate({ scrollLeft: pos.left }, this.options.speed, this.options.easing);
			}
			this.updateBtnStyles();
		},
		play: function () {
			var carousel = this;
			this.timer = setInterval(function () {
				carousel.nextItem();
			}, this.options.interval);
			this.playpauseLink
					.removeClass('playcontrol')
					.addClass('pausecontrol')
					.unbind()
					.bind('click.carousel', $.proxy(this, 'pause'));
			return false;
		},
		pause: function () {
			if (this.timer) {
				clearInterval(this.timer);
				this.timer = null;
				this.playpauseLink
					.removeClass('pausecontrol')
					.addClass('playcontrol')
					.unbind()
					.bind('click.carousel', $.proxy(this, 'play'));
			}
			return false;
		},
		showControls: function () {
			// if we mousein before the timer fires to hide the controls (just 2s after we started the carousel)
			// then we need to stop the timer firing otherwise it might hide the controls while we're still hovering
			if (this.hideControlTimer) {
				clearTimeout(this.hideControlTimer);
				this.hideControlTimer = null;
			}
			this.controls.stop().animate({ opacity: 0.5 }, 500);
		},
		hideControls: function () {
			this.controls.stop().animate({ opacity: 0 }, 500);
		},
		insertControls: function () {
			var offset = this.mask.offset();
			this.controls = $('<div id="controls" class="controls"><div id="nextcontrol"></div><div id="playpausecontrol" class="pausecontrol"></div><div id="prevcontrol"></div></div>')
				.css({
					position: 'absolute',
					//left: offset.left,
					//top: offset.top + this.mask.height() - 30,	// positions at bottom. 30 is the height of the controls div
					//top: offset.top,
					opacity: 0.5
				})
				.insertBefore(this.container)
				.show();
			this.mask.add(this.controls).mouseover($.proxy(this, 'showControls'));
			this.mask.add(this.controls).mouseout($.proxy(this, 'hideControls'));
			this.prevLink = $('#prevcontrol').bind('click.carousel', $.proxy(this, 'prevItem'));
			this.nextLink = $('#nextcontrol').bind('click.carousel', $.proxy(this, 'nextItem'));
			this.playpauseLink = $('#playpausecontrol').bind('click.carousel', $.proxy(this, 'pause'));
			this.updateBtnStyles();
			this.hideControlTimer = setTimeout($.proxy(this, 'hideControls'), 2000);
		}
	};

	// bridge
	$.fn.carousel = function (options) {
		return this.each(function () {
			var obj = Object.create(Carousel);
			obj.init($(this), options);
			$.data(this, 'carousel', obj);
		});
	};
})(jQuery);

