var Kleenex = (function() {
	
	// Slideshow Settings
	var _duration = 5000; // 5 seconds - original: 13 seconds
	var _speed = 3000; // 3 seconds
	
	// DOM References
	var _mainFrame = $('#Kleenex'),
		_loading = $('#Loading'),
		_spriteBackground = $('#SpriteBackground').css({'width': 0, 'height': 0}), // Effectively hides it so that we don't get any overflow issues
		_kleenexBox = $('#KleenexBox'),
		_infoBox = $('#InfoBox'),
		_callToAction = $('#CallToAction'),
		_learnButton = $('#LearnButton'),
		_textFrames = $('#TextFrames'),
		_mainLink = $('#MainLink');

	/* Init ******************************************************************************************/		
	var _init = function(url) {	
		$.ajax ({
			type: "GET",
			url: url,
			dataType: "json",
			success: function(data) {
				_buildBackgrounds(data, function(){ // Wait for images to be loaded, see next line
					// sprites have to be shown in order to tilt, but need to be hidden 
					// here so that they don't all play at once in the slideshow
					_spriteBackground.children('li').hide();
					_buildTextFrames(data);
					_buildInfoBox(data);
					_buildKleenexBoxes(data, function() { // Wait for images to be loaded
						_hideLoading();
						_showElements();
						_gleamStart();
						_startSlideshow(data);
					});
				});
			},
			error: function(req, status, err) {
				// Silence is golden
			}
		});
	};
	
	/* Builds ******************************************************************************************/
	var _imageSetsLoaded = 0;
	var _buildBackgrounds = function(data, callback) { // Uses imagesLoaded, so callback needs to be passed
		var bgs = data.Backgrounds,
			length = bgs.length - 1, // Zero based, used to track if all images are loaded
			templateLi = _spriteBackground.find('li').detach();
			
		$.each(bgs, function(idx, value) {
			var li = templateLi.clone(),
				sprites = li.find('div'),
				img = $('<img />'); // Create Image DO< Element
			
			// Adds data id
			li.data('id', value.Id);
			// Adds configuration class
			li.attr('class', 'Background' + value.Arrangement);
			
			// Adds image
			var image = value.Image;
			$.each(sprites, function(idx, value) {
				var i = img.clone().attr('src', image);
				$(value).append(i);
			});
			
			li.imagesLoaded(function($images) { // After the images are loaded, callback to transform the images
				_transformBackground($images, value);
				if (_imageSetsLoaded == length) {
					_imageSetsLoaded == 0; // Reset so that it can be used again
					callback();
				} else {
					_imageSetsLoaded++;
				}
			});
			_spriteBackground.append(li);
		});
	};
	
	var _transformBackground = function(images, data) {
		var sprites = images.parent(),
			tiltData = data.Tilt.split(','),
			scaleData = data.Scale.split(','),
			width = 80, // Assumes square images @ 80px
			height = 80;	

		$.each(sprites, function(idx, value) {
			var sprite = $(value);
			
			_scaleSprite(sprite, width, height, idx, scaleData);
			_tiltSprite(sprite, idx, tiltData);
		});
	};
	
	var _scaleSprite = function(sprite, width, height, idx, scaleData) {
		var img = sprite.children('img'), 
			scalePerc = scaleData[idx] * 1;
			newWidth = Math.floor(width * scalePerc),
			newHeight = Math.floor(height * scalePerc);
		
		img.width(newWidth);
		img.height(newHeight);
	};
	
	var _tiltSprite = function(sprite, idx, tiltData) {
		var degrees = tiltData[idx] * 1;
		if ($.browser.msie) { // IE only likes rotating the image tag
			sprite.find('img').rotate(degrees);
		} else { // Everything else works fine as it's CSS3
			sprite.rotate(degrees);
		}
	};
	
	var _buildTextFrames = function(data) {
		var frames = data.TextFrames,
			templateLi = _textFrames.find('li').detach();
			
		$.each(frames, function(idx, value) {
			var li = templateLi.clone(),
				title = li.find('h1'),
				desc = li.find('h2');
			
			// Adds data id
			li.data('id', value.Id);
			
			// Adds text
			title.text(value.Title);
			desc.html(value.Description);
			
			_textFrames.append(li);
		});
	};
	
	var _buildInfoBox = function(data) {
		// Build initial state of the info box and main link

		// Grab the first Slide and get the link, as it will be the first shown
		var url = data.Slides[0].Url;

		// Call To Action
		_callToAction.text(data.ButtonText);
		_callToAction.attr('href', url);
		
		// Price
		var price = _infoBox.find('h3');
		price.text(data.PriceText);
		
		// Sub Price
		var subPrice = _infoBox.find('p');
		subPrice.text(data.SubPriceText);
		
		// Learn Button
		_learnButton.text(data.LearnText);
		_learnButton.attr('href', data.LearnUrl);

		// Main Link
		_mainLink.attr('href', url);
	};
	
	var _buildKleenexBoxes = function(data, callback) {
		var templateLi = _kleenexBox.find('li').detach(),
			templateUl = _kleenexBox.find('ul').detach(),
			slides = data.Slides;

		$.each(slides, function(idx, slide) {
			var ul = templateUl.clone(),
				boxes = slide.KleenexBoxes;
			$.each(boxes, function(idx, box) {
				var li = templateLi.clone(),
					image = li.find('img');
				image.attr('src', box.Image);
				ul.append(li);
			});
			_kleenexBox.append(ul);
		});
		
		_kleenexBox.imagesLoaded(function($images) {
			callback();
		});
	};

	/* Start Gleam ******************************************************************************************/
	var _gleamStartingLeft = 0,
		_gleamDelay = 8000,
		_gleamInterval = 20000;
	
	var _gleamStart = function() {
		var div = $('<div />');
		_callToAction.append(div);
		_gleamStartingLeft = div.css('left').replace('px', '') * 1;

		$.doTimeout(_gleamDelay, function() {
			_animateGleam(div);
		});
	};

	var _animateGleam = function(gleam) {
		gleam.animate({
			'left': '100%'
		}, 500, 'linear', function() {
			gleam.css('left', _gleamStartingLeft);
			$.doTimeout(_gleamInterval, function() {
				_animateGleam(gleam);
			});
		});	
	};

	/* Start Slideshow ******************************************************************************************/
	var _currentSlide = 0;
	var _startSlideshow = function(data) {
		
		if ($.browser.msie) {
			_mainFrame.find('img[src$=".png"]').each(function() { // must have quotes around .png
		    	this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src="+this.src+",sizingMethod='scale')";
			});
		}
		
		// console.log('start slideshow');
		var slides = data.Slides,
			length = slides.length;
		
		_kleenexBox.cycle({
			fx: 'fade',
			timeout: _duration,
			speed: _speed,
			before: function() {
				var slide = slides[_currentSlide];
				
				// Update Links
				_updateLinks(slide);

				// Transitions
				_transitionBackground(slide);
				_transitionKleenexBoxes(slide);
				_transitionTextFrames(slide);
				
				_incrementSlideCount(length);
			}
		});			
	};
	
	var _incrementSlideCount = function(length) {
		if (_currentSlide == (length - 1)) { // Zero base the length
			_currentSlide = 0;
		} else {
			_currentSlide++;
		}
	};
	
	/* Background Transitons ******************************************************************************************/
	var _currentDisplayedBackground = [];
	var _transitionBackground = function(slide) {
		var bg = slide.Background,
			lis = _spriteBackground.children(),
			duration = _duration; // Backgrounds don't transition between multiple, so it will be here the entire time
		
		$.each(lis, function(idx, listItem) { // Find the background to show
			var li = $(listItem),
				id = li.data('id');
				
			if (id == bg) { 
				var sprites = li.children('div');
				$.each(sprites, function(idx, value){ var r = new RandomFade($(value)); });
				_showBackground(li, duration); 
				return false;
			}
		});
	};
	
	var _showBackground = function(bg, duration) {
		if (_currentDisplayedBackground.length) { _currentDisplayedBackground.fadeOut(); }
		bg.slideDown(1500, 'linear');
		_currentDisplayedBackground = bg;
	};
	
	/* Kleenex Box Transitons ******************************************************************************************/
	var _transitionKleenexBoxes = function(slide) {
		var boxes = slide.KleenexBoxes,
			length = boxes.length,
			uls = _kleenexBox.children('ul'),
			ul = $(uls[_currentSlide]), // These show up in order, so we can use our _currentSlide as an idx
			lis = ul.children('li'),
			duration = _calculateDuration(length),
			queue = _createBoxQueue(boxes, lis);
		
		_animateBoxQueue(queue, duration, (length - 1), 0); // Zero-base the length, Start at 0
	};
	
	var _createBoxQueue = function(textFrames, lis) {
		var queue = [];
		$.each(lis, function(idx, li) {
			li = $(li);
			queue.push(li);
		});
		return queue;
	};
	
	var _animateBoxQueue = function(queue, duration, length, idx) {

		queue[idx].css('z-index', idx).fadeIn(1000, 'linear', function() {
			// This is a double check. For some reason there a random frames
			// (few and far between) that don't fade in. If it isn't visible
			// after the initial fadeIn, then show it.
			if (!queue[idx].is(':visible')){ 
				queue[idx].css({
					'opacity': 1,
					'display': 'list-item'
				}); 
			}
		});

		
		$.doTimeout(duration, function() {
			if (length != idx) { // There's still more to animate
				idx++;
				_animateBoxQueue(queue, duration, length, idx);
				// We never fade out because we fade over the top
				// queue[idx].fadeOut(1500, 'linear', function() {});
			} else {
				var wait = (_duration + _speed) - duration;
				$.doTimeout(wait, function() { // Wait out the rest of the frame
					$.each(queue, function(idx, value) { // We're done with this frame, fadeOut
						$(value).fadeOut(3000);
					});
				});
			}
		});
	};
	
	/* Text Frame Transitons ******************************************************************************************/
	var _currentTextFrameId = null; // Hold the id of the currently shown frame
	var _currentShownFrame = null; // Hold the id of the currently shown frame
	var _transitionTextFrames = function(slide) {
		var textFrames = slide.TextFrames.split(','),
			length = textFrames.length,
			lis = _textFrames.children('li'),
			duration = _calculateDuration(length),
			queue = _createTextQueue(textFrames, lis);
		
		// This is a check to animate out a displayed frame
		// if the next set of frames starts with a different frame.
		// If a set starts with the same frame as the one that's showing
		// leave it because the animation is animating to the frame's currently set values
		if (_currentTextFrameId) { // There's nothing initiall showing, check
			var initialDataId = queue[0].data('id'); // Grab id of first in queue
			if (_currentTextFrameId !== initialDataId) { // If what's showing is not what will be first in queue, animate out
				_currentShownFrame.animate({'bottom': '100%', 'opacity': 0 }, 700, 'linear');
			}
		}

		_animateQueue(queue, duration, (length - 1), 0); // Zero-base the length, Start at 0
	};
	
	var _createTextQueue = function(textFrames, lis) {
		var queue = [];
		$.each(textFrames, function(idx, value) {
			var id = value * 1;
			$.each(lis, function(idx, li) {
				li = $(li);
				var dataId = li.data('id');
				if (dataId == id) { queue.push(li); }
			});
		});
		return queue;
	};
	
	var _animateQueue = function(queue, duration, length, idx) { // This animation fades and transitions at the same time
		queue[idx].animate({ 
			'bottom': 0,
			'opacity': 1
		}, 1500, 'easeOutExpo', function() {
			_currentShownFrame = queue[idx];
			_currentTextFrameId = queue[idx].data('id');
		});
		
		$.doTimeout(duration, function() {
			if (length !== idx) { // There's still more to animate
				queue[idx].animate({
					'bottom': '100%',
					'opacity': 0
				}, 700, 'linear', function() {
					idx++;
					_animateQueue(queue, duration, length, idx);
				});
			}
		});
	};

	/* Change Links ******************************************************************************************/
	var _updateLinks = function(data) {
		var url = data.Url;

		_callToAction.attr('href', url)
		_mainLink.attr('href', url);
	};

	/* Calculate Delay ******************************************************************************************/
	var _calculateDuration = function(num) {
		var delay = _duration + _speed;
		if (num > 1) { delay = delay / (num + 1); }
		return delay;
	};
	
	/* Loading Hide / Show ******************************************************************************************/	
	var _hideLoading = function() {
		_loading.fadeOut();
	};
	
	var _showLoading = function() {
		_loading.show();
	};

	var _showElements = function() {
		_spriteBackground.css({'width': '100%', 'height': '100%'});
	};
	
	return {
		init: _init,
		duration: _duration,
		speed: _speed
	};
}());


/* Random Fading ******************************************************************************************/	
var RandomFade = function(sprite) {
	var self = this,
		rand = $.randomBetween(200, 1500);
		duration = $.randomBetween(1000, 3000);
		
	$.doTimeout(rand, function() {
		self.fade(sprite, duration);
	});

	$.doTimeout(Kleenex.duration + Kleenex.speed, function() {
		self.breakCycle = true;
	});
};
RandomFade.prototype.breakCycle = false;
RandomFade.prototype.fade = function(sprite, duration) {
	var self = this;
	sprite.fadeToggle(duration, 'linear', function() {
		if (self.breakCycle) { return false; } // If break is true, stop calls
		self.fade(sprite, duration);
	});
};


$.fn.cycle.transitions.none2 = function($cont, $slides, opts) {
	var css = { top: 0, left: 0 }
	opts.fxFn = function(curr,next,opts,after){
		$.fn.cycle.commonReset(curr,next,opts,after);
		$([curr,next]).css(css);
		$(next).show();
		$(curr).hide();
		after();
	};
}
