/**
 * DrPepper.PromoFooter
 *	
 * Scrollable box for promo items. There is always only one PromoFooter, in the footer area.
 *
 * Author:	Silvan Reinhold
 * Date:	2009-03-05
 * See:		PromoFooter.php
 **/

var DrPepper = DrPepper || {};


/**
 * Constructor
 *
 * @param	p_xDomElement					DOM element representing this PromoFooter in the document (may also be an ID)
 * @param	p_bShowExpanded					Flag: initial state is expanded (true) or collapsed (false)
 * @param	p_bRememberStateImmediately		Flag: remember state in a cookie immediately (true), or only after first change (false)
 **/
DrPepper.PromoFooter = function(p_xDomElement, p_bShowExpanded, p_bRememberStateImmediately)
{
	this.init();

	// The promo page will have its promo footer collapsed by default.
	// If we navigate away from the promo page immediately, we want the original promo footer state restored (p_bRememberStateImmediately = false).
	// If the user expands the promo footer on the promo page, and it was collapsed on the previous page, we want to remember that new state for the new page.
	//
	this._bRememberStateImmediately = p_bRememberStateImmediately;
	this._bPreviousState = $.cookie("promofooterExpanded");	// state as recorded by the previous page
	this._bInitialState = p_bShowExpanded;					// initial state on this page
	
	// Keep references to important sub-elements for quick access
	//
	this._xDomElement = $(p_xDomElement);

	DrPepper.Util.disableSelection($(this._xDomElement).attr("id"));

	this._xMainContainer = $(".main-container", this._xDomElement);
	this._xItemContainer = $(".item-container", this._xDomElement);
	this._nNominalItemCount = $(".item", this._xItemContainer).size();
	this._nItemWidth = $(".item:eq(0)", this._xItemContainer).width();

	this._xBtnLeft = $(".btn-left", this._xDomElement);
	this._xBtnRight = $(".btn-right", this._xDomElement);
	this._xBtnExpand = $(".btn-expand", this._xDomElement);
	this._xSeparator = $(".separator", this._xDomElement);
	
	// This is the footer backdrop (i.e. outside the promo footer); we will fade it out whenever the promo footer
	// rolls in, and fade it back in whenever the promo footer rolls out.
	//
	this._xFooterBackdrop = $("#footer .backdrop");
    

	// Keep track of whether we are currently expanded or contracted
	//	
	this._bIsExpanded = p_bShowExpanded;
	
	// Calculate the top position to scroll to when the promo footer is to collapse
	//
	this._nCollapsedTop = $(this._xDomElement).height() - $(this._xBtnExpand).height() - $("#footer").height() - parseInt($("#footer").css("paddingTop"));


	// Set up interactive behavior
	//
	this.setupBehavior();

	// Initial (and p_bImmediate, i.e. not animated) expansion or contraction, based on the respective constructor parameter
	//
	this.expand(this._bIsExpanded, true);
}


/**
 * Class attributes
 **/
DrPepper.PromoFooter.VISIBLE_ITEM_COUNT = 3;	// Maximum number of items surfaced at any one time


/**
 * Instance attributes
 */
DrPepper.PromoFooter.prototype = {
	_bRememberStateImmediately	:	false,	// flag: remember expansion state in cookie
	
	_bAllowOpacityFade	:	false,	// avoid fancy effects (that might break in IE7, for example)
	_nMaxOpacity		:	1,
	
	_xDomElement		:	null,	// DOM element representing this PromoFooter

	_xMainContainer		:	null,	// references to DOM sub-elements, stored for quick access
	_xItemContainer		:	null,
	_xBtnLeft			:	null,
	_xBtnRight			:	null,
	_xBtnExpand			:	null,
	_xSeparator			:	null,
    
	_xFooterBackdrop	:	null,	// reference to the footer's backdrop (must fade out/in as promo box expands/contracts)
	
	_nNominalItemCount	:	0,		// nominal number of items in this PromoFooter
	_nActualItemCount	:	0,		// actual nominal number of items in this PromoFooter, including clones for cycling optimization
	_nScrollItemIndex	:	0,
	_bIsAnimating		:	false,	// flag: curently animating (used to block further animations until complete)
	
	_nCollapsedTop		:	0,		// top position when collapsed
	_bIsExpanded		:	false	// flag: PromoFooter is currently expanded
}


DrPepper.PromoFooter.prototype.init = function()
{
	// Certain browsers (such as IE7) may require degradation of animation behavior due to rendering bugs;
	// specifically, we will not fade in/out the _xSeparator line below the expand/contract button in IE7,
	// because that browser *still* has PNG transparency issues whenever opacity is not exactly 1.
	//
	// Likewise, Firefox 2 on the Mac hides any SWF overlapping with elements that have opacity < 1.
	// Therefore, that browser will also be excluded from opacity fades.
	//
	var l_bIsIE7Or8 =
		$.browser.msie &&
		((parseInt($.browser.version) == 7) || (parseInt($.browser.version) == 8));

	var l_bIsFirefox2Mac =
		$.browser.mozilla &&
		($.browser.version.substr(0, 3) < 1.9) &&		// FF2 uses Gecko engine version < 1.9
		(navigator.appVersion.indexOf("Mac") != -1);

	if (l_bIsIE7Or8 || l_bIsFirefox2Mac) {
		this._nMaxOpacity = 1;
	}
	else {
		this._nMaxOpacity = .9999;
	}
	
	this._bAllowOpacityFade = !l_bIsIE7Or8 && !l_bIsFirefox2Mac;
}


/**
 * Expands or collapses this PromoFooter.
 *
 * @param	p_bDoExpand		flag: expand (true) or collapse (false)
 * @param	p_bImmediate	flag: expand/collapse immediately (true) or by animating between states (false)
 */
DrPepper.PromoFooter.prototype.expand = function(p_bDoExpand, p_bImmediate)
{
	if (p_bDoExpand) {
		if (p_bImmediate) {
			$(this._xMainContainer).css("top", 0);
			if (this._bAllowOpacityFade) {
				$(this._xFooterBackdrop).css("opacity", 0);
				$(this._xSeparator).css("opacity", this._nMaxOpacity);
			}
			else {
				$(this._xFooterBackdrop).css("visibility", "hidden");
			}
		}
		else {
			$(this._xMainContainer).animate({ top: 0 }, 250);
			if (this._bAllowOpacityFade) {
				$(this._xFooterBackdrop).animate({ opacity: 0 }, 250);
				$(this._xSeparator).animate({ opacity: this._nMaxOpacity }, 750);
			}
			else {
				$(this._xFooterBackdrop).css("visibility", "hidden");
			}
		}
	}
	else {
		if (p_bImmediate) {
			$(this._xMainContainer).css("top", this._nCollapsedTop);
			if (this._bAllowOpacityFade) {
				$(this._xFooterBackdrop).css("visibility", "visible");
				$(this._xFooterBackdrop).css("opacity", this._nMaxOpacity);
				$(this._xSeparator).css("opacity", 0);
			}
			else {
				$(this._xFooterBackdrop).css("visibility", "visible");
			}
		}
		else {
			$(this._xMainContainer).animate({ top: this._nCollapsedTop }, 250);
			if (this._bAllowOpacityFade) {
				$(this._xFooterBackdrop).css("opacity", 0);
				$(this._xFooterBackdrop).css("visibility", "visible");
				$(this._xFooterBackdrop).animate({ opacity: this._nMaxOpacity }, 250);
				$(this._xSeparator).animate({ opacity: 0 }, 250);
			}
			else {
				$(this._xFooterBackdrop).css("visibility", "visible");
			}
		}
	}

	
	this._bIsExpanded = p_bDoExpand;
	
	// Remember expand/collapse state for next page switch
	//
	if (this._bRememberStateImmediately == true) {
		//
		// We *want to* remmeber the state change immediately
		//
		$.cookie("promofooterExpanded", this._bIsExpanded ? "1" : "0", { path: "/" });
	}
	else {
		//
		// We are *not* supposed to remember the state change immediately...
		//
		// Make sure the first call to expand() allows subsequent calls to expand() to remember the state
		// *unless* the state on the previous page differs from the initial state on this page
		//
		if (!this._bExpandedStateChangedOnceAlready && (this._bPreviousState != this._bInitialState)) {
			this._bExpandedStateChangedOnceAlready = true;
			return;
		}
		this._bRememberStateImmediately = true;
	}
}


/**
 * Initializes the dynamic behavior of this PromoFooter. This includes buttons and animations.
 */
DrPepper.PromoFooter.prototype.setupBehavior = function()
{
	var l_xPromoFooterObj = this;

	// Set up click behavior for all items
	//
	$(".item", this._xDomElement).click(function() {

		// Fetch metadata for this item
		var l_xMetaData = $(".meta-data", this);
		var l_sActionUrl = $(".action-url", l_xMetaData).text();
		var l_nLinkType = parseInt($(".link-type", l_xMetaData).text());

		// Fetch tracking metadata for this item (if applicable)
		var l_xTracking = $(".tracking", l_xMetaData);
		if (l_xTracking.length > 0) {
			//
			// If the promo footer item is being tracked:
			//
			// Find out where the clicked item is located in the visible area of the PromoFooter (left / middle / right)
			// If there is only one item, position is always "middle"
			// If there are two items, position is either "left" or "right"
			// For three or more items, position is either "left", "middle", or "right"
			//
			var l_sPosition = "";
			var l_nScrollItemIndexDiff = parseInt($(".actual-item-index", l_xMetaData).text()) - l_xPromoFooterObj._nScrollItemIndex;
			switch (l_nScrollItemIndexDiff) {
				case 0:
					if (l_xPromoFooterObj._nActualItemCount == 1) {
						l_sPosition = "middle";
					}
					else {
						l_sPosition = "left";
					}
					break;
				case 1:
					if (l_xPromoFooterObj._nActualItemCount == 2) {
						l_sPosition = "right";
					}
					else {
						l_sPosition = "middle";
					}
					break;
				case 2:
					l_sPosition = "right";
					break;
			}

			// Store the position value in the ".meta-data .tracking" element. It will be parsed by Tracking.track()
			//
			var l_sTrackingContent = l_xTracking.text();
			if ((l_sTrackingContent == null) || (l_sTrackingContent == "")) {
				l_sTrackingContent = "position: \"\"";
			}
			if (!l_sTrackingContent.match(/position:/)) {
				//
				// no position specified prior to this click: add it to the tracking parameters
				//
				l_sTrackingContent += ", position: \"" + l_sPosition + "\"";
			}
			else {
				//
				// some position was already specified during a previous click: adjust it to the current position
				//
				l_sTrackingContent = l_sTrackingContent.replace(/position:\s*"[^"]*"/, "position: \"" + l_sPosition + "\"");
			}
			l_xTracking.text(l_sTrackingContent);
		}
		
		DrPepper.Site.performLinkAction({ linkType: l_nLinkType, url: l_sActionUrl });
	});
	
	// Set up expand/contract functionality
	$(this._xBtnExpand).click(function() { l_xPromoFooterObj.expand(!l_xPromoFooterObj._bIsExpanded); });


	// Attach hover behavior to each item; this will highlight the item title only
	$(".item", this._xItemContainer).hover(
		function() {
			$(this).addClass("hover");
		},
		function() {
			$(this).removeClass("hover");
		}
	);

	// Set up scrolling functionality only if there are more items than can be displayed by definition
	//
	if (this._nNominalItemCount > DrPepper.PromoFooter.VISIBLE_ITEM_COUNT) {

		// Duplicate the first and last VISIBLE_ITEM_COUNT items, and append/prepend them to the item list
		// (e.g.: 5, 6, 7 -- 1, 2, 3, 4, 5, 6, 7 -- 1, 2, 3)
		// This is so that we can cycle through the list without visual interruption, because appending/prepending
		// during a click on the forward/back button may leave an item slot blank for a fraction of a second, while
		// the browser engine clones and places the element.
		//
		var l_xLastItems = $(".item:gt(" + (this._nNominalItemCount - DrPepper.PromoFooter.VISIBLE_ITEM_COUNT - 1) + ")", this._xItemContainer).clone(true);
		var l_xFirstItems = $(".item:lt(" + (DrPepper.PromoFooter.VISIBLE_ITEM_COUNT) + ")", this._xItemContainer).clone(true);
		$(this._xItemContainer).prepend(l_xLastItems).append(l_xFirstItems);
		this._nActualItemCount = $(".item", this._xItemContainer).size();
		

		// Focus on the acutal first item in the list
		//
		this._nScrollItemIndex = DrPepper.PromoFooter.VISIBLE_ITEM_COUNT;
		$(this._xItemContainer).css("left", -this._nScrollItemIndex * this._nItemWidth);

		// Set up scroll handler to loop through all items
		//
		function scrollByOne(p_bForward) {
			// Wait until the previous animation has finished
			if (l_xPromoFooterObj._bIsAnimating) {
				return;
			}
			// Block following animations until this one is completed (JS is still single-threaded for now, so no worries here)
			l_xPromoFooterObj._bIsAnimating = true;

			if (p_bForward) {
				// scroll to next actual item
				$(l_xPromoFooterObj._xItemContainer).animate({ left: "-=" + l_xPromoFooterObj._nItemWidth }, 200, "swing", function() {
					l_xPromoFooterObj._nScrollItemIndex++;
					if (l_xPromoFooterObj._nScrollItemIndex >= DrPepper.PromoFooter.VISIBLE_ITEM_COUNT + l_xPromoFooterObj._nNominalItemCount) {
						// skip to nominal first item again (which corresponds to the clone that is currently displayed on the far left)
						l_xPromoFooterObj._nScrollItemIndex = DrPepper.PromoFooter.VISIBLE_ITEM_COUNT;
						$(l_xPromoFooterObj._xItemContainer).css("left",  -l_xPromoFooterObj._nScrollItemIndex * l_xPromoFooterObj._nItemWidth);
					}
					l_xPromoFooterObj._bIsAnimating = false; 
				});
			}
			else {
				// scroll to previous actual item
				$(l_xPromoFooterObj._xItemContainer).animate({ left: "+=" + l_xPromoFooterObj._nItemWidth }, 200, "swing", function() {
					l_xPromoFooterObj._nScrollItemIndex--;
					if (l_xPromoFooterObj._nScrollItemIndex <= 0) {
						// skip to original item corresponding to the clone that is currently displayed on the far left
						l_xPromoFooterObj._nScrollItemIndex = l_xPromoFooterObj._nNominalItemCount;
						$(l_xPromoFooterObj._xItemContainer).css("left", -l_xPromoFooterObj._nScrollItemIndex * l_xPromoFooterObj._nItemWidth);
					}
					l_xPromoFooterObj._bIsAnimating = false; 
				});
			}
		}

		$(this._xBtnLeft).css("visibility", "visible").click(function() { scrollByOne(false); });
		$(this._xBtnRight).css("visibility", "visible").click(function() { scrollByOne(true); });
	}
	else {
		// If there VISIBLE_ITEM_COUNT or less items, center the items and do not display scroll buttons
		$(this._xItemContainer).css("left", "50%").css("marginLeft", "-" + Math.round(this._nItemWidth * this._nNominalItemCount * 0.5) + "px");
		$(this._xBtnLeft).css("visibility", "hidden");
		$(this._xBtnRight).css("visibility", "hidden");
		this._nActualItemCount = this._nNominalItemCount;
	}

	// Each *actual* item will have its own, fixed index in [0; number of actual items - 1],
	// which is used by the click handler to calculate its relative position to the leftmost visible item (_nScrollItemIndex),
	// in order to determine whether the item is located "left", "middle", or "right"
	$(".item .meta-data", this._xItemContainer).each(function(p_nIndex) {
		$(this).append($("<span />").addClass("actual-item-index").text(p_nIndex));
	});
	
	// Make sure the actual item container holds all items (the hosting scroll container will clip any overflow)
	//
	$(this._xItemContainer).css("visibility", "visible").css("width", (this._nActualItemCount + 1) * this._nItemWidth);
}
