/*
* Works with either divs or a list.
*/
(function($){
	
	/* Create a new carousel for each element in the matched set */
	$.fn.clikCarousel = function(o){
		return this.each(function() {
            new $.cC(this, o);
        });
	}
	
	/* The carousel constructor */
	$.cC = function(e,options){
		
		/* Extend the options object */
		options = $.extend({
					next: null,//The id of the button to scroll forward
					prev: null,//The id of the button to scroll backward
					show: null,//The number of images to show in the carousel
					scroll: 1,//The number of images to scroll through
					scrollShowing: true, //overrides the scroll setting above and scrolls through the same number of images which are set to show.
					vertical: false,//Vertical or horizontal carousel
					cycle: true,//Cycle through images
					start: 0,//index of start image
					speed: 300,//Animation speed
					centre: true,//Centre the carousel in the parent
					endAction:'animate',//When the carousel is not cycled, the action when the end is reached. Options: animate, deactivate
					deactivatedClass:'deactivated',//Class name applied to inactive controls
					keyboardCtrl:true,
					autoDeactivate:true,//Deactivate the controls if there are no more images to show and 'cycle' is not set.
					notIfPresent:'div#imageDsp',// Not an ideal solution to other plugins using keyboard control. This is a CSS selector for another element which, if present, stops keyboard control for the carousel.
					nextKey:39,
					prevKey:37,
					size:null,//Options here and below are set by the function
					index:null,
					eW:null,
					eH:null,
					list:null,
					pos:null,
					dAnim:null,
					cssDim:null,
					addItems:null,
					lastIndex:null
					},
					options||{});
		
		/* Set up the carousel for the element passed in */
		return $(e).each(function(){
			$e = $(e);
			options.eW=0;
			options.eH=0;
			options.eWFull=0;
			options.eHFull=0;
			outerId = 'outer';
			
			var outer;
			var parent = $e.parent();//The element that the carousel element is in.
			ul = $('ul',e);//Look for a list in the element.
			/* If there is a list then set the list items to be the carousel elements (called 'div') */
			if(ul.size()>0){
				div = $('li',e);
				outer = ul;
			}
			/* If there is no list then assume the carousel uses divs */
			else{
				/* Get divs which are direct descendents of the element passed in */
				//div = $('#'+e.id+'>div');
				div = $($e.children());
				//Wrap the divs in an outer div which is the one actually moved.
				div.wrapAll($('<div id="'+outerId+'"></div>'));
				outer = $('div#'+outerId);
			}
			
			/* Set css commands for carousel elements - either divs or lis 
				Float them left if it's horizontal */
			div.css({
					'float':options.vertical?'none':'left',
					display:'inline',
					'list-style-type':'none'//,//Will only apply to li but set it any way.
					//overflow:'hidden'.//
					//'text-align':'center'
					});
			/*Find the maximum width of all the elements within the carousel.*/
			div.each(function(){
				//widthFull = $(this).csswidth();
				//heightFull = $(this).cssheight();
				widthFull = $(this).outerWidth(1);
				heightFull = $(this).outerHeight(1);
				width = $(this).width();
				height = $(this).height();
				if(width > options.eW){
					options.eW = width;
				}
				if(widthFull > options.eWFull){
					options.eWFull = widthFull;
				}
				if(height > options.eH){
					options.eH = height;
				}
				if(heightFull > options.eHFull){
					options.eHFull = heightFull;
				}			
			});
			parentWidth = parent.width() - 
					((parseInt($e.css('margin-left')) || 0) + 
					(parseInt($e.css('margin-right')) || 0));
			parentHeight = parent.height() - 
					((parseInt($e.css('margin-top')) || 0) + 
					(parseInt($e.css('margin-bottom')) || 0));
						
			/* If there is no specific number of images to show then calculate it as a proportion of the parent width/height */			
			if(!options.show){
				options.show = options.vertical ? parseInt(parentHeight/options.eHFull) : parseInt(parentWidth/options.eWFull);
			}
			/* Set the height and width of all elements to be the same and find the number of elements */
			options.size = div.css({
								height:options.eH,
								width:options.eW
							})
							.size();
			if(options.size > 0){
				/* If the total number of items is less than is set to show, alter the number to show */
				options.show = options.show>options.size?options.size:options.show;
				/* If the total number of items is less than the number to scroll through then set scroll to the number showing 
					OR if scrollShowing is set to true. */
				options.scroll = options.scroll>options.size||options.scrollShowing?options.show:options.scroll;
				
				/* Remove padding */
				$e.css({
						'padding-top':0,
						'padding-bottom':0,
						'padding-left':0,
						'padding-right':0});
				
				/* Centre the carousel in the parent element */
				if(options.centre){
					if(options.vertical){
						mT = parseInt($e.css('margin-top')) || 0;
						mB = parseInt($e.css('margin-bottom')) || 0;
						addMargin = (parentHeight - options.show*options.eHFull)/2;
						$e.css({'margin-top':mT+addMargin,'margin-bottom':mB+addMargin})
					}
					else{
						mL = parseInt($e.css('margin-left')) || 0;
						mR = parseInt($e.css('margin-right')) || 0;
						addMargin = (parentWidth - options.show*options.eWFull)/2;
						$e.css({'margin-left':mL+addMargin,'margin-right':mR+addMargin});
					}
				}
				
				/* Set the animation axis and quantum */
				options.dAnim = options.vertical?'top':'left';
				options.cssDim = options.vertical?options.eHFull:options.eWFull;
				
				/* If the carousel is to cycle through at either end, copy and append elements to the start and end. */
				if(options.cycle){
					options.addItems = options.show > options.scroll ? options.show : options.scroll;
					//options.addItems = options.addItems > options.size ? options.size : options.addItems;
					outer.prepend(div.slice(options.size - options.addItems).clone()).append(div.slice(0, options.addItems).clone());
					options.lastIndex = options.size+options.addItems-1;
					options.totalSize = options.size + options.addItems*2 + 1;
				}
				else{
					//options.lastIndex = options.show>options.scroll?options.size-options.show:options.size-options.scroll;
					options.lastIndex = options.size-options.show;
					//options.lastIndex = options.lastIndex<0?0:options.lastIndex;
					options.totalSize = options.size;
				}
				
				/* Set the styling for the carousel element */
				borderV = parseInt($e.css('borderTopWidth')) + parseInt($e.css('borderBottomWidth'));
				borderH = parseInt($e.css('borderLeftWidth')) + parseInt($e.css('borderRightWidth'));
				$e.css({
							overflow:'hidden',
							position:'relative'})
						//.height((options.vertical?(options.show*options.eHFull):options.eHFull))
						//.width((options.vertical?options.eWFull:options.show*options.eWFull));
						.height((options.vertical?(options.show*options.eHFull):options.eHFull)+borderV) //no need to remove border width from width.
						.width((options.vertical?options.eWFull:options.show*options.eWFull));
				
				/* Adjust start index if passed option is greater than the size */
				if(options.start > options.size-1){
					options.start = 0;
				}
				
				toggleActiveButtons(options.start);
							
				/* Set initial index depending on passed start index and whether the carousel will cycle */
				options.index = options.cycle ? options.addItems+options.start : options.start;
				
				options.list = outer.css({position:'absolute'});
				//options.vertical?outer.height(options.size*options.eHFull):.width(options.size*options.eWFull);
				options.pos = -(options.index*options.cssDim);
				options.list.css(options.dAnim=='left'?
					{left:options.pos,width:options.totalSize*options.eWFull}:
					{top:options.pos,height:options.totalSize*options.eHFull});
				
				running = false;
				
				if(options.size==options.show && options.autoDeactivate && !options.cycle){
					$(options.prev+','+options.next).hide();
					$('#carouselMessage').hide();
				}
				else {
					if(options.next){
						$(options.next).click(function(){
							moveTo(options.index+options.scroll);
							return false;
						});
					}
					
					if(options.prev){
						$(options.prev).click(function(){
							moveTo(options.index-options.scroll);
							return false;
						});
					}
										
					if(options.keyboardCtrl){
						$(document)
						.unbind('keydown.clikCarousel')
						.bind('keydown.clikCarousel',function(e){
							if(!$(options.notIfPresent).size()){
								if(e.keyCode == options.nextKey){
									moveTo(options.index+options.scroll);
								}
								if(e.keyCode == options.prevKey){
									moveTo(options.index-options.scroll);
								}
							}
						});
					}
				}
			}
			
			
		});
		
		function moveTo(newIndex){
			if(!running){
				running = true;
				if(newIndex > options.index){
					if(newIndex > options.lastIndex && options.cycle){
						newIndex -= (options.size + options.scroll);
						moveList(newIndex);
						newIndex += options.scroll;
					}
					else if(newIndex > options.lastIndex && !options.cycle){
						dI = -1;
						newIndex = options.lastIndex;
						if(options.endAction==='deactivate'){
							$(options.next).addClass(options.deactivatedClass);
						}
					}					
					newPos = options.pos - ((newIndex - options.index)*options.cssDim);
				}
				else{
					if(newIndex < 0 && options.cycle){
						newIndex += (options.size + options.scroll);
						moveList(newIndex);
						newIndex -= options.scroll;
					}
					else if(newIndex < 0 && !options.cycle){
						dI = 1;
						newIndex = 0;
					}
					if(newIndex-options.scroll < 0 && !options.cycle && options.endAction==='deactivate'){
						$(options.prev).addClass(options.deactivatedClass);
					}
					newPos = options.pos + ((options.index - newIndex)*options.cssDim);
				}
				if(!options.cycle && options.endAction==='animate' && (newIndex == 0 || newIndex == options.lastIndex) && newIndex == options.index){
					tmpPos = newPos;
					/*if(options.index == 0){
						dI = 1;
					}					
					else if(options.index == options.lastIndex){
						dI = -1;
					}*/
					tmpPos = options.pos + ((options.index - newIndex + dI)*options.cssDim)/2;
					options.list.animate(options.dAnim=='left'?{left:tmpPos}:{top:tmpPos},(options.speed/2),'linear',function(){running = false;});
				}
				options.list.animate(options.dAnim=='left'?{left:newPos}:{top:newPos},options.speed,'linear',function(){running = false;});
				options.index = newIndex;
				options.pos = newPos;

				toggleActiveButtons(options.index);
				
			}
			return false;
			
		}
		
		function toggleActiveButtons(testIndex){
			if(!options.cycle && options.endAction==='deactivate'){
				testIndex == 0?$(options.prev).addClass(options.deactivatedClass):$(options.prev).removeClass(options.deactivatedClass);				
				testIndex == options.lastIndex?$(options.next).addClass(options.deactivatedClass):$(options.next).removeClass(options.deactivatedClass);
			}
		}
		
		function moveList(i){
			options.list.css(options.dAnim=='left'?{left:-(i*options.cssDim)}:{top:-(i*options.cssDim)});
		}
				
	}
	
})(jQuery);