// --------------------------------------------------------------------------
// Extensions
//

(function() {

// String
var __RE_trim	= /^\s+|\s+$/g;
String.prototype.trim				= function() { return this.replace(__RE_trim, ''); };

// Array
Array.prototype.clone				= function() { return this.slice(0); };
Array.prototype.empty				= function() { this.length = 0; };
Array.prototype.removeIndex			= function(p_nI) { return this.slice(p_nI, 1)[0]; };
Array.prototype.removeItemsByValue	= function(p_v) { var nCounter = 0; for (var nI = 0, nL = this.length; nI < nL; nI++) { if (this[nI] == p_v) this.removeIndex(nI--); } };
Array.prototype.sortByProperty		= function(property, rev) { var fn = function(a, b) { if (a[property] < b[property]) { return (rev)? 1 : -1; } else if (a[property] > b[property]) { return (rev)? -1 : 1; } else return 0; }; this.sort(fn); return this;};
Array.prototype.reverse				= function() { var a = [], nI = this.length; while (nI--) a.push(this[nI]); return a; };
Array.prototype.rnd					= function() { var a = this.clone(), nL = a.length, aRnd = []; while (aRnd.length < nL) { aRnd.push(a.splice(Math.getRnd(0, a.length - 1), 1)[0]); } return aRnd; };

// Number
Number.GUID							= function() { var aGUID =	[]; for (var nI = 0; nI < 32; nI++) { aGUID.push(Math.floor(Math.random() * 0xF).toString(0xF)); } return aGUID.join(''); };

// Math
Math.getRnd							= function(nMn, nMx) { if (!isNaN(nMn)) { if (!isNaN(nMx)) { nMx -= nMn; } else { nMx = nMn, nMn = 0; } } else { nMn = 0, nMx = 100; } return Math.round(Math.random() * (nMx - nMn)) + nMn; };
})();


// ---------------------------------------------
// CLASS: GridCell
function GridCell(p_oElm, p_nRowPosition, p_nColumnPosition, p_nCellPosition)
{
	this.id			= p_oElm.id;
	this.top		= 0;	// calculate later
	this.left		= p_oElm.offsetLeft		|| 0;
	this.width		= p_oElm.offsetWidth	|| 0;
	this.height		= p_oElm.offsetHeight	|| 0;
	
	this.position	= p_nCellPosition	|| 1;
	this.row		= p_nRowPosition	|| 1;
	this.column		= p_nColumnPosition	|| 1;
	
	this.colSpan	= 1;	// calculate later
	
	this.positionsAbove = [];
	this.positionsBelow = [];
	
	GridCell.positions[String(this.position)]	= this;
	GridCell.instances.push(this);
	
	return this;
}
GridCell.instances			= [];
GridCell.positions			= {};
GridCell.columnCount		= (typeof(eventCols) == 'number')? eventCols : 3;
GridCell.rowCount			= (typeof(eventRows) == 'number')? eventRows : 10;
GridCell.cellCount			= (GridCell.columnCount * GridCell.rowCount);
GridCell.lastRow			= 0;
// Static methods
GridCell.getByPosition		= function(p_nPosition) { return GridCell.positions[String(p_nPosition)] || null; };
GridCell.getByRow			= function(p_nRow)
{
	var aCellsInRow	= [];
	// Loop backwards through cells and
	for (var
		nCellIndex		= (GridCell.instances.length - 1),
		nCellLoopEnd	= 0,
		oCell;
		nCellIndex		>= nCellLoopEnd;
		nCellIndex--)
	{
		oCell	= GridCell.instances[nCellIndex];
		if (oCell.row == p_nRow) aCellsInRow.push(oCell);
	}
	
	return aCellsInRow;
};
GridCell.foundAllColumnsInRow	= function(p_oColumns)
{
	var bFoundAllColumnsInRow	= true;
	for (var sColumn in p_oColumns)
	{
		if (p_oColumns[sColumn] == false)
		{
			bFoundAllColumnsInRow	= false;
			break;
		}
	}
	return bFoundAllColumnsInRow;
};


// Instance methods
GridCell.prototype.getElm		= function() { return document.getElementById(this.id) || null; };
GridCell.prototype.getTop		= function() { return this.getElm().offsetTop || 0; };
// Fit the cell above, whether having to move the cell up or down
GridCell.prototype.fitCellAbove	= function()
{
	//alert(this.id + ' - CellsAbove: ' + this.positionsAbove)
	for (var
		nI			= 0,
		nL			= this.positionsAbove.length,
		oCellAbove, nLowestBottom, nCellTop = this.top;
		nI			< nL;
		nI++)
	{
		oCellAbove		= GridCell.getByPosition(this.positionsAbove[nI]);
		nLowestBottom	= (oCellAbove.top + oCellAbove.height);
		
		if (nCellTop < nLowestBottom)
		{
			nCellTop	= nLowestBottom;
		}
	}
	
	if (this.top < nCellTop)
	{
		this.top				= nCellTop;
		this.getElm().style.top	= nCellTop + 'px';
	}
};
// Always expand - Never shrink the cell
GridCell.prototype.expandCellDown	= function()
{
	//alert(this.id + ' - ' + this.positionsBelow.length)
	var nCellBottom	= (this.top + this.height);
	for (var
		nI			= 0,
		nL			= this.positionsBelow.length,
		nHighestTop	= nCellBottom,
		oCellBelow;
		nI			< nL;
		nI++)
	{
		oCellBelow		= GridCell.getByPosition(this.positionsBelow[nI]);
		if (nHighestTop < oCellBelow.top)
		{
			nHighestTop	= oCellBelow.top;
		}
	}

	if (nHighestTop > nCellBottom)
	{
		this.height					= (nHighestTop - this.top);
		this.getElm().style.height	= this.height + 'px';
	}
};

// ---------------------------------------------
// STATIC CLASS: GridManager
window.GridManager	=
{
	init	: function()
	{
		// Loop through all cells, and if an associated element exists, create a GridCell object to determine left, width, and height of cell
		
		// Loop through rows
		for (var
			nRowPosition = 1, nColumnPosition = 1, nCellPosition = 1,
			oElm, oCell,  oPreceedingCell, nPreceedingCellPosition;
			nRowPosition <= GridCell.rowCount;
			nRowPosition++)
		{
			// Loop through cells in row
			for (nColumnPosition = 1; nColumnPosition <= GridCell.columnCount; nColumnPosition++)
			{
				oElm	= document.getElementById('module' + nCellPosition);
				if (oElm)
				{
					oCell	= new GridCell(oElm, nRowPosition, nColumnPosition, nCellPosition);
					
					if (GridCell.lastRow < oCell.row) GridCell.lastRow = oCell.row;
						
					// In the first row, adjust the cell's top and height to the first cell's top and height
					if (nRowPosition == 1)
					{
						// If we are on the second+ column within the row
						if (nColumnPosition > 1)
						{
							nPreceedingCellPosition	= (nCellPosition - 1);
							oPreceedingCell			= GridCell.getByPosition(nPreceedingCellPosition);
							while (!oPreceedingCell && nPreceedingCellPosition > 0)
							{
								oPreceedingCell = GridCell.getByPosition(--nPreceedingCellPosition);
							}
							if (oPreceedingCell)
							{
								oCell.top		= oPreceedingCell.top;
								oElm.style.top	= oCell.top + 'px';
								if (oCell.height < oPreceedingCell.height)
								{
									oCell.height		= oPreceedingCell.height;
									oElm.style.height	= oCell.height + 'px';
								}
							}
						}
						else // Else, we are on the first column
						{
							oCell.top	= oElm.offsetTop;
						}
					}
				}
				
				// Increment the cell (row->col) position
				nCellPosition++
			}
		}
		
		// Reset the rowCount to the actual number of rows
		GridCell.rowCount	= GridCell.lastRow;
		GridCell.cellCount	= (GridCell.rowCount * GridCell.columnCount);
		
		var oOverallElm	= document.getElementById('overall');
		
		// Loop through cells (row->cell) again, and calculate squish in tight grid
		for (var
			nCellIndex	= 0,
			nCellCount	= GridCell.instances.length,
			oCell, nCellRight/*, oPreviousCell*/, oNextCell,
			nCellAboveRow, bFoundAbove,
			oCellAbove, nCellAbovePos, nCellAboveCount,
			oCellBelow, nCellBelowPos, nCellBelowCount;
			nCellIndex	< nCellCount;
			nCellIndex++)
		{
			oCell	= GridCell.instances[nCellIndex];
			
			// If the cell is on the second+ row
			if (oCell.row > 1)
			{
				nCellRight	= (oCell.left + oCell.width);
				bFoundAbove	= false;
				
				// Loop through elements above and set top of cell to the greatest bottom of the elements above
				nCellAboveRow	= 2;
				nCellAbovePos	= (((oCell.row - nCellAboveRow) * GridCell.columnCount) + 1);
				nCellAboveCount	= (nCellAbovePos + (GridCell.columnCount - 1));
				while (nCellAbovePos <= nCellAboveCount && (oCell.row - nCellAboveRow) >= 0)
				{
					oCellAbove	= GridCell.getByPosition(nCellAbovePos);
					if (oCellAbove
						&& oCellAbove.left < nCellRight
						&& (oCellAbove.left + oCellAbove.width) > oCell.left
					)
					{
						bFoundAbove = true;
						oCell.positionsAbove.push(oCellAbove.position);
					}
					nCellAbovePos++
					// If we have reached the end but have not found a cell above, then reset
					if (!bFoundAbove && nCellAbovePos > nCellAboveCount)
					{
						nCellAbovePos	= (((oCell.row - (++nCellAboveRow)) * GridCell.columnCount) + 1);
						nCellAboveCount	= (nCellAbovePos + (GridCell.columnCount - 1));
					}
				}
				oCell.fitCellAbove();
				
				// If not yet on the last row, expand down (last row is taken care of later)
				if (oCell.row < GridCell.lastRow)
				{
					// Loop through elements below and set height of cell to the top of the elements below
					nCellBelowPos	= ((oCell.row * GridCell.columnCount) + 1);
					nCellBelowCount	= (nCellBelowPos + (GridCell.columnCount - 1));
					while (nCellBelowPos <= nCellBelowCount)
					{
						oCellBelow	= GridCell.getByPosition(nCellBelowPos);
						if (
							oCellBelow
							&& oCellBelow.left < nCellRight
							&& (oCellBelow.left + oCellBelow.width) > oCell.left
						)
						{
							oCell.positionsBelow.push(oCellBelow.position);
						}
						nCellBelowPos++
					}
				}
			}
			
			// Calculate colSpan and following cell position in row
			oNextCell			= GridCell.instances[(nCellIndex + 1)] || null;
			if (oNextCell && oNextCell.row == oCell.row)
			{
				//oCell.followingPositionInRow	= oNextCell.position;
				oCell.colSpan	= (oNextCell.column - oCell.column);
			}
			else
			{
				oCell.colSpan	= (GridCell.columnCount - oCell.column) + 1;
			}
			
			// TODO - Extra logic to check to make sure that the width extends through the colspan
			// if not, cut the col span short
			// HACK (for now) - if the cell extends to the end of the column, the and the right position is less than the width,
			//					decrement the colSpan
			if ((oCell.column + (oCell.colSpan - 1)) == GridCell.columnCount && (oCell.left + oCell.width) < oOverallElm.offsetWidth)
			{
				oCell.colSpan--;
			}
		}
		
		// Loop through all cells to determine the greatest bottom of all the cells
		var nGreatestBottom	= 0;
		for (var
			nCellIndex		= 0,
			nCellLoopEnd	= GridCell.instances.length,
			oCell, nBottom;
			nCellIndex		< nCellLoopEnd;
			nCellIndex++)
		{
			oCell			= GridCell.instances[nCellIndex];
			if (nGreatestBottom < (nBottom = (oCell.top + oCell.height))) nGreatestBottom = nBottom;
		}
		
		// Loop backwards through each row, starting with the last, and then backwards through each row's cells
		// until finding the bottom cell for each column, and then expand to the greatest bottom
		var oFoundColumns	= {};
		for (var nCol = 1; nCol <= GridCell.columnCount; nCol++) oFoundColumns[String(nCol)] = false;
		for (var nRow = GridCell.lastRow, oCell, nHeight, nCol, nCell = GridCell.cellCount; nRow >= 1; nRow--)
		{
			for (nCol = GridCell.columnCount; nCol >= 1; nCol--)
			{
				oCell	= GridCell.getByPosition(nCell);
				if (oCell && oFoundColumns[String(oCell.column)] == false)
				{
					oFoundColumns[oCell.column]	= true;
					nHeight	= (nGreatestBottom - oCell.top);
					if (nHeight > oCell.height)
					{
						oCell.height				= nHeight;
						oCell.getElm().style.height	= nHeight + 'px';
					}
					
					// If this cell spans more than one column, mark thos as found as well
					if (oCell.colSpan > 1)
					{
						nColPos		= (oCell.column + 1);
						while (nColPos <= (oCell.column + (oCell.colSpan - 1)))
						{
							oFoundColumns[String(nColPos)]	= true;
							nColPos++
						}
					}
				}
				nCell--;
			}
			if (GridCell.foundAllColumnsInRow(oFoundColumns)) break;
		}
		
		
		// Loop through cells (row->cell) again, and calculate squish in tight grid
		for (var
			nCellIndex	= 0,
			nCellCount	= GridCell.instances.length,
			oCell, oCellBelow, nCellBelowPos, nCellBelowCount;
			nCellIndex	< nCellCount;
			nCellIndex++)
		{
			oCell	= GridCell.instances[nCellIndex];
			// If not yet on the last row, expand down (last row is taken care of later)
			if (oCell.row > 1 && oCell.row < GridCell.lastRow) oCell.expandCellDown();
		}
		
		// Set the height and top of the overall/footer elements based upon the above calculations
		var oFooterElm	= document.getElementById('footer');
		
		oOverallElm.style.height = nGreatestBottom + 'px';
		if (oFooterElm) oFooterElm.style.top = (oOverallElm.offsetTop + nGreatestBottom) + 'px';
		// Loop through all of the cells and display them
		for (var
			nCellIndex		= 0,
			nCellLoopEnd	= GridCell.instances.length,
			oCell;
			nCellIndex		< nCellLoopEnd;
			nCellIndex++)
		{
			oCell			= GridCell.instances[nCellIndex];
			if (oCell.row > 1)
			{
				oCell.getElm().style.visibility	= 'visible';
			}
		}
		
		// Display the footer element
		if (oFooterElm) oFooterElm.style.visibility	= 'visible';
		
		// Reset static properties of GridCell
		GridCell.lastRow			= 0;
		GridCell.instances			= [];
		GridCell.positions			= {};
	}
};


/* *************************************************
	EDA: GLOBAL
****************************************************/
function event_navigate(p_sEventId, p_sWebPageTypeCd, p_sPubForDate, p_sQS4)
{
	if (typeof(p_sEventId) == 'string' && p_sEventId.length > 0)
	{
		var sUrl	= '/promo-' + p_sEventId;
		if (typeof(p_sWebPageTypeCd) == 'string' && p_sWebPageTypeCd.length > 0)
		{
			sUrl	+= '-' + p_sWebPageTypeCd;
		}
		if (typeof(p_sPubForDate) == 'string' && p_sPubForDate.length > 0)
		{
			sUrl	+= '-' + p_sPubForDate;
		}
		if (typeof(p_sQS4) == 'string' && p_sQS4.length > 0)
		{
			sUrl	+= '-' + p_sQS4;
		}
		top.location.href	= sUrl;
	}
	return false;
}

/* *************************************************
	EDA: PHOTO GALLERY
****************************************************/
function event_photo(p_sEventID, p_sGalleryID, p_sPhotoID)
{
	var sUrl		= '/library/slideshow/default.asp?ev=' + p_sEventID + '&gid=' + p_sGalleryID + '&pid=' + (p_sPhotoID || '');
	window.open(sUrl, 'slideshow', 'width=450,height=700,scrollbars=yes,menubar=no,location=no,resizeable=no,status=no,toolbar=no');
	return false;
}


/* *************************************************
	EDA: POLL
****************************************************/

function pollVote(p_sPollId, p_sContainerElmId)
{
	var sPollUrl	= '';
	try
	{
		if (typeof(p_sPollId) != 'string' || p_sPollId.length === 0)
		{
			throw new Error('Invalid p_sPollId parameter.');
		}
		
		var oForm	= document.forms['poll_form_' + p_sPollId];
		
		if (!oForm || !oForm.elements)
		{
			throw new Error('Form does not exist.');
		}
		
		var sChoice	= '';
		for (var nI = 0, nL = oForm.elements.length, oElm; nI < nL; nI++)
		{
			oElm	= oForm.elements[nI];
			if (oElm.type === 'radio' && oElm.checked)
			{
				sChoice	= oElm.value;
				break;
			}
		}
		
		if (sChoice.length > 0)
		{
			sPollUrl	= 'http://' + location.host + '/eda/poll.asp?poll_id=' + p_sPollId + '&user_choice=' + sChoice + '&GUID=' + Number.GUID();
			pollSendVote(sPollUrl, p_sContainerElmId);
		}
		else
		{
			alert('Please make a selection');
		}
	}
	catch (ex)
	{
		alert('ERROR in pollVote(\'' + p_sPollId + '\', \'' + p_sContainerElmId + '\').\nPoll Url: ' + sPollUrl + '\n' + ex);
	}
	return false;
}
function pollSendVote(sPollUrl, p_sContainerElmId)
{
	var oScript	= document.getElementById('pollScript');
	if (oScript)
	{
		var oParent = oScript.parentNode;
		oParent.removeChild(oScript);
	}
	oScript		= document.createElement('script');
	oScript.setAttribute('id', 'pollScript');
	oScript.setAttribute('src', sPollUrl + '&cid=' + p_sContainerElmId);
	document.getElementsByTagName('head')[0].appendChild(oScript);
}

/* This function is called from a script which is written into the page by the return of poll.asp */
function pollDisplayResults(p_aAnswers, p_sContainerElmId)
{
	if (typeof(eda_customPollFunc) == 'function')
	{
		var bCancel = eda_customPollFunc(p_aAnswers, p_sContainerElmId);
		if (bCancel == true) return true;
	}
	var bDisplayResultsOnPage = !(window.EDA.doNotDisplayPollResults === true);
	var sContainerElmId	= p_sContainerElmId || '';
	if (sContainerElmId.length === 0)
	{
		throw new Error('Invalid sContainerElmId parameter');
	}
	
	var oContainerElm	= document.getElementById(sContainerElmId);
	if (!oContainerElm)
	{
		throw new Error('Container element does not exist.');
	}
	oContainerElm.className		= 'poll_container_results';
	oContainerElm.style.dislpay	= 'none';
	
	for (var nI = 0, aElms = oContainerElm.getElementsByTagName('div'), nL = aElms.length, oElm; nI < nL; nI++)
	{
		oElm	= aElms[nI];
		switch (oElm.className.split(/\s/g)[0])
		{
			case ('eda_cmpt_poll_answer')	:
			{
				oElm.removeChild(oElm.firstChild); // remove radio button
				break;
			}
			case ('poll_vote_button')	:
			{
				//oElm.parentNode.removeChild(oElm); // remove vote button
				oElm.style.visibility = 'hidden'; // hide vote button
				break;
			}
		}
		oElm = null;
	}
	
	if (bDisplayResultsOnPage && p_aAnswers)
	{
		var aResults= [];
		for (var
			nI		= 0, nAnswerIndex = 0,
			aElms	= oContainerElm.getElementsByTagName('*'),
			nL		= aElms.length,
			oElm, oAnswer, sPercent;
			nI < nL; nI++)
		{
			oElm			= aElms[nI];
			if (oElm.className.indexOf('eda_cmpt_poll_answer ') >= 0)
			{
				oAnswer			= p_aAnswers[nAnswerIndex];
				sPercent		= oAnswer.percent;
				aResults.push({elm:oElm, percent:sPercent });
				nAnswerIndex++;
			}
		}
		
		for (var nI = 0, nL = aResults.length, sPercent, oResultsElm, aTd; nI < nL; nI++)
		{
			sPercent	= aResults[nI].percent;
			oResultsElm	= aResults[nI].elm;
			aTd			= oResultsElm.getElementsByTagName('td');
			if (aTd.length)
			{
				aTd[0].innerHTML		+= '<div class="poll_result_bar_container"><div class="poll_result_bar" style="width:' + sPercent + '%;"></div><div class="poll_bar_dropshadow"></div></div><span class="poll_result_percent">' + sPercent + '%</span></div>';
			}
			else
			{
				oResultsElm.innerHTML	+= '<div class="poll_result_bar_container"><div class="poll_result_bar" style="width:' + sPercent + '%;"></div><div class="poll_bar_dropshadow"></div></div><span class="poll_result_percent">' + sPercent + '%</span></div>';
			}
			oResultsElm.className		+= ' poll_result_text_container';
		}
		
		oContainerElm.style.dislpay	= 'block';
		
		if(typeof(noArrange) == "undefined")
		{
		    arrangeItems();
		}
	}
	else
	{
		var sThankYouUrl = 'http://' + location.host + '/eda/common/vote_thank_you.asp?eventID=' + window.EDA.eventID;
		var sWinFeatures = 'height=147,width=250';
		var oWin = window.open(sThankYouUrl, 'vote_thank_you', sWinFeatures);
		if (oWin == undefined) alert('A pop-up window failed to open. \nIf you have a pop-up blocker, you may want to \nconfigure it to allow pop-ups on this site.');
		oWin = null;
	}
}

/***************************************************
	EDA: TABS
****************************************************/
function tabManager(p_sModuleId)
{
	this.modID				= p_sModuleId;
	this.id					= 'tabsManager_' + p_sModuleId;
	this.selectedPosition	= 1;
	this.tabs				= {};
	
	try
	{
		// Initialize tab elements
		for (var nI = 0, aElms = document.getElementById('module' + p_sModuleId).getElementsByTagName('div'), nL = aElms.length, oElm, RE, aResult, sTabId; nI < nL; nI++)
		{
			oElm	= aElms[nI];
			
			if (oElm && oElm.className && (oElm.className.indexOf('tab_selected') > -1 || oElm.className.indexOf('tab_available') > -1))
			{
				RE		= /(mod_\d*_tab_)(\d*)/;
				aResult	= RE.exec(oElm.parentNode.className);
				if (aResult)
				{
					sTabId	= 'tab' + aResult[2];
					if (!this.tabs[sTabId])
					{
						this.tabs[sTabId]	= { tab:null, content:null };
					}
					
					this.tabs[sTabId].tab	= oElm;
				}
			}
			else if (oElm.className.indexOf('content_selected') > -1 || oElm.className.indexOf('content_available') > -1)
			{
				RE		= /(mod_\d*_contentGroup_)(\d*)/;
				aResult	= RE.exec(oElm.className);
				if (aResult)
				{
					sTabId	= 'tab' + aResult[2];
					if (!this.tabs[sTabId])
					{
						this.tabs[sTabId]	= { tab:null, content:null };
					}
					
					this.tabs[sTabId].content	= oElm;
				}
			}
		}
	}
	catch (ex)
	{
		alert('ERROR initializing tabManager(\'' + p_sModuleId + '\'): ' + ex.description);
	}
	
	return (tabManager.instances[this.id]	= this);
}
tabManager.instances		= {};
tabManager.get				= function(p_sModuleId)
{
	if (!tabManager.instances['tabsManager_' + p_sModuleId])
	{
		tabManager.init(p_sModuleId);
	}
	return tabManager.instances['tabsManager_' + p_sModuleId] || null;
};
tabManager.init				= function(p_sModuleId) { new tabManager(p_sModuleId); };
tabManager.prototype.toggle	= function(p_nPos, p_fCallback)
{
	try
	{
		if (typeof(p_nPos) == 'number' && p_nPos > 0 && p_nPos != this.selectedPosition)
		{
			var oTab;
			oTab					= this.tabs['tab' + this.selectedPosition];
			oTab.tab.className		= String(oTab.tab.className).replace(/tab_selected/, 'tab_available');
			oTab.content.className	= String(oTab.content.className).replace(/content_selected/, 'content_available');
			
			oTab					= this.tabs['tab' + p_nPos];
			oTab.tab.className		= String(oTab.tab.className).replace(/tab_available/, 'tab_selected');
			oTab.content.className	= String(oTab.content.className).replace(/content_available/, 'content_selected');
			
			this.selectedPosition	= p_nPos;
			
			if (typeof(p_fCallback) == 'function')
			{
				p_fCallback(this.modID);
			}
		}
	}
	catch (ex)
	{
	}
	return false;
};

function arrangeItems()
{
	GridManager.init();
}