/**
 * Chips Ahoy!
 * 
 * @author    Tharsan Bhuvanendran <tbhuvanendran@360i.com>
 * @copyright 360i
 * @version   1.0
 * @revision  $Id$
 */

/**
 * The minimum visible percentage allowed for any pane until it is deemed "active".
 * @var int
 */
var PANE_VISIBILITY_ACTIVATION_THRESHOLD = 80,

/**
 * The speed at which the foreground chips layer will move with respect to the
 * browser's scroll position.
 * @var int
 */
    SPEED_FOREGROUND_CHIPS = 2,

/**
 * The speed at which the foreground chips layer will move with respect to the
 * browser's scroll position.
 * @var int
 */
    SPEED_BACKGROUND_CHIPS = 0.5,

/**
 * The speed at which the product placements layer will move with respect to the
 * browser's scroll position.
 */
    SPEED_PRODUCT_PLACEMENTS = 2,

/**
 * The number of unique chip sprites available for each pane.
 * @var int
 */
    UNIQUE_PANE_CHIP_COUNT   = 7,

/**
 * The duration (in ms) to wait with a pane in focus before a pageview tracking
 * event is fired.
 * @var int
 */
    TIMEOUT_PANE_PAGEVIEW_TRACKING = 5000,

/**
 * The duration (in ms) to wait before redrawing page elements automatically.
 */
	TIMEOUT_AUTO_REDRAW = 1000;

var animationEnabled = !('ontouchstart' in document),
    cssAnimationEnabled = (
      document.documentElement.style.webkitTransition !== undefined
	  || document.documentElement.style.MozTransition !== undefined
	  || document.documentElement.style.OTransition !== undefined
	  || document.documentElement.style.msTransition !== undefined
	  || document.documentElement.style.transition !== undefined
	) && navigator.userAgent.indexOf('Safari') == -1;

var chipsahoy = {
	panes: ['home', 'original', 'chewy', 'chunky', 'chewygooey', 'reeses', 'games'],
	paneChipCount: [12, 12, 12, 12, 12, 12, 0],
	productHeights: [0, 390, 450, 375, 460, 415, 0],
	eventTrackingTimeout: null,
	lastScrollTop: 0,
	redrawTimeout: null,
	movingToPane: false,

	elements: {
		'chips-fg': document.getElementById('chips-layer-fg'),
		'chips-bg': document.getElementById('chips-layer-bg'),
		'panes':    $('section.pane')
	},

	init: function() {
		$('nav')
			.bind('reveal', chipsahoy.nav.reveal)
			.bind('conceal', chipsahoy.nav.conceal);

		$('.pane')
			.bind('centerInView', chipsahoy.pane.centerInView)
			.bind('configureNav', chipsahoy.pane.configureNav);

		// attach to the window's scroll event
		$(window).scroll(chipsahoy.redrawElements);

		if(!animationEnabled)
			$('body').addClass('no-animation');

		// scatter chips randomly throughout the chip overlay layers
		$('section.pane').each(chipsahoy.overlayChips);

		// re-center the header, products and games when the window is resized
		$(window).resize(function(e) {
			$('header').css('left', $(window).width()/2 - $('header').width()/2);
			$('section.pane .product').css('left', function(index, value) {
				return $(window).width() / 2 - this.offsetWidth/2;
			});
			$('#games ul').css('left', $(window).width()/2 - 480);
		}).resize();

		// link tracking
		$('a[rel="external"]').attr('target', '_blank');
		$('nav.root ul > li > a[href^="http"], section a.cta').click(tracking.trackEvent);
		$('nav.root ul > li > a[href^="#/"]').click(tracking.trackPageView);

		tracking.init({
			TRACKER_GOOGLE_ANALYTICS: {
				id: 'UA-23014770-1'
			}
		});

		hashNav.init(function(slide) {
			$('#'+slide).trigger('centerInView');
		});
	},

	pane: {
		/**
		 * Event 'centerInView' scrolls the browser window so that the target pane
		 * is centered vertically in the viewport.
		 */
		centerInView: function(e) {
			var $pane = $(this),
		    viewportHeight = $(window).height(),
		    paneHeight     = $pane.height(),
		    paneTop        = $pane.offset().top,
		    scrollTop      = paneTop; // by default, scroll to the top of the pane

			// if the viewport is larger than the pane, then attempt to center the
			// pane in the viewport
			if(viewportHeight > paneHeight)
				scrollTop -= (viewportHeight-paneHeight)/2;

			chipsahoy.movingToPane = true;
			$('html, body').stop().animate({
				scrollTop: scrollTop + 'px'
			}, 1000, function() {
				chipsahoy.movingToPane = false;
				$(this).trigger('configureNav');
			});
		},

		/**
		 * Event 'configureNav' sets the 'active' class on the current nav & subnav
		 * items, and updates the URL hash.
		 */
		configureNav: function(e) {
			var $pane = $(this),
			    paneName = $pane.attr('id'),
			    $navItem = $('header nav li.item-' + paneName);

			if($navItem.hasClass('active'))
				return true;

			$navItem.siblings().removeClass('active').end() // deactivate all sibling subnav items
				.addClass('active') // activate this subnav item only
				.parents('li')
					.siblings().removeClass('active').end() // deactivate all sibling nav items
					.addClass('active') // active this nav item only
					.children('nav').trigger('reveal');

			// conceal any subnav elements below an inactive nav item
			if(!$pane.hasClass('product'))
				$('.root ul li nav').find('ul li').removeClass('active').end()
					.trigger('conceal').parent().removeClass('active');

			location.hash = hashNav.lastHash = '#/' + paneName;

			$pane.addClass('active');
		}
	},

	nav: {
		/**
		 * Event 'reveal' on a subnav floats it out below the main nav, and then
		 * pops it up top of the main nav.
		 */
		reveal: function(e) {
			if(this.style.zIndex != 1) {
				$(this).stop().animate({
					top: '80px'
				}, 250, function() {
					$(this).css('zIndex', 1);
				});
			}
		},

		/**
		 * Event 'conceal' on a subnav pops it below the main nav, and then slides it
		 * underneath the main nav.
		 */
		conceal: function(e) {
			if(this.style.zIndex != -1) {
				$(this).css('zIndex', -1).stop().animate({
					top: '-80px'
				}, 250);
			}
		}
	},

	/**
	 * Update the position of each of the dynamic layer elements.
	 * This includes the vertical position of each chips layer, and the placement
	 * of the product in each slide pane.
	 * 
	 * @param evt The event object.
	 * @returns nothing
	 */
	redrawElements: function(evt) {
		var viewportHeight = $(window).height(),
		    viewportTop    = $(window).scrollTop(),
		    viewportCenter = viewportTop + viewportHeight / 2, 
		    viewportBottom = viewportTop + viewportHeight,
		    fgChipsTop = -1*viewportTop*SPEED_FOREGROUND_CHIPS,
		    bgChipsTop = -1*viewportTop*SPEED_BACKGROUND_CHIPS,
			scrolled   = viewportTop - chipsahoy.lastScrollTop;

		if(animationEnabled && cssAnimationEnabled) {
			chipsahoy.elements['chips-fg'].style.webkitTransform = 'translate(0,'+fgChipsTop+'px)';
			chipsahoy.elements['chips-fg'].style.MozTransform = 'translate(0,'+fgChipsTop+'px)';
			chipsahoy.elements['chips-fg'].style.msTransform = 'translate(0,'+fgChipsTop+'px)';
			chipsahoy.elements['chips-fg'].style.OTransform = 'translate(0,'+fgChipsTop+'px)';
			chipsahoy.elements['chips-fg'].style.transform = 'translate(0,'+fgChipsTop+'px)';
			chipsahoy.elements['chips-bg'].style.webkitTransform = 'translate(0,'+bgChipsTop+'px)';
			chipsahoy.elements['chips-bg'].style.MozTransform = 'translate(0,'+bgChipsTop+'px)';
			chipsahoy.elements['chips-bg'].style.msTransform = 'translate(0,'+bgChipsTop+'px)';
			chipsahoy.elements['chips-bg'].style.OTransform = 'translate(0,'+bgChipsTop+'px)';
			chipsahoy.elements['chips-bg'].style.transform = 'translate(0,'+bgChipsTop+'px)';
		} else if(animationEnabled) {
			chipsahoy.elements['chips-fg'].style.top = fgChipsTop + 'px';
			chipsahoy.elements['chips-bg'].style.top = bgChipsTop + 'px';
		}

		chipsahoy.elements.panes.each(function(i,pane) {
			var product     = pane.children[0],
			    paneHeight  = pane.offsetHeight,
			    paneTop     = pane.offsetTop,
			    paneCenter  = paneTop + paneHeight/2,
			    paneBottom  = paneTop + paneHeight,
			    pctVisible  = 100,
			    productTop,
				productHeight = chipsahoy.productHeights[i];

			// neither pane boundary is inside the viewport
			if(viewportTop > paneBottom || viewportBottom < paneTop)
				pctVisible = 0;

			// only top pane boundary is inside viewport
			else if(paneTop < viewportBottom && paneBottom > viewportBottom)
				pctVisible = (viewportBottom - paneTop) / paneHeight * 100;

			// only bottom pane boundary is inside the viewport
			else if(paneBottom < viewportBottom && paneTop < viewportTop)
				pctVisible = (paneBottom - viewportTop) / paneHeight * 100;

			// cutover between panes when an inactive pane has crossed into primary view
			if(!chipsahoy.movingToPane && pctVisible > PANE_VISIBILITY_ACTIVATION_THRESHOLD && ! $(pane).hasClass('active')) {
				$('section.pane').removeClass('active');
				$(pane).addClass('active').trigger('configureNav');
				if(!chipsahoy.movingToPane)
					chipsahoy.trackDelayedPageView();
			}

			if(product.className.indexOf('product') > -1 && animationEnabled) {
				if(pctVisible > 0) {
					productTop = (SPEED_PRODUCT_PLACEMENTS * (paneCenter - viewportCenter)) - (productHeight/2);

					// small screen (can't see a full pane in viewport) so center between header bottom and viewport bottom
					if(viewportHeight < paneHeight+70)
						productTop += ((viewportHeight-200)/2) + 80;

					// plenty of space so center between viewport top and viewport bottom
					else
						productTop += (viewportHeight/2) - 80;
				} else {
					productTop = (scrolled < 0) ? -5000 : 5000;
				}
	
				if(cssAnimationEnabled && product) {
					product.style.top = 0;
					product.style.webkitTransform = 'translate(0,'+productTop+'px)';
					product.style.MozTransform = 'translate(0,'+productTop+'px)';
					product.style.msTransform = 'translate(0,'+productTop+'px)';
					product.style.OTransform = 'translate(0,'+productTop+'px)';
					product.style.transform = 'translate(0,'+productTop+'px)';
				} else if(product) {
					product.style.top = productTop + 'px';
				}
			}
		});

		if(evt)
			setTimeout(chipsahoy.redrawElements, TIMEOUT_AUTO_REDRAW);

		chipsahoy.lastScrollTop = viewportTop;
	},

	/**
	 * Inject random chip crumbles into the foreground & background chip layers
	 * overlaid on top of the context pane.
	 * 
	 * @param paneIndex int    The numeric pane index in the collection of panes.
	 * @param pane      object The pane HTML element.
	 */
	overlayChips: function(paneIndex,pane) {
			var maxWidth   = $(window).width()*0.9,
		    paneHeight = $(pane).height(),
		    paneTop    = $(pane).offset().top,
		    paneName   = chipsahoy.panes[paneIndex],
		    paneChipCount = chipsahoy.paneChipCount[paneIndex];

		// inject random crumbs into the background and foreground layers for this pane
		for(var i=0; i < paneChipCount; i++) {
			var chipNum  = Math.ceil(Math.random() * UNIQUE_PANE_CHIP_COUNT),
			    imgSrc   = "images/pane/chips/" + paneIndex + "-" + paneName + "-" + chipNum + ".png",
			    layer    = 'bg',
			    scale    = SPEED_BACKGROUND_CHIPS+1,
			    maxHeight,
			    bgLeft,
			    bgTop,
			    coords;

			if(Math.random() < 0.5) {
				layer = 'fg';
				scale = SPEED_FOREGROUND_CHIPS+1;
			}
			maxHeight = paneHeight*scale;

			if(layer == 'fg')
				bgLeft = 100;
			else
				bgLeft = Math.floor(Math.random()*4)*100;

			if(pane.id == 'variety-chunky')
				bgTop = (Math.random() < 0.4) ? 200 : Math.floor(Math.random()*2)*100;
			else if(pane.id == 'variety-reeses')
				bgTop = (Math.random() < 0.4) ? 300 : Math.floor(Math.random()*2)*100;
			else
				bgTop = Math.floor(Math.random()*2)*100;

			coords = {};
			coords['backgroundPosition'] = (-1*bgLeft) + 'px ' + (-1*bgTop) + 'px';
			if(Math.random() < 0.5)
				coords['left'] = Math.random() * (maxWidth-400) / 2;
			else
				coords['right'] = Math.random() * (maxWidth-400) / 2;
			coords['top'] = (Math.random() * maxHeight) + (paneTop * scale) - 400;

			$('<div/>').addClass('chip').addClass('draggable')
				.addClass('pane-' + pane.id)
				.css(coords)
				.appendTo('#chips-layer-' + layer);
		}
	},

	/**
	 * Track a page view, by waiting some preconfigured length of time without
	 * changing active panes.
	 */
	trackDelayedPageView: function() {
		if(chipsahoy.eventTrackingTimeout)
			clearTimeout(chipsahoy.eventTrackingTimeout);

		chipsahoy.eventTrackingTimeout = setTimeout(function() {
			tracking.trackPageView(location.href);
		}, TIMEOUT_PANE_PAGEVIEW_TRACKING);
	}
}

chipsahoy.init();

