// Defines the default options for a carousel
// These options can be modified per service or per unique carousel, in the service-specific .js file

(function($){
		
	// Carry on if the browser is supported 
	var wsCarousel = {	
	
		// Metadata
		author: 'BBC World Service',
		version: '0.0.2',
		
		// Movement
		auto: null,
		circular: true,		
		scroll: 4,
		speed: 1500,
		count: 1,		
		easing: 'easeOutQuart',
		
		// Display
		visible: 4,		
		start: 0,					
		vertical: false,
		flush: false,
		gap: 10,

		// Events
		beforeStart: null,
		afterEnd: null,
		
		// Hooks
		divClass: 	null,
		ulClass: 	null,
		navClass:	"js-nav",
		btnNext: 	"next",
		btnPrev: 	"prev",
		pageClass:	"page",
		
		
		// Dynamic Properties, assigned during build()
		// pages

		// Other
		// snip: 0,		
		// index: 0,

		build: function(currCarousel) {
		
			// Check if the browser can handle this script
			if(($.browser.opera && $.browser.version < 8) || ($.browser.msie && $.browser.version < 6)) return;
			// Stop now if not		
			
			// Add instance-specific properties
			wsCarousel.total = currCarousel.find(".list-items li").length;
			
			if (wsCarousel.total > wsCarousel.visible) {	
			
				// Add class for JavaScript-only carousel style
				currCarousel.addClass("js-carousel");
				
				// Add class if movement is vertical
				if (wsCarousel.vertical == true) {currCarousel.find(".list-content").addClass("js-vertical");}

				// Add navigation controls						
				currCarousel.buildNav(wsCarousel);
				
				// Run jCarouselLite
				currCarousel.jCarouselLite(wsCarousel);
			} else {
				// Add class to specify that javascript enhancements are turned off
				// for this specific instance of the carousel
				currCarousel.addClass("js-carousel-off");
			}
		}
	};
	if ($.ws.wsCarousel) {
		wsCarousel = pseudoPrototype($.ws.wsCarousel, wsCarousel);		
	};
	$.fn.wsCarousel = wsCarousel;	
	
		
	/**
	 * jCarouselLite - jQuery plugin to navigate images/any content in a carousel style widget.
	 * @requires jQuery v1.1.3.1 or above
	 *
	 * http://gmarwaha.com/jquery/jcarousellite/
	 *
	 * Copyright (c) 2007 Ganeshji Marwaha (gmarwaha.com)
	 * Dual licensed under the MIT and GPL licenses:
	 * http://www.opensource.org/licenses/mit-license.php
	 * http://www.gnu.org/licenses/gpl.html
	 *
	 * Version: 1.0
	 */
	 
	/** Modified by the BBC World Service, 2008 **/

	$.fn.buildNav = function(settings){
	
		var div = settings.divClass != null ? $(this).find("." + settings.divClass) : $(this).find("div:first");	
		var div = div.parent();		
		var navClass = settings.navClass != null ? settings.navClass : "js-nav";
		// Resave class so up-to-date when used by CarouselLite
		settings.navClass = navClass;
			
		// Insert the basic navigation markup
		div.prepend('<div class="' + navClass + '"><ul><li class="prev scroll"><span class="label">Previous</span>&nbsp;</li><li class="next scroll">&nbsp;<span class="label">Next</span></li></ul></div>');
		var nav = div.find(".js-nav");
		
		// Calculate how many 'pages' the carousel will divide into
		var ul = settings.ulClass != null ? div.find("." + settings.ulClass) : div.find("ul:not(." + navClass + ")");			
		var totalPages = Math.ceil(ul.find("li").length / settings.visible);	
		settings.pages = totalPages;
		
		// Insert a list item for each 'page' in the carousel		
		for(var i = 0; i < totalPages; i++){
			div.find(".next").before('<li class="page"><span class="label hidden">Page </span><span class="count">' + (i + 1) + '</span></li>');
		}		

		// Collect together each different type of navigation link
		var navUL = nav.find("ul");
		var pagesUL = navUL.find(".page");
		var scrollUL = navUL.find(".next, .prev");
		
		var navHeight = height(pagesUL);
		pagesUL.css("width", navHeight + "px");
		
		var navWidth = 0;
		navUL.find("li").each(function(){
			navWidth = navWidth + width($(this));
		});
			 		
		navUL.css("width", navWidth + "px");
		navUL.css("height", navHeight + "px");
		navUL.css("lineHeight", navHeight + "px");

	
		scrollUL.css("height", navHeight + "px");
		scrollUL.find("p").each(function(){
           $(this).css("margin-top", (navHeight - height($(this))) / 2);
        });
		
		// Add .selected to the current page
		var onLastPage = showCurrentPage(nav, (settings.circular ? (settings.start + settings.visible) + 1 : settings.start + 1), settings);
		
		// Check whether scroll buttons need disabling
		if (!settings.circular) {
			if (settings.start == 0) {
				navUL.find(".prev").addClass("disabled");				
			} else if (onLastPage) {
				navUL.find(".next").addClass("disabled");
			};
		};

	};
	
	$.fn.jCarouselLite = function(settings){   
	
		return this.each(function() {                          		// Returns the element collection. Chainable.
		
			var running = false;
			var animCss = settings.vertical ? "top" : "left";				// If vertical = true then animCss = top, else animCss = left
			var sizeCss = settings.vertical ? "height" : "width";			// If vertical = true then sizeCss = height, else animCss = width				

			var carousel = $(this);			
			var div = settings.divClass != null ? $(this).find("." + settings.divClass) : $(this).find("div:not(." + settings.navClass + "):first");		// Find the parent of the carousel's actual list
			var ul = settings.ulClass != null ? div.find("." + settings.ulClass) : div.find("ul");											// Find the carousel's actual list container
			
			var trueLi = ul.find("li");						// Find the items in the list
			var trueLength = trueLi.length;					// Count how many items are in the list
			var visible = settings.visible;					// Count how many items are actually visible
		
			// TEMP			
			// var index;
			// ul.find("li").each(function(){
			// 	index = ul.find("li").index(this) + 1;
			// 	$(this).find(".ts-body .body a").before("<p>Original: " + index + "</p>");
			// });
			// END TEMP					
										
			if(settings.circular) { 
				ul.prepend(trueLi.slice(trueLength - visible).clone()).append(trueLi.slice(0, visible).clone());
				settings.start += visible;
			}

			// Remove .first (not needed for js-enhanced carousel)
            ul.find("li.first").removeClass("first");
			
			// TEMP			
			// var index;
			// ul.find("li").each(function(){
			// 	index = ul.find("li").index(this) + 1;
			// 	$(this).find(".ts-body .body a").replaceWith("<p>New: " + index + "</p>");
			// });
			// END TEMP
		
			var li = ul.find("li");					// Find the items in the possibly new, extended list 
			var itemLength = li.length;					// And count them 
			var curr = settings.start;					// Find out which one should be first		
		
			var liSize = settings.vertical ? height(li) : width(li);	// Full li size (incl margin) - Used for animation											

			var ulSize = liSize * itemLength;                  			// size of full ul (total length, not just for the visible items)
			var divSize = liSize * visible;								// size of entire div (total length for just the visible items)
			var startCoord = -(curr * liSize);							// pseudo-coordinates of item to show first
			
			// Adjust if flush edges required
			if (settings.flush = true) {				
				divSize = divSize - settings.gap;			
			}
			
			ul.css(sizeCss, ulSize+"px")                    // Width of the UL is the full length for all the images
			.css(animCss, startCoord);          	        // Move to item specified to be first
			
			div.css(sizeCss, divSize+"px");                 // Width of the DIV. length of visible images	
		
			if (settings.btnPrev && settings.btnNext) {
				$(document).ready(function(){			
					$("." + settings.btnPrev).click(function() { 	
						if(!running){settings.count--;} 					// only count once
						return go(curr - settings.scroll); 								
					});
					$("." + settings.btnNext).click(function() { 	
						if(!running){settings.count++;} 					// only count once		
						return go(curr + settings.scroll); 									
					});
					if (settings.pageClass != null && settings.pageClass != '') {
						$("." + settings.navClass).find("." + settings.pageClass).click(function(){
							var clickedPage = $("." + settings.navClass).find("." + settings.pageClass).index($(this)) + 1;
							if (clickedPage != settings.count) {												
								if(!running) {settings.count = clickedPage;}
								var skipTo = (settings.count - 1) * settings.visible;
								if (settings.circular) {
									skipTo = skipTo + settings.visible;
								}								
								return go(skipTo);
							};
						});
					};

				});			
			};
		
			if(settings.auto) {
				setInterval(function() { 
					go(curr+settings.scroll); 				
				}, settings.auto+settings.speed);
			};	
		
			function vis() {
				return li.slice(curr - 1).slice(0, visible, o);
			}; 	
		
			function go(to) {
				if(!running) {				
					if(settings.beforeStart) {
						settings.beforeStart.call(this, vis(), o); // matc :: added object to return call()
					}						
					
					if(settings.circular) {            // If circular we are in first or last, then goto the other end
					
						var listWidth;
						if(to <= settings.start - visible - 1) {           // If first, then goto last
						
							listWidth = -((itemLength - (visible * 2)) * liSize) + "px";					
												
							ul.css(animCss, -((itemLength - (visible * 2)) * liSize) + "px");  
							// If "scroll" > 1, then the "to" might not be equal to the condition; it can be lesser depending on the number of elements. 
							curr = to == settings.start - visible - 1 ? itemLength - (visible * 2) - 1 : itemLength - (visible * 2) - settings.scroll;
						
						} else if(to >= itemLength - visible + 1) { // If last, then goto first
						
							listWidth = -((visible) * liSize) + "px";																	
						
							ul.css(animCss, -((visible) * liSize) + "px" );
							// If "scroll" > 1, then the "to" might not be equal to the condition; it can be greater depending on the number of elements. 
							curr = to == itemLength - visible + 1 ? visible + 1 : visible + settings.scroll;
					
						} else {
							curr = to;
						}
						
					} else {                    // If non-circular and to points to first or last, we just return.		
					
						if(to < 0 || to > itemLength - visible) return;
						else curr = to;
					}                           // If neither overrides it, the curr will still be "to" and we can proceed.


					// Calculate how many pixels the list needs to be moved by					
					var moveBy = settings.flush ? -(curr * liSize) :  -(curr * liSize);			
					
					running = true;
				
					ul.animate(
						animCss == "left" ? { left: moveBy } : { top: moveBy }, settings.speed, settings.easing,
						function() {																				
						
							if(settings.afterEnd) {
								settings.afterEnd.call(this, vis(), o); // matc :: added object to return call()								
							}
							running = false;
						}
					);											

					// Update the navigation so that it shows the new current page
					var onLastPage = showCurrentPage(carousel.find("." + settings.navClass), (curr + 1), settings);

					// Disable buttons when the carousel reaches the last/first, and enable when not
					if(!settings.circular) {
						$("." + settings.btnPrev + ", ." + settings.btnNext).removeClass("disabled");
						$(
							((curr - settings.scroll < 0) && ("." + settings.btnPrev)) 
							|| 
							((curr + settings.scroll > itemLength - visible) && ("." + settings.btnNext))
							||
							[]
						).addClass("disabled");
					}												
				}		
				
				return false;
			};
		});
	};

	
	function css(el, prop) {
	    return parseInt($.css(el[0], prop)) || 0;
	};
	
	function width(el) {
	    return  el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');
	};
	
	function height(el) {
	    return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');
	};
	
	function margin(el, vertical) {		
		return vertical ? css(el, 'marginTop') : css(el, 'marginLeft');
	};
	
	function showCurrentPage(nav, curr, settings) {
		
		// Remove .selected from the old current page
		nav.find(".page.selected").removeClass("selected");					

		// Calculate which page is the new current page
		var currPage = Math.ceil((curr + 1) / settings.visible);
		
		if (settings.circular) {
			currPage = currPage - 1;
			if (currPage > settings.pages) {
				currPage = 1;
			} else if (currPage < 1) {
				currPage = settings.pages;
			}	
		};
		
		// Add .selected to the new current page
		nav.find(".page:eq("+ (currPage - 1) + ")").addClass("selected");		
		
		return currPage == nav.find(".page").length ? true : false;
	};		
	
})(jQuery);
