// http://www.adoromedia.com/projects/carousel/
//
// with minor edits for KOHLER AT HOME
if(typeof Adoro !== "object") Adoro = {};
Adoro.Carousel = function(container, options) {
	var state = { 
		currentSlideIndex: 0, // starts from 0 as in 0, 1, 2, 3 etc
		animating: false
	};
	var config = {
		automaticDelay: 0,
		automatic: false,
		automaticDirectionBackwards: false,
		scrollCount: 3,
		clipType: "div",
		clipClass: "clip",
		vertical: false,
		offsetReveal: 0,
		isCircular: false,
		animate: true,
		animateEasing: "linear",
		animateSpeed: 300,
		
		forwardButton: true,
		forwardButtonHTML: "<span>Forward</span>",
		forwardButtonDisabledHTML: "<span>Forward disabled</span>",
		forwardButtonClass: "forward",
		forwardButtonDisabledClass: "forwardDisabled",
		forwardButtonAppendTo: container,
		
		backButton: true,
		backButtonHTML: "<span>Back</span>",
		backButtonDisabledHTML: "<span>Back disabled</span>",
		backButtonClass: "back",
		backButtonDisabledClass: "backDisabled",
		backButtonAppendTo: container,
		
		startButton: true,
		startButtonHTML: "<span>Start</span>",
		startButtonDisabledHTML: "<span>Start disabled</span>",
		startButtonClass: "start",
		startButtonDisabledClass: "startDisabled",
		startButtonAppendTo: container,
		
		stopButton: true,
		stopButtonHTML: "<span>Stop</span>",
		stopButtonClass: "stop",
		stopButtonDisabledClass: "stopDisabled",
		stopButtonAppendTo: container,
		
		indicators: true,
		indicatorsContainerClass: "indicatorsContainer",
		indicatorsContainerAppendTo: container,
		indicatorButtonHTML: "<span>Indicator</span>",
		indicatorButtonSelectedHTML: "<span>Indicator selected</span>",
		indicatorButtonClass: "indicator",
		indicatorButtonSelectedClass: "indicatorSelected"
	};
	
	if(typeof options === "object") {
		config.automaticDelay = typeof options.automaticDelay === "number" ? options.automaticDelay : config.automaticDelay;
		config.automatic = typeof options.automatic === "boolean" ? options.automatic : config.automatic;
		config.automaticDirectionBackwards = typeof options.automaticDirectionBackwards === "boolean" ? options.automaticDirectionBackwards : config.automaticDirectionBackwards;
		config.scrollCount = typeof options.scrollCount === "number" ? options.scrollCount : config.scrollCount;
		config.clipType = typeof options.clipType === "string" ? options.clipType : config.clipType;
		config.clipClass = typeof options.clipClass === "string" ? options.clipClass : config.clipClass;
		config.vertical = typeof options.vertical === "boolean" ? options.vertical : config.vertical;
		config.offsetReveal = typeof options.offsetReveal === "number" ? options.offsetReveal : config.offsetReveal;
		config.isCircular = typeof options.isCircular === "boolean" ? options.isCircular : config.isCircular;
		config.animate = typeof options.animate === "boolean" ? options.animate : config.animate;
		config.animateEasing = typeof options.animateEasing === "string" ? options.animateEasing : config.animateEasing;
		config.animateSpeed = typeof options.animateSpeed === "number" ? options.animateSpeed : config.animateSpeed;
		
		config.forwardButton = typeof options.forwardButton === "boolean" ? options.forwardButton : config.forwardButton;
		config.forwardButtonHTML = typeof options.forwardButtonHTML === "string" ? options.forwardButtonHTML : config.forwardButtonHTML;
		config.forwardButtonDisabledHTML = typeof options.forwardButtonDisabledHTML === "string" ? options.forwardButtonDisabledHTML : config.forwardButtonDisabledHTML;
		config.forwardButtonClass = typeof options.forwardButtonClass === "string" ? options.forwardButtonClass : config.forwardButtonClass;
		config.forwardButtonDisabledClass = typeof options.forwardButtonDisabledClass === "string" ? options.forwardButtonDisabledClass : config.forwardButtonDisabledClass;
		config.forwardButtonAppendTo = options.forwardButtonAppendTo || config.forwardButtonAppendTo;
		
		config.backButton = typeof options.backButton === "boolean" ? options.backButton : config.backButton;
		config.backButtonHTML = typeof options.backButtonHTML === "string" ? options.backButtonHTML : config.backButtonHTML;
		config.backButtonDisabledHTML = typeof options.backButtonDisabledHTML === "string" ? options.backButtonDisabledHTML : config.backButtonDisabledHTML;
		config.backButtonClass = typeof options.backButtonClass === "string" ? options.backButtonClass : config.backButtonClass;
		config.backButtonDisabledClass = typeof options.backButtonDisabledClass === "string" ? options.backButtonDisabledClass : config.backButtonDisabledClass;
		config.backButtonAppendTo = options.backButtonAppendTo || config.backButtonAppendTo;
		
		config.startButton = typeof options.startButton === "boolean" ? options.startButton : config.startButton;
		config.startButtonHTML = typeof options.startButtonHTML === "string" ? options.startButtonHTML : config.startButtonHTML;
		config.startButtonDisabledHTML = typeof options.startButtonDisabledHTML === "string" ? options.startButtonDisabledHTML : config.startButtonDisabledHTML;
		config.startButtonClass = typeof options.startButtonClass === "string" ? options.startButtonClass : config.startButtonClass;
		config.startButtonDisabledClass = typeof options.startButtonDisabledClass === "string" ? options.startButtonDisabledClass : config.startButtonDisabledClass;
		config.startButtonAppendTo = options.startButtonAppendTo || config.startButtonAppendTo;
		
		config.stopButton = typeof options.stopButton === "boolean" ? options.stopButton : config.stopButton;
		config.stopButtonHTML = typeof options.stopButtonHTML === "string" ? options.stopButtonHTML : config.stopButtonHTML;
		config.stopButtonDisabledHTML = typeof options.stopButtonDisabledHTML === "string" ? options.stopButtonDisabledHTML : config.stopButtonDisabledHTML;
		config.stopButtonClass = typeof options.stopButtonClass === "string" ? options.stopButtonClass : config.stopButtonClass;
		config.stopButtonDisabledClass = typeof options.stopButtonDisabledClass === "string" ? options.stopButtonDisabledClass : config.stopButtonDisabledClass;
		config.stopButtonAppendTo = options.stopButtonAppendTo || config.stopButtonAppendTo;
		
		config.indicators = typeof options.indicators === "boolean" ? options.indicators : config.indicators;
		config.indicatorsContainerClass = typeof options.indicators === "string" ? options.indicatorsContainerClass : config.indicatorsContainerClass;
		config.indicatorsContainerAppendTo =  options.indicatorsContainerAppendTo || config.indicatorsContainerAppendTo;
		config.indicatorButtonHTML = typeof options.indicatorButtonHTML === "string" ? options.indicatorButtonHTML : config.indicatorButtonHTML;
		config.indicatorButtonSelectedHTML = typeof options.indicatorButtonSelectedHTML === "string" ? options.indicatorButtonSelectedHTML : config.indicatorButtonSelectedHTML;
		config.indicatorButtonClass = typeof options.indicatorButtonClass === "string" ? options.indicatorButtonClass : config.indicatorButtonClass;
		config.indicatorButtonSelectedClass = typeof options.indicatorButtonSelectedClass === "string" ? options.indicatorButtonSelectedClass : config.indicatorButtonSelectedClass;
	}
	
	var container = container || null;
	var clip = $(container).find(config.clipType+"."+config.clipClass)[0] || null;
	var ul = $(clip).find("ul")[0] || null;
	
	if(!ul) return;
	
	setULStyle();
	
	function setULStyle() {
		if(config.vertical) {
			$(ul).find("li").css({"display": "block","float": "none"});
			$(ul).css({
				"height": getSlidesDimensions(getSlides()).height + "px",
				"top": config.offsetReveal + "px",
				"position": "relative"
			});
		}
		else {
			$(ul).find("li").css({"display": "inline","float": "left"});
			$(ul).css({
				"width": getSlidesDimensions(getSlides()).width + "px",
				"left": config.offsetReveal + "px",
				"position": "relative"
			});
		}
	}
	
	setClipStyle();
	
	function setClipStyle() {
		$(clip).css({"overflow": "hidden", "position":"relative"});
	}
	
	function move(move) {
		if(state.animating || move === 0) return;
		if(move < 0) {
			// adjust, but only when not indicators are showing and isCircular
			if(config.indicators && config.isCircular && getState("currentSlideIndex") + move < 0) {
				var newCurrentSlideIndex = getSlides().length + move + getState("currentSlideIndex");
				var remainder = newCurrentSlideIndex % config.scrollCount;
				if(remainder !== 0) {
					move = move + (config.scrollCount - remainder);
				}
			}
			
			// if not circular and will be moving past 0 then return
			if(!getOption("isCircular") && (getState("currentSlideIndex") + move < 0)) return;
			
			move = move * -1;
			config.animate ? moveBackwardsAnimate(move) : moveBackwards(move);
		}
		else {
			// adjust
			if(config.indicators && config.isCircular && getState("currentSlideIndex") + move > getSlides().length-1) {
				var newCurrentSlideIndex = getState("currentSlideIndex") - getSlides().length + move;
				var remainder = newCurrentSlideIndex % config.scrollCount;
				if (remainder !== 0) {
					move = move - remainder;
				}
			}
			// if not circular and will be moving past the end then return
			if(!getOption("isCircular") && (getState("currentSlideIndex") + move > getSlides().length-1)) return;
			config.animate ? moveForwardsAnimate(move) : moveForwards(move);
		}
	}
	
	function moveBackwards(move) {
		if(config.automatic) play();
	}
	
	function moveForwards(move) {
		if(config.automatic) play();
	}
	
	function moveBackwardsAnimate(move) {
		var allSlides = getSlides();
		var slidesFrom = allSlides.length-move;
		var slidesTo = allSlides.length;
		var slides = getSlides(slidesFrom, slidesTo);
		$(ul).prepend(slides);
		$(ul).css(config.vertical ? {"top": -getSlidesDimensions(slides).height } : { "left": -getSlidesDimensions(slides).width });
		setState("animating", true);
		$(ul).animate(config.vertical ? {"top": config.offsetReveal+"px"} : {"left": config.offsetReveal+"px"},{"duration": config.animateSpeed, "easing": config.animateEasing, "complete": function(){
			setState("animating", false);
			if(getState("currentSlideIndex") - move < 0) {
				setState("currentSlideIndex", allSlides.length - move + getState("currentSlideIndex"))
			}
			else {
				setState("currentSlideIndex", getState("currentSlideIndex") - move);
			}
			setButtonStates();
			if(config.automatic) play();
		}});
	}
	
	function moveForwardsAnimate(move) {
		var allSlides = getSlides();
		var slidesFrom = 0;
		var slidesTo = move;
		var slides = getSlides(slidesFrom, slidesTo);
		setState("animating", true);
		$(ul).animate(config.vertical ? {"top": -getSlidesDimensions(slides).height+config.offsetReveal+"px"} : {"left": -getSlidesDimensions(slides).width+config.offsetReveal+"px"}, {"duration": config.animateSpeed,"easing": config.animateEasing,"complete": function(){
			$(ul).append(slides);
			$(ul).css(config.vertical ? "top":"left", config.offsetReveal+"px");
			setState("animating", false);
			if(getState("currentSlideIndex") + move > allSlides.length-1) {
				setState("currentSlideIndex", getState("currentSlideIndex") - allSlides.length + move);
			}
			else {
				setState("currentSlideIndex", getState("currentSlideIndex") + move);
			}
			setButtonStates();
			if(config.automatic) play();
		}});
	}
	
	function setButtonStates() {
		if(config.indicators) indicators.setSelected();
		if(config.backButton) backButton.setState();
		if(config.forwardButton) forwardButton.setState();
	}
	
	function getSlides(from, to) {
		var slides = [];
		var allSlides = $(ul).find("li");
		var slide = null;
		for(var i = allSlides.length-1; i>=0; i--) {
			slide = allSlides[i];			
			if(	(typeof from === "number" && i < from) ||
				(typeof to === "number" && i>to-1) ||
				(slide.parentNode !== ul) ) continue;
			slides.push(slide);
		}
		slides = slides.reverse();
		return slides;
	}
	
	function getSlidesDimensions(slides) {
		var dimensions = {width:0, height: 0};
		var slide;
		for(var i = slides.length-1; i>=0; i--) {
			slide = slides[i];
			if (slide.parentNode !== ul) continue;
			dimensions.height = dimensions.height + $(slide).outerHeight({margin: true});
			dimensions.width = dimensions.width + $(slide).outerWidth({margin: true});
		}
		return dimensions;
	}
	
	this.setOption = setOption;
	function setOption(key, value) {
		config[key] = value;
	}
	
	this.getOption = getOption;
	function getOption(key) {
		return config[key];
	}
	
	this.setState = setState;
	function setState(key, value) {
		state[key] = value;
	}
	
	this.getState = getState;
	function getState(key) {
		return state[key];
	}
	
	if (config.indicators) {
		var indicators = new (function(){
			var indicators = [];
			
			var slides = getSlides(),
				indicator,
				indicatorsContainer = $('<div></div>')[0];
				
			indicatorsContainer.className = config.indicatorsContainerClass;
			config.indicatorsContainerAppendTo.appendChild(indicatorsContainer);
			for(var i = 0; i<slides.length; i++) {
				if(i % config.scrollCount > 0) continue;
				indicator = new Indicator(i);
				indicators.push(indicator);
				indicatorsContainer.appendChild(indicator.el);
			}
			setSelected();
			
			this.setSelected = setSelected;
			function setSelected() {
				for(var i = 0; i < indicators.length; i++) {
					if(indicators[i].value === getState("currentSlideIndex")) {
						indicators[i].setSelected();
					}
					else {
						indicators[i].setUnselected();
					}
				}
			}
			
			function Indicator(value) {
				var el = $('<a href="#"></a>')[0];
				this.el = el;
				el.innerHTML = config.indicatorButtonHTML;
				el.className = config.indicatorButtonClass;
				$(el).bind("click", fire);
				this.value = value;
				function fire(){
					move(value - state.currentSlideIndex);
					return false;
				}
				
				this.setSelected = setSelected;
				function setSelected() {
					$(el).addClass(config.indicatorButtonSelectedClass);
					el.innerHTML = config.indicatorButtonSelectedHTML;
				}
				
				this.setUnselected = setUnselected;
				function setUnselected() {
					$(el).removeClass(config.indicatorButtonSelectedClass);
					el.innerHTML = config.indicatorButtonHTML;
				}
			}
		});
	}

	if (config.backButton) {
		var backButton = new (function(){
			var el = $('<a href="#"></a>')[0];
			el.className = config.backButtonClass;
			el.innerHTML = config.backButtonHTML;
			config.backButtonAppendTo.appendChild(el);
			$(el).bind("click", fire);
			function fire(){
				move(-config.scrollCount);
				return false;
			}
			
			this.enable = enable;
			function enable(){
				$(el).removeClass(config.backButtonDisabledClass);
                $(el).parent().removeClass(config.backButtonDisabledClass);         // KOHLER AT HOME
				el.innerHTML = config.backButtonHTML;
			}
			
			this.disable = disable;
			function disable(){
				$(el).addClass(config.backButtonDisabledClass);
                $(el).parent().addClass(config.backButtonDisabledClass);            // KOHLER AT HOME
				el.innerHTML = config.backButtonDisabledHTML;
			}
			
			this.setState = setState;
			function setState() {
				if (!getOption("isCircular") && (getState("currentSlideIndex") - config.scrollCount < 0)) {
					disable();
				}
				else {
					enable();
				}
			}
			
		});
	}
	
	if (config.forwardButton) {
		var forwardButton = new (function(){
			var el = $('<a href="#"></a>')[0];
			el.className = config.forwardButtonClass;
			el.innerHTML = config.forwardButtonHTML;
			config.forwardButtonAppendTo.appendChild(el);
			$(el).bind("click", fire);
			function fire(){
				move(config.scrollCount);
				return false;
			}
			
			this.enable = enable;
			function enable(){
				$(el).removeClass(config.forwardButtonDisabledClass);
                $(el).parent().removeClass(config.forwardButtonDisabledClass);      // KOHLER AT HOME
				el.innerHTML = config.forwardButtonHTML;
			}
			
			this.disable = disable;
			function disable(){
				$(el).addClass(config.forwardButtonDisabledClass);
                $(el).parent().addClass(config.forwardButtonDisabledClass);         // KOHLER AT HOME
				el.innerHTML = config.forwardButtonDisabledHTML;
			}
			
			this.setState = setState;
			function setState() {
				if(!getOption("isCircular") && (getState("currentSlideIndex") + config.scrollCount > getSlides().length-1)) {
					disable();
				}
				else {
					enable();
				}
			}
			
		});
	}
	
	if (config.startButton) {
		var startButton = new (function(){
			var el = $('<a href="#"></a>')[0];
			el.className = config.startButtonClass;
			el.innerHTML = config.startButtonHTML;
			config.startButtonAppendTo.appendChild(el);
			$(el).bind("click", fire);
			function fire(){
				play();
				return false;
			}
			
			this.enable = enable;
			function enable(){
				$(el).removeClass(config.startButtonDisabledClass);
			}
			
			this.disable = disable;
			function disable(){
				$(el).addClass(config.startButtonDisabledClass);
			}
		});
	}
	
	if (config.stopButton) {
		var stopButton = new (function(){
			var el = $('<a href="#"></a>')[0];
			el.className = config.stopButtonClass;
			el.innerHTML = config.stopButtonHTML;
			config.stopButtonAppendTo.appendChild(el);
			$(el).bind("click", fire);
			function fire(){
				stop();
				return false;
			}
			this.enable = enable;
			function enable(){
				$(el).removeClass(config.stopButtonDisabledClass);
			}
			this.disable = disable;
			function disable(){
				$(el).addClass(config.stopButtonDisabledClass);
			}
		});
	}
	
	var timer = null;
	function play() {
		setOption("automatic", true);
		timer = window.setTimeout(function(){
			move(config.automaticDirectionBackwards ? -config.scrollCount : config.scrollCount);
		}, config.automaticDelay);
		if(config.startButton) startButton.disable();
		if(config.stopButton) stopButton.enable();
	}
	
	function stop() {
		setOption("automatic", false);
		clearTimeout(timer);
		if(config.startButton) startButton.enable();
		if(config.stopButton) stopButton.disable();
	}
	
	if(config.automatic) play();
	setButtonStates();	
}

