// On DOM Load...
$(function(){
	$("#CarouselPreloader").load("/home/carousel.php?r="+Math.random(),function(){Carousel.onPreloadComplete();});
});



// CarouselOnPreloadComplete():void
function CarouselOnPreloadComplete() {
	this.attachData();
	this.attachEvents();
	this.setupAndStart();
	MainNavbarAttachEvents();
}



// CarouselReset():void
function CarouselReset() {
	location.href="/home/";
}



// Options...
var Carousel = {
	// properties...
	spinDuration: 200,
	normalInterval: 3300,
	rushingInterval: 250,
	timeoutReference: null,
	playbackMode: "normal",  // other possibility is "rushing"
	imgHeight: 200,
	imgWidth:  200,
	jAllImages: $(),
	offCenterFactors: [0.65,0.25,0.10],
	currentPositionIndex: 0,
	destinationPositionIndex: 0,

	
	// methods...
	modProcess:         CarouselModProcess,
	repaint:            CarouselRepaint,
	goForward:          CarouselGoForward,
	goBackward:         CarouselGoBackward,
	attachData:         CarouselAttachData,
	attachEvents:       CarouselAttachEvents,
	setupAndStart:      CarouselSetupAndStart,
	onPreloadComplete:  CarouselOnPreloadComplete,
	setNormalPlayback:  CarouselSetNormalPlayback,
	setRushingPlayback: CarouselSetRushingPlayback
}



// MainNavbarAttachEvents():void
function MainNavbarAttachEvents() {
	Carousel.jAllImages.each(function(theIndex){
		var jImg = $(this);
		var jLink = $("#btn" + jImg.data("Type") + jImg.data("ID"));
		jLink.hover(
			function(){
				Carousel.setRushingPlayback(theIndex);
			},
			function(){
				Carousel.setNormalPlayback();
			}
		);
	});
}



// CarouselSetNormalPlayback():void
function CarouselSetNormalPlayback() {
	clearTimeout(this.timeoutReference);
	this.playbackMode = "normal";
	this.timeoutReference = setTimeout("Carousel.repaint()",this.normalInterval);
}



// CarouselSetRushingPlayback(theDestination):void
function CarouselSetRushingPlayback(theDestination) {
	clearTimeout(this.timeoutReference);
	this.destinationPositionIndex = theDestination;
	this.playbackMode = "rushing";
	this.timeoutReference = setTimeout("Carousel.repaint()",this.rushingInterval);
}



// CarouselAttachData()
function CarouselAttachData() {
	$("#CarouselPreloader img").each(function(){
		var jImg = $(this);
		var imgFields = jImg.attr("alt").split(":");
		jImg.data("Type", imgFields[0]);
		jImg.data("Href", imgFields[1]);
		jImg.data("ID",   imgFields[2]);
		jImg.data("Name", imgFields[3]);
		jImg.attr("alt", jImg.attr("title"));
	});
}



// CarouselAttachEvents()
function CarouselAttachEvents() {
	$("#CarouselPreloader img").each(function(){
		$(this).click(function(){
			var jImg = $(this);
			if(jImg.hasClass("CenterImage")) {
				location.href = jImg.data("Href");
			}
		});
	});
}



// CarouselRepaint():void
function CarouselRepaint() {
	if($("#CarouselDisplay").children("img").length < (this.offCenterFactors.length * 2)) {
		CarouselReset();
	}
	
	// modProcess each index...
	this.currentPositionIndex     = this.modProcess(this.currentPositionIndex);
	this.destinationPositionIndex = this.modProcess(this.destinationPositionIndex);
	
	// ensure advancing behavior for normal playback
	if(this.playbackMode=="normal") {
		this.destinationPositionIndex = (this.currentPositionIndex + 1);
	}
	
	// shortcut to return if equal...
	if(this.currentPositionIndex == this.destinationPositionIndex) return;

	// determine which way around is the shortest...
	var shouldGoForward = true;
	if(this.currentPositionIndex > this.destinationPositionIndex) {
		var wraparoundDistance = (this.jAllImages.length - this.currentPositionIndex) + this.destinationPositionIndex;
		var normalDistance     = (this.currentPositionIndex - this.destinationPositionIndex);
		if(wraparoundDistance < normalDistance) {
			shouldGoForward = true; 
		} else {
			shouldGoForward = false;
		}
	} else { // if the destination is higher than the current...
		var wraparoundDistance = (this.jAllImages.length - this.destinationPositionIndex) + this.currentPositionIndex;
		var normalDistance     = (this.destinationPositionIndex - this.currentPositionIndex);
		if(wraparoundDistance < normalDistance) {
			shouldGoForward = false;
		} else {
			shouldGoForward = true;
		}
	}
	
	// dispatch advance
	if(shouldGoForward) {
		this.goForward();
	} else {
		this.goBackward();
	}
	
	// loop again for next repaint
	if(this.playbackMode=="normal") {
		clearTimeout(this.timeoutReference);
		this.timeoutReference = setTimeout("Carousel.repaint()",this.normalInterval);
	} else { // if we're "rushing" to arrive at a particular image tile
		clearTimeout(this.timeoutReference);
		this.timeoutReference = setTimeout("Carousel.repaint()",this.rushingInterval);
	}
}



// CarouselGoForward():void
function CarouselGoForward() {
	var jDisplay   = $("#CarouselDisplay");
	
	// append next image onto end of display...
	var nextImgNum = this.modProcess(this.currentPositionIndex + this.offCenterFactors.length + 1);
	var nextImg = this.jAllImages.eq(nextImgNum);
	nextImg.css({
		width: "0px",
		height: (this.imgHeight + "px"),
		opacity: 0.0
	});
	jDisplay.append(nextImg);
	
	// start animations to show rotation:
	this.currentPositionIndex++;
	
	// first, do the image that's going away (on the left)...
	var whichImg = 0;
	jDisplay.children("img").eq(whichImg).animate({
			width: "0px",
			height: (this.imgHeight + "px"),
			opacity: 0.0
		},
		this.spinDuration,
		function(){
			jDisplay.children("img:first").detach();
		}
	).removeClass("CenterImage");
	whichImg++;
	
	// next, do the images to the left of the new center image...
	for(var i=(this.offCenterFactors.length - 1); i >= 0; i--) {
		jDisplay.children("img").eq(whichImg).animate({
				width: (Math.round(this.imgWidth * this.offCenterFactors[i]) + "px"),
				height: (this.imgHeight + "px"),
				opacity: this.offCenterFactors[i]
			},this.spinDuration
		).removeClass("CenterImage");
		whichImg++;
	}
	
	// next, do the new center image, and give it (exclusively) the CenterImage class...
	jDisplay.children("img").eq(whichImg).animate({
			width: (this.imgWidth + "px"),
			height: (this.imgHeight + "px"),
			opacity: 1.0
		},this.spinDuration
	).addClass("CenterImage");
	whichImg++;
	
	// next, do the images to the right of the new center image...
	for(var i=0; i < this.offCenterFactors.length; i++) {
		jDisplay.children("img").eq(whichImg).animate({
				width: (Math.round(this.imgWidth * this.offCenterFactors[i]) + "px"),
				height: (this.imgHeight + "px"),
				opacity: this.offCenterFactors[i]
			},this.spinDuration
		).removeClass("CenterImage");
		whichImg++;
	}
}



// CarouselGoBackward():void
function CarouselGoBackward() {
	var jDisplay   = $("#CarouselDisplay");
	
	// append next image onto end of display...
	var prevImgNum = this.modProcess(this.currentPositionIndex - this.offCenterFactors.length - 1);
	var prevImg = this.jAllImages.eq(prevImgNum);
	prevImg.css({
		width: "0px",
		height: (this.imgHeight + "px"),
		opacity: 0.0
	}).removeClass("CenterImage");
	jDisplay.prepend(prevImg);
	
	// start animations to show rotation:
	this.currentPositionIndex--;

	// first, do the images to the left of the new center...
	var whichImg = 0;
	for(var i=(this.offCenterFactors.length - 1); i >= 0; i--) {
		jDisplay.children("img").eq(whichImg).animate({
				width: (Math.round(this.imgWidth * this.offCenterFactors[i]) + "px"),
				height: (this.imgHeight + "px"),
				opacity: this.offCenterFactors[i]
			},this.spinDuration
		).removeClass("CenterImage");
		whichImg++;
	}
	
	// next, do the new center image...
	jDisplay.children("img").eq(whichImg).animate({
			width: (this.imgWidth + "px"),
			height: (this.imgHeight + "px"),
			opacity: 1.0
		},this.spinDuration
	).addClass("CenterImage");
	whichImg++;
	
	// next, do the images to the right of the new center...
	for(var i=0; i < this.offCenterFactors.length; i++) {
		jDisplay.children("img").eq(whichImg).animate({
				width: (Math.round(this.imgWidth * this.offCenterFactors[i]) + "px"),
				height: (this.imgHeight + "px"),
				opacity: this.offCenterFactors[i]
			},this.spinDuration
		).removeClass("CenterImage");
		whichImg++;
	}
	
	// last, do the image that's going away (on the far right)...
	jDisplay.children("img").eq(whichImg).animate({
			width: "0px",
			height: (this.imgHeight + "px"),
			opacity: 0.0
		},
		this.spinDuration,
		function(){
			jDisplay.children("img:last").detach();
		}
	).removeClass("CenterImage");

}



// CarouselSetup()
function CarouselSetupAndStart() {
	var jDisplay   = $("#CarouselDisplay");
	var jPreloader = $("#CarouselPreloader");
	
	// pull images (with events still attached) into array
	this.jAllImages = jPreloader.children("img").detach();
	
	// place starting images into display area, slender and transparent
	var setToAppend   = new Array();
	var whichToAppend = this.currentPositionIndex - this.offCenterFactors.length;
	for(var i=0; i < (1+(this.offCenterFactors.length * 2)); i++) {
		// start off skinny and invisible
		this.jAllImages.eq(this.modProcess(whichToAppend)).css({
			width: "1px",
			height: (this.imgHeight + "px"),
			opacity: 0.0
		});
		// ensure the right image has the CenterImage class
		if(whichToAppend == this.currentPositionIndex) {
			this.jAllImages.eq(this.modProcess(whichToAppend)).addClass("CenterImage");
		} else {
			this.jAllImages.eq(this.modProcess(whichToAppend)).removeClass("CenterImage");
		}
		// insert into display
		jDisplay.append(this.jAllImages.eq(this.modProcess(whichToAppend)));
		whichToAppend++;
	}
	
	// enlarge and fade in the starting images to their proper starting state:
	// first the images to the left of center;
	var whichToEnlarge = 0;
	for(var i=(this.offCenterFactors.length - 1); i >= 0; i--) {
		jDisplay.children("img").eq(whichToEnlarge).animate({
				width: (Math.round(Carousel.imgWidth * this.offCenterFactors[i]) + "px"),
				height: (this.imgHeight + "px"),
				opacity: this.offCenterFactors[i]
			},this.spinDuration
		);
		whichToEnlarge++;
	}
	
	// then the image in the center;
	jDisplay.children("img").eq(whichToEnlarge).animate({
			width: (this.imgWidth + "px"),
			height: (this.imgHeight + "px"),
			opacity: 1.0
		},this.spinDuration
	);
	whichToEnlarge++;
	
	// then the images to the right of center;
	for(var i=0; i < this.offCenterFactors.length; i++) {
		jDisplay.children("img").eq(whichToEnlarge).animate({
				width: (Math.round(this.imgWidth * this.offCenterFactors[i]) + "px"),
				height: (this.imgHeight + "px"),
				opacity: this.offCenterFactors[i]
			},this.spinDuration
		);
		whichToEnlarge++;
	}

	// start up the repaint() cycle
	this.repaint();
}



// CarouselInstance.CarouselModProcess(int):int
function CarouselModProcess(num) {
	if(num < 0) {
		var howMany = -1 * Math.floor(num / this.jAllImages.length);
		num += (howMany * this.jAllImages.length);
	}
	num = (num % this.jAllImages.length);
	return num;
}
