/**
 * DrPepper.ModuleBox
 *	
 * Multi-row box with expand/collapse button, for modules/items.
 *
 * Author:	Silvan Reinhold
 * Date:	2009-04-16
 * See:		ModuleBox.php
 **/

var DrPepper = DrPepper || {};


/**
 * Constructor
 *
 * @param	p_xDomElement		DOM element representing this ModuleBox in the document (may also be an ID)
 * @param	p_bShowExpanded		Flag: initial state is expanded (true) or collapsed (false)
 **/ 
DrPepper.ModuleBox = function(p_xDomElement, p_bShowExpanded)
{
	this.init();

	this._xDomElement = $(p_xDomElement);

	this._xBtnExpand = $(".btn-expand", this._xDomElement);
	this._nRowCount = $(".item-row", this._xDomElement).size();
	
	// Do not fade out content rows in IE7, because it may break IE6/IE7 PNG transparency;
	// using the IE6 PNG fix instead is not really an option for performance reasons
	//
	if (this._bAllowOpacityFade) {
		$(".item-row:gt(0)", this._xDomElement).each(function() {
			$(this).css("opacity", 0);
		});

		// Fix FF2/Mac opacity rendering bug (flashing items when opacity is set to 1)
		//
		$(".item-row:eq(0)", this._xDomElement).css("opacity", this._nMaxOpacity);
	}


	this.setupBehavior();

	if (this._nRowCount > 1) {
		this.expand(p_bShowExpanded, true);
	}
}


/**
 * Class attributes
 **/
DrPepper.ModuleBox._bIsAutoTriggering;		// flag: currently triggering an item based on a history change
DrPepper.ModuleBox._bIsManuallyTriggering;	// flag: currently triggering an item based on a manual item link click

DrPepper.ModuleBox._bIsTrackingHistory = false;	// flag: track history (true) or not (false)


/**
 * Instance attributes
 */
DrPepper.ModuleBox.prototype = {
	_bAllowOpacityFade	:	true,
	_nMaxOpacity		:	1,		// for any browser other than Safari or IE, opacity will be .9999 to avoid rendering issues
	
	_xDomElement		:	null,	// DOM element representing this ModuleBox
	_xBtnExpand			:	null,	// reference to the expand button, for quick access
	_nExpandedHeight	:	0,		// px-height of this box in its expanded state
	_nCollapsedHeight	:	0,		// px-height of this box in its collapsed state
	
	_bIsExpanded		:	false,	// flag: box is currently expanded (true) or collapsed (false)
	_nRowCount			:	0		// total number of rows
}


DrPepper.ModuleBox.prototype.init = function()
{
	// Certain browsers (such as IE6/7) may require degradation of animation behavior due to rendering bugs;
	// specifically, we will not fade in/out the separator 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_bIsIE =
		$.browser.msie;

	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_bIsIE || l_bIsFirefox2Mac) {
		this._nMaxOpacity = 1;
	}
	else {
		this._nMaxOpacity = .9999;
	}
	
	this._bAllowOpacityFade = !l_bIsIE && !l_bIsFirefox2Mac;
}


/**
 * Expands or collapses this ModuleBox.
 *
 * @param	p_bDoExpand	flag: expand (true) or collapse (false)
 * @param	p_bImmediate	flag: expand/collapse p_bImmediately (true) or by animating between states (false)
 */
DrPepper.ModuleBox.prototype.expand = function(p_bDoExpand, p_bImmediate)
{
	var l_nMaxOpacity = this._nMaxOpacity;
	
	if (p_bImmediate) {
		if (p_bDoExpand) {
			$(this._xDomElement).css("height", this._nExpandedHeight);
			
			if (this._bAllowOpacityFade) {
				$(".item-row:gt(0)", this._xDomElement).each(function() {
					$(this).css("opacity", l_nMaxOpacity);
				});
			}

			$(this._xBtnExpand).css("backgroundPosition", "0px -44px");			
			$(this._xBtnExpand).addClass("expanded");

			$(this._xDomElement).removeClass("collapsed");
			$(this._xDomElement).addClass("expanded");
		}
		else {
			$(this._xDomElement).css("height", this._nCollapsedHeight);

			if (this._bAllowOpacityFade) {
				$(".item-row:gt(0)", this._xDomElement).each(function() {
					$(this).css("opacity", 0);
				});
			}

			$(this._xBtnExpand).css("backgroundPosition", "0px 0px");			
			$(this._xBtnExpand).removeClass("expanded");

			$(this._xDomElement).removeClass("expanded");
			$(this._xDomElement).addClass("collapsed");
		}
	}
	else {
		if (p_bDoExpand) {
			$(this._xDomElement).animate({ height: this._nExpandedHeight }, 300);

			if (this._bAllowOpacityFade) {
				$(".item-row:gt(0)", this._xDomElement).each(function() {
					$(this).animate({ opacity: l_nMaxOpacity }, 300);
				});
			}
			
			$(this._xBtnExpand).css("backgroundPosition", "0px -44px");			
			$(this._xBtnExpand).addClass("expanded");

			$(this._xDomElement).removeClass("collapsed");
			$(this._xDomElement).addClass("expanded");
		}
		else {
			$(this._xDomElement).animate({ height: this._nCollapsedHeight }, 300);

			if (this._bAllowOpacityFade) {
				$(".item-row:gt(0)", this._xDomElement).each(function() {
					$(this).animate({ opacity: 0 }, 300);
				});
			}
			
			$(this._xBtnExpand).css("backgroundPosition", "0px 0px");			
			$(this._xBtnExpand).removeClass("expanded");

			$(this._xDomElement).removeClass("expanded");
			$(this._xDomElement).addClass("collapsed");
		}
	}
	this._bIsExpanded = p_bDoExpand;
}


/**
 * Initializes the dynamic behavior of this ModuleBox. This includes buttons and animations.
 */
DrPepper.ModuleBox.prototype.setupBehavior = function()
{
	$(".item", this._xDomElement).each(function() {
		
		// Fetch item metadata
		var l_xMetaData = $(".meta-data", this);
		var l_nLinkType = parseInt($(".link-type", l_xMetaData).text());		

		if (l_nLinkType == DrPepper.Site.LINKTYPE_VIDEO) {
			// VideoModuleBoxItem
			var l_sApplicationUrl = $(".application-url", l_xMetaData).text();
			var l_sActionUrl = $(".action-url", l_xMetaData).text();
			var l_sStillUrl = $(".still-url", l_xMetaData).text();
			var l_sCategoryTitle = $(".category-title", l_xMetaData).text();
			var l_sTitle = $(".title", l_xMetaData).text();
			var l_sAddedDate = $(".added-date", l_xMetaData).text();
			var l_sLinkId = $(".link-id", l_xMetaData).text();

			$(this).click(function()
				{
					// History tracking currently only for VIDEO items
					if (DrPepper.ModuleBox._bIsTrackingHistory) {
						if (!DrPepper.ModuleBox._bIsAutoTriggering) {
							// Only change hash if we're not currently browsing history 
							DrPepper.ModuleBox._bIsAutoTriggering = false;
							DrPepper.ModuleBox._bIsManuallyTriggering = true;
							SWFAddress.setValue("/" + l_sLinkId);	
						}
					}
					DrPepper.Site.performLinkAction({ linkType: l_nLinkType, url: l_sActionUrl, applicationUrl: l_sApplicationUrl, stillUrl: l_sStillUrl, categoryTitle: l_sCategoryTitle, title: l_sTitle, addedDate: l_sAddedDate });
				}
			);
			
			// Hovering over the item will highlight its caption
			$(this).hover(
				function() { $(".caption", this).addClass("hover"); },
				function() { $(".caption", this).removeClass("hover"); }
			);		
		}
		else {
			// All other item types...
			
			var l_aActionUrls = [];
			var l_aLinkIds = [];
			$(".action-url", l_xMetaData).each(function() {
				l_aActionUrls.push($(this).text());
			});

			if (l_aActionUrls.length == 1) {
				// Only one action URL: SimpleModuleBoxItem
				$(this).click(function() {
					DrPepper.Site.performLinkAction({ linkType: l_nLinkType, url: l_aActionUrls[0] });
				});

				// Hovering over the item will highlight the caption
				$(this).hover(
					function() { $(".caption", this).addClass("hover"); },
					function() { $(".caption", this).removeClass("hover"); }
				);
			}
			else {
				// Multiple action URLs: MultiLinkModuleBoxItem
				
				// Add a click handler to each of the action links inside the item
				$(".action-link", this).each(
					function(l_nIndex) {
						$(this).click(
							function(e) {
								DrPepper.Site.performLinkAction({ linkType: l_nLinkType, url: l_aActionUrls[l_nIndex] });
								// Stop click event propagation in case the containing item's click handler invoked us
								e.stopPropagation();
								return false;
							}
						)
					}
				);
				
				// Add an extra click handler to the item itself, which will invoke the click handler of the contained action link
				// that currently holds the hover focus
				$(this).click(function(e) {
					$(".action-link", this).each(function(l_nIndex) {
						if ($(this).hasClass("hover")) {
							$(this).click();
						}
					});
				});

				// Hovering over the item will highlight the caption and the first action link
				$(this).hover(
					function() { $(".caption", this).addClass("hover"); $(".action-link:eq(0)", this).addClass("hover"); },
					function() { $(".caption", this).removeClass("hover"); $(".action-link", this).removeClass("hover"); }
				);
				
				// Hovering over one of the action links will highlight that action link and turn off the highlight for all other action links
				$(".action-link", this).hover(
					function() { $(this).addClass("hover"); $(this).siblings(".action-link").removeClass("hover"); },
					function() { $(this).removeClass("hover"); $(this).siblings(".action-link:eq(0)").addClass("hover"); }
				);
			}
		}
	});

	
	// Set up expand and collapse handlers
	//
	// Only show the expand/collapse button if there are at least two rows
	if (this._nRowCount > 1) {
		
		$(this._xBtnExpand).css("display", "block");


		// NOTE!!! Hover handling would normally entail adding/removing a "hover" class
		// (considering that the :hover pseudoclass would require the user to move the mouse after clicking,
		// in order to update the button state again). HOWEVER, IE6 has a CSS bug where .button.expanded.hover
		// replaces .button.hover (as opposed to being viewed as a different state). Therefore, the following
		// code sets backgroundPosition manually.
		// 
		var l_xExpandableModule = this;
		$(this._xBtnExpand).click(function() {
			l_xExpandableModule.expand(!l_xExpandableModule._bIsExpanded, false);

			if (l_xExpandableModule._bIsExpanded) {
				$(this).css("backgroundPosition", "0px -44px");
			}
			else {
				$(this).css("backgroundPosition", "0px 0px");
			}
		});
		
		$(this._xBtnExpand).hover(
			function() {
				if (l_xExpandableModule._bIsExpanded) {
					$(this).css("backgroundPosition", "0px -66px");
				}
				else {
					$(this).css("backgroundPosition", "0px -22px");
				}
			},
			function() {
				if (l_xExpandableModule._bIsExpanded) {
					$(this).css("backgroundPosition", "0px -44px");
				}
				else {
					$(this).css("backgroundPosition", "0px 0px");
				}
			}
		);
	}
	
	// Calculations for expansion and contraction
	//
	var l_xRowContainer = $(".row-container", this._xDomElement);
	var l_nFirstRowHeight = 0;
	
	if (this._nRowCount > 0) {
		//
		// rows exist, so calculate the height of one individual row,
		// as well as the height of the full row container with all rows
		//
		var l_xFirstRow = $(".item-row:eq(0)", this._xDomElement);
		l_nFirstRowHeight = $(l_xFirstRow).height();
	}

	// Remember the collapsed and expanded heights to handle expand button clicks
	this._nCollapsedHeight =
		l_nFirstRowHeight +
		parseInt($(l_xRowContainer).css("marginTop")) +
		parseInt($(l_xRowContainer).css("marginBottom"));
		
	this._nExpandedHeight =
		$(l_xRowContainer).height() +
		parseInt($(l_xRowContainer).css("marginTop")) +
		parseInt($(l_xRowContainer).css("marginBottom"));

	$(this._xDomElement).css("height", this._nCollapsedHeight);

	// Make sure all items are the same height as all other items in the same row, so that hover behavior
	// will be consistent
	//
	$(".item-row", this._xDomElement).each(function() {
		var l_nMaxItemHeight = 0;

		var items = $(".item", this);		
		$(items).each(function() {
			if ($(this).height() > l_nMaxItemHeight) l_nMaxItemHeight = $(this).height();
		});
		$(items).each(function() {
			$(this).height(l_nMaxItemHeight);
		})
	});

}


/**
 * Triggers the item with the specified link-id meta-data attribute
 *
 * @param	p_sLinkId	Link ID of the item to be triggered
 * @return				true, if item was successfully triggered
 */
DrPepper.ModuleBox.triggerItemByLinkId = function(p_sLinkId)
{
	var l_xItem = null;
	var l_nLinkType;
	
	if ((p_sLinkId != null) && (p_sLinkId != "")) {
		//
		// If a link ID has been specified, find the item that it belongs to, if possible
		//
		$(".module-box .item .meta-data .link-id").each(function() {
			if ($(this).text() == p_sLinkId) {
				l_xItem = $(this).parent().parent();
			}
		});
	}

	
	if (l_xItem && ($(l_xItem).length > 0)) {
		//
		// If the item link exists, trigger it and inform the caller accordingly
		//
		if (DrPepper.ModuleBox._bIsTrackingHistory) {
			DrPepper.ModuleBox._bIsAutoTriggering = true;
			DrPepper.ModuleBox._bIsManuallyTriggering = false;
		}
		$(l_xItem).click();
		if (DrPepper.ModuleBox._bIsTrackingHistory) {
			DrPepper.ModuleBox._bIsAutoTriggering = false;
		}
		return true;			
	}
	else {
		//
		// Otherwise, tell the caller that triggering failed
		//
		return false;
	}
}


/**
 * Triggers the first item on the page
 **/
DrPepper.ModuleBox.triggerFirstItem = function()
{
	var l_xFirstItem = $(".module-box:eq(0) .item:eq(0)"); 

	if (l_xFirstItem.length > 0) {
		if (DrPepper.ModuleBox._bIsTrackingHistory) {
			// Ensure that hash will not remain empty
			DrPepper.ModuleBox._bIsAutoTriggering = false;
		}
		$(l_xFirstItem).click();
	}
}


/**
 * Initiates history handling for all ModuleBoxes on the current page.
 **/
DrPepper.ModuleBox.followHistoryUpdates = function()
{
	DrPepper.ModuleBox._bIsTrackingHistory = true;
	SWFAddress.addEventListener(SWFAddressEvent.CHANGE, DrPepper.ModuleBox.historyChangeHandler);

	var l_sHash = SWFAddress.getPath().substr(1);
	if (l_sHash == "") {
		DrPepper.ModuleBox.triggerFirstItem();
	}
	else {
		DrPepper.ModuleBox.triggerItemByLinkId(l_sHash);
	}
}


/**
 * If URL hash changes, trigger the appropriate ModuleBox item link
 **/
DrPepper.ModuleBox.historyChangeHandler = function(p_xEvent)
{
	// This callback is invoked every time the hash updates. This is also the case when the user clicks on an item link.
	// In that case, do not trigger the item again. (Item link click handler sets _bIsManuallyTriggering flag).
	//
	if (DrPepper.ModuleBox._bIsManuallyTriggering) {
		DrPepper.ModuleBox._bIsManuallyTriggering = false;
		return;
	}

	// Otherwise, this is a legitimate history update, so trigger the item indicated by hash.
	//
	var l_sLinkId = p_xEvent.value.substr(1);
	if (l_sLinkId == "") {
		DrPepper.ModuleBox._bIsTrackingHistory = false;
		DrPepper.ModuleBox.triggerFirstItem();
		DrPepper.ModuleBox._bIsTrackingHistory = true;
	}
	else {
		DrPepper.ModuleBox.triggerItemByLinkId(l_sLinkId);
	}
}
