(function($) {
	$.fn.featureCarousel= function(options) {
		options=$.extend({},$.fn.featureCarousel.defaults,options||{});
		return $(this).each( function() {
			var pluginData={currentCenterNum:options.startingFeature,containerWidth:0,containerHeight:0,largeFeatureWidth:0,largeFeatureHeight:0,smallFeatureWidth:0,smallFeatureHeight:0,totalFeatureCount:$(this).children("div").length,currentlyMoving:false,featuresContainer:$(this),featuresArray:[],containerIDTag:"#"+$(this).attr("id"),timeoutVar:null,rotationsRemaining:0,itemsToAnimate:0,borderWidth:0};
			preload( function() {
				setupFeatureDimensions();
				setupCarousel();
				setupFeaturePositions();
				setupBlips();
				initiateMove(true,1);
			});
			function preload(callback) {
				if(options.preload==true) {
					var $imageElements=pluginData.featuresContainer.find("img");
					var loadedImages=0;
					var totalImages=$imageElements.length;
					$imageElements.each( function() {
						$(this).load( function() {
							loadedImages++;
							if(loadedImages==totalImages) {
								callback();
							}
						});
						if(this.complete) {
							$(this).trigger('load');
						}
					});
				} else {
					callback();
				}
			}

			function getContainer(featureNum) {
				return pluginData.featuresArray[featureNum-1];
			}

			function getBySetPos(position) {
				$.each(pluginData.featuresArray, function() {
					if($(this).data().setPosition==position)
						return $(this);
				});
			}

			function getPreviousNum(num) {
				if((num-1)==0) {
					return pluginData.totalFeatureCount;
				} else {
					return num-1;
				}
			}

			function getNextNum(num) {
				if((num+1)>pluginData.totalFeatureCount) {
					return 1;
				} else {
					return num+1;
				}
			}

			function setupFeatureDimensions() {
				pluginData.containerWidth=pluginData.featuresContainer.width();
				pluginData.containerHeight=pluginData.featuresContainer.height();
				var $firstFeatureImage=$(pluginData.containerIDTag).find("div img:first");
				if(options.largeFeatureWidth>1)
					pluginData.largeFeatureWidth=options.largeFeatureWidth;
				else if(options.largeFeatureWidth>0&&options.largeFeatureWidth<1)
					pluginData.largeFeatureWidth=$firstFeatureImage.width()*options.largeFeatureWidth;
				else
					pluginData.largeFeatureWidth=$firstFeatureImage.outerWidth();
				if(options.largeFeatureHeight>1)
					pluginData.largeFeatureHeight=options.largeFeatureHeight;
				else if(options.largeFeatureHeight>0&&options.largeFeatureHeight<1)
					pluginData.largeFeatureHeight=$firstFeatureImage.height()*options.largeFeatureHeight;
				else
					pluginData.largeFeatureHeight=$firstFeatureImage.outerHeight();
				if(options.smallFeatureWidth>1)
					pluginData.smallFeatureWidth=options.smallFeatureWidth;
				else if(options.smallFeatureWidth>0&&options.smallFeatureWidth<1)
					pluginData.smallFeatureWidth=$firstFeatureImage.width()*options.smallFeatureWidth;
				else
					pluginData.smallFeatureWidth=$firstFeatureImage.outerWidth()/2;
				if(options.smallFeatureHeight>1)
					pluginData.smallFeatureHeight=options.smallFeatureHeight;
				else if(options.smallFeatureHeight>0&&options.smallFeatureHeight<1)
					pluginData.smallFeatureHeight=$firstFeatureImage.height()*options.smallFeatureHeight;
				else
					pluginData.smallFeatureHeight=$firstFeatureImage.outerHeight()/2;
			}

			function setupCarousel() {
				if(options.displayCutoff>0&&options.displayCutoff<pluginData.totalFeatureCount) {
					pluginData.totalFeatureCount=options.displayCutoff;
				}
				pluginData.featuresContainer.children("div").each( function(index) {
					if(index<pluginData.totalFeatureCount) {
						pluginData.featuresArray[index]=$(this);
					}
				});
				if(pluginData.featuresContainer.children("div").first().css("borderLeftWidth")!="medium") {
					pluginData.borderWidth=parseInt(pluginData.featuresContainer.children("div").first().css("borderLeftWidth"))*2;
				}
				pluginData.featuresContainer.children("div").each( function() {
					$(this).css({'left':(pluginData.containerWidth/2)-(pluginData.smallFeatureWidth/2)-(pluginData.borderWidth/2),'width':pluginData.smallFeatureWidth,'height':pluginData.smallFeatureHeight,'top':options.smallFeatureOffset+options.topPadding,'opacity':0});
				}).find("img:first").css({'width':pluginData.smallFeatureWidth});
				if(pluginData.totalFeatureCount<4) {
					pluginData.itemsToAnimate=pluginData.totalFeatureCount;
				} else {
					pluginData.itemsToAnimate=4;
				}
			}

			function setupFeaturePositions() {
				$.each(pluginData.featuresArray, function(i) {
					$(this).data('setPosition',i+1);
				});
				var oneBeforeStarting=getPreviousNum(options.startingFeature);
				pluginData.currentCenterNum=oneBeforeStarting;
				var $centerFeature=getContainer(oneBeforeStarting);
				$centerFeature.data('position',1);
				var $prevFeatures=$centerFeature.prevAll();
				$prevFeatures.each( function(i) {
					$(this).data('position',(pluginData.totalFeatureCount-i));
				});
				var $nextFeatures=$centerFeature.nextAll();
				$nextFeatures.each( function(i) {
					if($(this).data('setPosition')!=undefined) {
						$(this).data('position',(i+2));
					}
				});
				if(options.counterStyle==3) {
					$.each(pluginData.featuresArray, function() {
						var pos=getPreviousNum($(this).data('position'));
						var $numberTag=$("<span></span>");
						$numberTag.addClass("numberTag");
						$numberTag.html("("+pos+" of "+pluginData.totalFeatureCount+") ");
						$(this).find('div p').prepend($numberTag);
					});
				}
			}

			function setupBlips() {
				if(options.counterStyle==1||options.counterStyle==2) {
					var $list=$("<ul></ul>");
					$list.addClass("blipsContainer");
					for(var i=0;i<pluginData.totalFeatureCount;i++) {
						var counter;
						if(options.counterStyle==2)
							counter="";
						else
							counter=i+1;
						var $blip=$("<div>"+counter+"</div>");
						$blip.addClass("blip");
						$blip.css("cursor","pointer");
						$blip.attr("id","blip_"+(i+1));
						var $listEntry=$("<li></li>");
						$listEntry.append($blip);
						$listEntry.css("float","left");
						$listEntry.css("list-style-type","none");
						$list.append($listEntry);
					}
					$(pluginData.containerIDTag).append($list);
					$list.hide().show();
				}
			}

			function changeBlip(oldCenter,newCenter) {
				var $blipsContainer=pluginData.featuresContainer.find(".blipsContainer");
				var $oldCenter=$blipsContainer.find("#blip_"+oldCenter);
				var $newCenter=$blipsContainer.find("#blip_"+newCenter);
				$oldCenter.removeClass("blipSelected");
				$newCenter.addClass("blipSelected");
			}

			function autoPlay() {
				if(pluginData.timeoutVar!=null) {
					pluginData.timeoutVar=clearTimeout(pluginData.timeoutVar);
				}
				if(options.autoPlay!=0) {
					var autoTime=(Math.abs(options.autoPlay)<options.carouselSpeed)?options.carouselSpeed:Math.abs(options.autoPlay);
					pluginData.timeoutVar=setTimeout( function() {
						if(options.autoPlay>0)
							initiateMove(true,1);
						else if(options.autoPlay<0)
							initiateMove(false,1);
					},autoTime);
				}
			}

			function rotatePositions(direction) {
				$.each(pluginData.featuresArray, function() {
					var newPos;
					if(direction==false) {
						newPos=getNextNum($(this).data().position);
					} else {
						newPos=getPreviousNum($(this).data().position);
					}
					$(this).data('position',newPos);
				});
			}

			function animateFeature($feature,direction) {
				var new_width,new_height,new_top,new_left,new_zindex,new_padding,new_fade;
				var oldPosition=$feature.data('position');
				var newPosition;
				if(direction==true)
					newPosition=getPreviousNum(oldPosition);
				else
					newPosition=getNextNum(oldPosition);
				if(newPosition==1) {
					new_width=pluginData.largeFeatureWidth;
					new_height=pluginData.largeFeatureHeight;
					new_top=options.topPadding;
					new_zindex=$feature.css("z-index");
					new_left=(pluginData.containerWidth/2)-(pluginData.largeFeatureWidth/2)-(pluginData.borderWidth/2);
					new_fade=1.0;
				} else {
					new_width=pluginData.smallFeatureWidth;
					new_height=pluginData.smallFeatureHeight;
					new_top=options.smallFeatureOffset+options.topPadding;
					new_zindex=1;
					new_fade=0.4;
					if(newPosition==pluginData.totalFeatureCount) {
						new_left=options.sidePadding;
					} else if(newPosition==2) {
						new_left=pluginData.containerWidth-pluginData.smallFeatureWidth-options.sidePadding-pluginData.borderWidth;
					} else {
						new_left=(pluginData.containerWidth/2)-(pluginData.smallFeatureWidth/2)-(pluginData.borderWidth/2);
						new_fade=0;
					}
				}
				if(newPosition!=1) {
					$feature.find("div").animate({marginLeft:"-30px",marginTop:"30px",width:"160px"},500, 'linear');
					$feature.find("div p").animate({fontSize:"10px"},500);
					$feature.find("div a").animate({fontSize:"11px"},500);
				} else {
					$feature.find("div").animate({marginLeft:"0px",marginTop:"0px",width:"210px"},500, 'linear');
					$feature.find("div p").animate({fontSize:"11px"},500);
					$feature.find("div a").animate({fontSize:"14px"},500)
				}
				$feature.animate({width:new_width,height:new_height,top:new_top,left:new_left,opacity:new_fade},options.carouselSpeed,options.animationEasing, function() {
					if(newPosition==1) {
						$feature.find("div").fadeTo("fast",0.85);
					}
					pluginData.rotationsRemaining=pluginData.rotationsRemaining-1;
					$feature.css("z-index",new_zindex);
					if(options.counterStyle==1||options.counterStyle==2) {
						if(newPosition==1) {
							var newCenterItemNum=pluginData.featuresContainer.children("div").index($feature)+1;
							var oldCenterItemNum;
							if(direction==false)
								oldCenterItemNum=getNextNum(newCenterItemNum);
							else
								oldCenterItemNum=getPreviousNum(newCenterItemNum);
							changeBlip(oldCenterItemNum,newCenterItemNum);
						}
					}
					var divide=pluginData.rotationsRemaining/pluginData.itemsToAnimate;
					if(divide%1==0) {
						pluginData.currentlyMoving=false;
						rotatePositions(direction);
						if(pluginData.rotationsRemaining>0)
							move(direction);
					}
					autoPlay();
				}).find("img:first").animate({width:new_width,height:new_height},options.carouselSpeed,options.animationEasing).end();
			}

			function move(direction) {
				pluginData.currentlyMoving=true;
				var $newCenter,$newLeft,$newRight,$newHidden;
				if(direction==true) {
					$newCenter=getContainer(getNextNum(pluginData.currentCenterNum));
					$newLeft=getContainer(pluginData.currentCenterNum);
					$newRight=getContainer(getNextNum(getNextNum(pluginData.currentCenterNum)));
					$newHidden=getContainer(getPreviousNum(pluginData.currentCenterNum));
					pluginData.currentCenterNum=getNextNum(pluginData.currentCenterNum);
				} else {
					$newCenter=getContainer(getPreviousNum(pluginData.currentCenterNum));
					$newLeft=getContainer(getPreviousNum(getPreviousNum(pluginData.currentCenterNum)));
					$newRight=getContainer(pluginData.currentCenterNum);
					$newHidden=getContainer(getNextNum(pluginData.currentCenterNum));
					pluginData.currentCenterNum=getPreviousNum(pluginData.currentCenterNum);
				}
				if(direction) {
					$newLeft.css("z-index",3);
				} else {
					$newRight.css("z-index",3);
				}
				$newCenter.css("z-index",4);
				animateFeature($newLeft,direction);
				animateFeature($newCenter,direction);
				animateFeature($newRight,direction);
				if(pluginData.totalFeatureCount>3) {
					animateFeature($newHidden,direction);
				}
			}

			function initiateMove(direction,rotations) {
				if(pluginData.currentlyMoving==false) {
					var queue=rotations*pluginData.itemsToAnimate;
					pluginData.rotationsRemaining=queue;
					move(direction);
				}
			}

			function findShortestDistance(from,to) {
				var goingToLeft=1,goingToRight=1,tracker;
				tracker=from;
				while((tracker=getPreviousNum(tracker))!=to) {
					goingToLeft++;
				}
				tracker=from;
				while((tracker=getNextNum(tracker))!=to) {
					goingToRight++;
				}
				return(goingToLeft<goingToRight)?goingToLeft*-1:goingToRight;
			}

			$(".leftButton").click( function() {
				initiateMove(false,1);
			});
			$(".rightButton").click( function() {
				initiateMove(true,1);
			});
			pluginData.featuresContainer.children("div").click( function() {
				var position=$(this).data('position');
				if(position==2) {
					initiateMove(true,1);
				} else if(position==pluginData.totalFeatureCount) {
					initiateMove(false,1);
				}
			}).mouseover( function() {
				if(pluginData.currentlyMoving==false) {
					var position=$(this).data('position');
					if(position==2||position==pluginData.totalFeatureCount) {
						$(this).css("opacity",0.8);
					}
				}
			}).mouseout( function() {
				if(pluginData.currentlyMoving==false) {
					var position=$(this).data('position');
					if(position==2||position==pluginData.totalFeatureCount) {
						$(this).css("opacity",0.4);
					}
				}
			});
			$("a",pluginData.containerIDTag).live("click", function(event) {
				var $parents=$(this).parentsUntil(pluginData.containerIDTag);
				$parents.each( function() {
					var position=$(this).data('position');
					if(position!=undefined) {
						if(position!=1) {
							if(position==pluginData.totalFeatureCount) {
								initiateMove(false,1);
							} else if(position==2) {
								initiateMove(true,1);
							}
							event.preventDefault();
							return false;
						}
					}
				});
			});
			$(".blip").live("click", function() {
				var goTo=$(this).attr("id").substring(5);
				var whereIsIt=pluginData.featuresContainer.children("div").eq(goTo-1).data('position');
				var currentlyAt=pluginData.currentCenterNum;
				if(goTo!=currentlyAt) {
					var shortest=findShortestDistance(1,whereIsIt);
					if(shortest<0) {
						initiateMove(false,(shortest*-1));
					} else {
						initiateMove(true,shortest);
					}
				}
			});
		});
	};
	$.fn.featureCarousel.defaults={largeFeatureWidth:0,largeFeatureHeight:0,smallFeatureWidth:.5,smallFeatureHeight:.5,topPadding:20,sidePadding:30,smallFeatureOffset:50,startingFeature:1,carouselSpeed:1000,autoPlay:0,counterStyle:1,preload:true,displayCutoff:0,animationEasing:'swing'};
})(jQuery);

