// ---------- List Carousel ----------

TWODEE.Classes.ListCarousel = new TWODEE.Class();
TWODEE.Classes.ListCarousel.selectors = {
	"panelsContainerSelector": ".carousel-content",
	"panelsScrollSelector": ".gallery-thumbs",	
	"panelsSelector": "li",
	"nextButtons": ".carousel-button.carousel-next",
	"previousButtons": ".carousel-button.carousel-previous",
	"firstButton": ".carousel-button.carousel-first"
};
TWODEE.Classes.ListCarousel.classFunction = function(configObject) {
	var classFunctionPub = {};
	var thisClass = TWODEE.Classes.ListCarousel;
	
	var selectors = thisClass.selectors;
	var targetJq; // Main HTML element jQuery wrapped 
	var currentPanelIndex = configObject.currentPanelIndex;
	var newPanelIndex = currentPanelIndex;
	var panelArray = [];
	var pageLength = configObject.pageLength;
	var panelsJq;
	var panelsContainerJq;
	var panelsScrollJq;	
	
	var firstButton;
	var nextButtonArray = [];
	var previousButtonArray = [];	
	
	var currentRequest = null;
	var currentRequestCount;
	var currentRequestOffset;	
	var currentRequestSuccessFunction;		
	
	var isAnimating = false;
	
	var getNumPanelsVisible = function() {
		panelsScrollJq.find(selectors.panelsSelector+":visible");
		return panelsScrollJq.length;
	}
	
	var Panel = function(elem, index) {
		var panelPub = new Object();

		panelPub.panelJq = jQuery(elem);
		panelPub.imageIndex = panelPub.panelJq.find(".number").text();
		
		var nearestActivePanelIndex = function() {
			// Find nearest panel in the DOM
			for(var i = 1; i <= panelArray.length * 2; i++) {
				if ( (i/2) == Math.round(i/2) ) {
					// Even
					var j = index + (i/2);
				} else {
					// Odd
					var j = index - Math.round(i/2)
				}
			
				if (panelArray[j]) {
					if (panelArray[j].isInDOM()) {
						return j;
					}
				}
			}
			return null;
		}
		
		panelPub.isInDOM = function() {
			return(panelPub.panelJq.parent()[0] == panelsScrollJq[0]);
		}
		
		panelPub.forceHide = function(onoff) {
			if (onoff == false) {
				panelPub.panelJq.removeClass("hide");
			} else {
				panelPub.panelJq.removeClass("show");
				panelPub.panelJq.addClass("hide");
			}
		}
		panelPub.forceShow = function(onoff) {
			if (onoff == false) {
				panelPub.panelJq.removeClass("show");
			} else {
				panelPub.panelJq.removeClass("hide");
				panelPub.panelJq.addClass("show");
			}
		}
		
		panelPub.setThumbCountClass = function(thumbCount) {
			var classString = panelPub.panelJq.attr("class");
			var regex = /thumb-(\d+)/g;
			var match;    
			while (match = regex.exec(classString)) {
			    panelPub.panelJq.removeClass(match[0]);
			}

			panelPub.panelJq.addClass("thumb-"+thumbCount);			
		}
		
		panelPub.insert = function() {
			if (!panelPub.isInDOM()) {
				var nearestIndex = nearestActivePanelIndex();

				if (nearestIndex == null) {
					panelsScrollJq.append(panelPub.panelJq);
				} else {
					if (index > nearestIndex) {
						panelPub.panelJq.insertAfter(panelArray[nearestIndex].panelJq);
					} else {
						panelPub.panelJq.insertBefore(panelArray[nearestIndex].panelJq);					
					}
				}				
			}
		}
		panelPub.remove = function() {
			panelPub.panelJq.remove();
		}
		
		return panelPub;
	}
	
	// PRE-INIT	
	
	var enableDisableButtons = function(panelIndex) {
		var panelIndex = (typeof(panelIndex) == "number") ? panelIndex : currentPanelIndex;

		jQuery.each(nextButtonArray, function(){
			var pageBy = this.pageBy;			
			var buttonPanelIndex = panelIndex + pageBy;
			var buttonLastPanelInView = buttonPanelIndex + (pageBy-1);
			var lastPanelInView = panelIndex + (pageBy-1);

			if (lastPanelInView >= configObject.totalPanels-1) {
				this.controlButton.disable();				
			} else {
				if (buttonLastPanelInView > configObject.totalPanels-1) {
					this.controlButton.setActionFunction(function(){
						showPanel((configObject.totalPanels-1) - (pageBy-1));
					});
				} else {					
					this.controlButton.setActionFunction(function(){
						pagePanelsBy(pageBy);
					});
				}
				this.controlButton.enable();				
			}
		});

		jQuery.each(previousButtonArray, function(){
			var pageBy = this.pageBy;
			var buttonPanelIndex = panelIndex + pageBy;
			
			if (panelIndex == 0) {
				this.controlButton.disable();				
			} else {
				if (buttonPanelIndex < 0) {
					this.controlButton.setActionFunction(function(){
						showPanel(0);
					});
				} else {
					this.controlButton.setActionFunction(function(){
						pagePanelsBy(pageBy);
					});
				}
				this.controlButton.enable();				
			}
		});
		
		if (panelIndex == 0) {
			firstButton.disable();			
		} else {
			firstButton.enable();			
		}
	}
	
	var loadPanels = function(count, offset, successFunction) {
		var unloadedPanels = [];
		
		for (var i = offset; i < count+offset; i++ ) {
			if (typeof(panelArray[i]) != "object") {
				unloadedPanels.push(i)
			}
		}
		
		if (unloadedPanels.length == 0) {
			if (typeof(successFunction) == "function") {
				successFunction();					
			}
		} else {
			var newRequestIsNecessary = true;
			
			// See if any current request going on contains these things
			if (currentRequest !== null) {
				if (offset >= currentRequestOffset) {
					if (offset+count <= currentRequestOffset+currentRequestCount) {
						var newRequestIsNecessary = false;						
					}
				}
			}
			
			if (newRequestIsNecessary) {				
				if (currentRequest !== null) {
					currentRequest.abort();					
				}
				
				currentRequestOffset = offset;
				currentRequestCount = count;	
				if (typeof(successFunction) == "function") {
					// Only update if there's a new function
					currentRequestSuccessFunction = successFunction;
				}
				
				currentRequest = jQuery.get(configObject.ajaxUrl, {
					"count": count,
					"offset": offset
				}, function(data, textStatus, jqXHR) {
					var tempContainer = jQuery("<ul></ul>");
					tempContainer.html(data);
					var tempPanelsJq = tempContainer.find(selectors.panelsSelector);

					tempPanelsJq.each(function(i){
						if (panelArray[offset + i] == undefined) {
							panelArray[offset + i] = new Panel(this, offset + i);
						}
					});

					currentRequest = null;

					if (typeof(currentRequestSuccessFunction) == "function") {
						currentRequestSuccessFunction();	
						currentRequestSuccessFunction = null;
					}

				}, "html");					
				
			} else {
				if (typeof(successFunction) == "function") {
					currentRequest.success(successFunction);
				}
			}
			
		}
	}
	
	var preloadPanels = function(panelIndex) {
		var count = pageLength * 3;
		var offset = panelIndex-pageLength;
		
		if (offset < 0) {
			offset = 0;
		}
				
		loadPanels(count, offset);
	}
	
	var showPanel = function(panelIndex) {
		enableDisableButtons(panelIndex);
		
		// Load in the thumbs we need between what's currently in view, and what's going to be shown

		var lastCurrentPanelIndex = currentPanelIndex + (pageLength-1);
		var count = 0;
		var offset = 0;
		
		if (panelIndex > lastCurrentPanelIndex) {
			offset = lastCurrentPanelIndex + 1;
			count = panelIndex - lastCurrentPanelIndex + (pageLength-1);
		} else if (panelIndex < currentPanelIndex) {
			offset = panelIndex;
			count = currentPanelIndex - panelIndex;
		} else if (panelIndex !== currentPanelIndex) {
			offset = lastCurrentPanelIndex + 1;
			count = panelIndex - offset + pageLength;
		}
		
		newPanelIndex = panelIndex;

		if (count != 0) {
			loadPanels(count, offset, function(){
				panelsScrollJq.stop();
				
				var oldPosition = parseFloat(panelsScrollJq.css("margin-left"));
				var oldPanelPosition = panelArray[currentPanelIndex].panelJq.position().left;
				
				// Insert the new panels
				for (var i = offset; i < count+offset; i++ ) {
					if (typeof(panelArray[i]) == "object") {
						panelArray[i].insert();											
					}
				}

				// Show all panels we need to scroll between
				var scrollStartIndex = Math.min(offset, currentPanelIndex);
				var scrollEndIndex = Math.max(offset+count, currentPanelIndex+(pageLength-1))
				for (var i = scrollStartIndex; i < scrollEndIndex; i++) {
					if (typeof(panelArray[i]) == "object") {
						panelArray[i].forceShow();
					}					
				}
				
				var newPanelPosition = panelArray[currentPanelIndex].panelJq.position().left;
				
				panelsScrollJq.css("margin-left", getPercentageOffset(oldPosition + (oldPanelPosition - newPanelPosition))+"%")
				doShow();				
			});
		} else {
			doShow();
		}
		
		function getPercentageOffset(pixels) {
			if (pixels == 0) {
				return 0;
			} else {
				return (pixels/panelsScrollJq.innerWidth())*100;				
			}
		}
		
		function doShow() {			
			var scrollCarouselTo = -getPercentageOffset(panelArray[panelIndex].panelJq.position().left)+"%";
			
			isAnimating = true;
			panelsScrollJq.stop().animate({
				"margin-left": scrollCarouselTo
			}, {
				duration: 700,
				easing: "swing",
				complete: function() {
					var thumbCount = 1;
					jQuery.each(panelArray, function(i) {
						if (i < panelIndex || i > (panelIndex + (pageLength-1))) {
							if (typeof(panelArray[i]) == "object") {
								// Hide unwanted panels
								panelArray[i].forceHide();								
							}
						} else {
							if (typeof(panelArray[i]) == "object") {
								// Let the CSS dictate which to show
								panelArray[i].forceShow(false);	
								
								// Reset the thumb- classes
								panelArray[i].setThumbCountClass(thumbCount);
								thumbCount++;	
							}
						}
					});
					panelsScrollJq.css("margin-left", 0)					
					
					currentPanelIndex = panelIndex;					
					isAnimating = false;
					
					preloadPanels(panelIndex);					
				}
			});					
		}
	}	
	var pagePanelsBy = function(pageBy) {
		showPanel(newPanelIndex+pageBy);
	}
	
	
	var convertToControlButton = function(elem, actionFunction) {
		var elemJq = jQuery(elem);
		var controlButton = new TWODEE.Utilities.ControlButton(elemJq.text(), elemJq.attr("class"), actionFunction);
		elemJq.replaceWith(controlButton.elemJq);
		return controlButton;
	}
	
	
	// INIT	
	classFunctionPub.init = function() {
		targetJq = jQuery(configObject.uniqueTargetNodeOrSelector)
		panelsContainerJq = targetJq.find(selectors.panelsContainerSelector);
		panelsScrollJq = targetJq.find(selectors.panelsScrollSelector);
		panelsJq = panelsScrollJq.find(selectors.panelsSelector);	

		var panelsScrollWrapJq = jQuery("<div class='gallery-scroll-wrap'></div>");
		panelsScrollWrapJq.insertAfter(panelsScrollJq);
		panelsScrollWrapJq.append(panelsScrollJq);
		
		nextButtonsJq = targetJq.find(selectors.nextButtons);
		previousButtonsJq = targetJq.find(selectors.previousButtons);
		
		nextButtonsJq.each(function() {
			var elemJq = jQuery(this);
			var classString = elemJq.attr("class");
			var regex = /(\d+)thumbs/;
			var pageBy = parseInt(regex.exec(classString)[1]);
			var controlButton = convertToControlButton(this, function(){
				pagePanelsBy(pageBy)
			});
			nextButtonArray.push({
				"pageBy": pageBy,
				"controlButton": controlButton
			});
			controlButton.enable();
		});
		previousButtonsJq.each(function() {
			var elemJq = jQuery(this);
			var classString = elemJq.attr("class");
			var regex = /(\d+)thumbs/;
			var pageBy = parseInt(-regex.exec(classString)[1]);
			var controlButton = convertToControlButton(this, function(){
				pagePanelsBy(pageBy)
			});
			previousButtonArray.push({
				"pageBy": pageBy,
				"controlButton": controlButton
			});
			controlButton.enable();			
		});
		
		firstButtonJq = targetJq.find(selectors.firstButton);
		firstButton = convertToControlButton(firstButtonJq[0], function(){
			showPanel(0);
		});
		
		
		panelsJq.each(function(i){
			panelArray[currentPanelIndex + i] = new Panel(this, currentPanelIndex + i);
		});
		
		enableDisableButtons();
		
		preloadPanels(currentPanelIndex);
		
		targetJq.addClass('js-active');		
	}


	classFunctionPub.showPanel = showPanel;
	
	return classFunctionPub;
}
