﻿// ----------------------------------------------
// File:		ProductGrid.js
// Author:		Nathan Derksen
// Description:	Visual component for laying out products in a grid
// Example:
// var prodGrid = new ProductGrid(document.getElementById("resultsHolder"));
// prodGrid.setProducts(resultArray);
// prodGrid.drawGrid();
// ----------------------------------------------

// Keep track of which images have completely loaded
loadedMouseOverImages = new Object();
loadedMouseOutImages = new Object();

lastMouseoverId = "";

productToolTipInstance = "";

// ----------------------------------------------
// Function:	ProductGrid()
// Author:		Nathan Derksen
// Description:	Base class
// Inputs:		<DOMElement> containerElement: The DOM element to act as a holder for
//					the HTML generated by this component.
// Returns:		<Nothing>
// ----------------------------------------------
function ProductGrid(containerElement)
{
	this.containerElement = containerElement;
	this.gridType = "topLeftBottomRight";
	this.productArray = [];

	this.pNumColumns = 6;
	this.pMaxRows = 3;
	
	// Keep track of how many items each row type is capable of displaying
	this.pRowSizes = new Object();
	this.pRowSizes["bigLeftSmallRight"] = 5;
	this.pRowSizes["bigLeftNoRight"] = 3;
	this.pRowSizes["smallLeftBigRight"] = 5;
	this.pRowSizes["smallLeftNoRight"] = 4;
	this.pRowSizes["noLeftBigRight"] = 3;
	this.pRowSizes["noLeftSmallRight"] = 4;
	this.pRowSizes["allSmall"] = 6;
	
	this.pRowOrdering = new Object();
	this.pRowOrdering["topLeftBottomRight"] = [0, 2, 3, 4, 5, 6, 7, 1, 8, 9, 10, 11];
	this.pRowOrdering["topLeft"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
	this.pRowOrdering["bottomLeftTopRight"] = [2, 3, 4, 5, 1, 0, 6, 7, 8, 9, 10, 11];
	this.pRowOrdering["uniform"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];

	if (typeof(ToolTip) != "undefined")
	{
		productToolTipInstance = ToolTip.getInstance();
	}
}

// ----------------------------------------------
// Function:	ProductGrid.setProducts()
// Author:		Nathan Derksen
// Description:	Assign a list of products to show in the grid
// Inputs:		<Array> productArray: The list of products to use, each array element is
//					one object holding properties for one product
// Returns:		<Nothing>
// ----------------------------------------------
ProductGrid.prototype.setProducts = function(productArray)
{
	if (productArray)
	{
		if (productArray.length > 0)
		{
			this.productArray = productArray;
		}
		else
		{
			this.productArray = [{id:"", name:"", price:0, qs:""}];
		}
	}
	else
	{
		this.productArray = [{id:"", name:"", price:0, qs:""}];
	}

	this.drawGrid();	
};

// ----------------------------------------------
// ----------------------------------------------
ProductGrid.prototype.setToolTip = function(toolTipInstance)
{
	productToolTipInstance = toolTipInstance;
}

// ----------------------------------------------
// ----------------------------------------------
ProductGrid.prototype.setNumColumns = function(numColumns)
{
	this.pNumColumns = numColumns;

	// Keep track of how many items each row type is capable of displaying
	this.pRowSizes["bigLeftSmallRight"] = this.pNumColumns - 1;
	this.pRowSizes["bigLeftNoRight"] = this.pNumColumns - 3;
	this.pRowSizes["smallLeftBigRight"] = this.pNumColumns - 1;
	this.pRowSizes["smallLeftNoRight"] = this.pNumColumns - 2;
	this.pRowSizes["noLeftBigRight"] = this.pNumColumns - 3;
	this.pRowSizes["noLeftSmallRight"] = this.pNumColumns - 2;
	this.pRowSizes["allSmall"] = this.pNumColumns;
};

// ----------------------------------------------
// Function:	ProductGrid.setGridType()
// Author:		Nathan Derksen
// Description:	Sets the layout rule to apply to this product grid
// Inputs:		<String> gridType: The kind of layout to use for this list of products. Options:
//					"topLeftBottomRight", "bottomLeftTopRight", "topLeft", and "uniform".
// Returns:		<Nothing>
// ----------------------------------------------
ProductGrid.prototype.setGridType = function(gridType)
{
	this.gridType = gridType;
};

// ----------------------------------------------
// Function:	ProductGrid.drawGrid()
// Author:		Nathan Derksen
// Description:	Redraw the HTML that lays out the product grid
// Inputs:		<None>
// Returns:		<Nothing>
// ----------------------------------------------
ProductGrid.prototype.drawGrid = function()
{
	loadedMouseOverImages = new Object();
	loadedMouseOutImages = new Object();

	var gridType = this.gridType;
	// If less than 8 items in list, override layout but do not change setter value
	if (this.productArray.length < 8 && gridType.toLowerCase() != "uniform")
	{
		gridType = "topLeft";
	}
	
	switch(gridType.toLowerCase())
	{
		case "topleftbottomright":
			this.drawGridType("topLeftBottomRight");
			break;
		case "bottomlefttopright":
			this.drawGridType("bottomLeftTopRight");
			break;
		case "topleft":
			this.drawGridType("topLeft");
			break;
		default:
			this.drawGridType("uniform");
			break;
	}
};

// ----------------------------------------------
// Function:	ProductGrid.drawGridType() (PRIVATE)
// Author:		Nathan Derksen
// Description:	Split up grid into sections of 12. The grid works in units of self-contained
//				units of 12, so it's easier to work with the display logic of 12 at a time
// Inputs:		<String> gridType - The type of layout to use
// Returns:		<Nothing>
// ----------------------------------------------
ProductGrid.prototype.drawGridType = function(gridType)
{
	var numSections = Math.ceil(this.productArray.length / 12);
	var componentMarkup = '<table cellpadding="0" cellspacing="10">';
	for (var i=0; i < numSections; i++)
	{
		componentMarkup += this.drawGridSection(i*12, gridType);
	}
	componentMarkup += '</table>';
	this.containerElement.innerHTML = componentMarkup;
};

// ----------------------------------------------
// Function:	ProductGrid.drawGridSection() (PRIVATE)
// Author:		Nathan Derksen
// Description:	Figure out actual HTML, based on layout rule
// Inputs:		<Number> startIndex: The index in the product array to use as a starting point
//				<String> layoutType: The type of layout to use
// Returns:		<Nothing>
// ----------------------------------------------
ProductGrid.prototype.drawGridSection = function(startIndex, layoutType)
{
	var numRows = 3;
	var numItems = numRows * this.pNumColumns - 6;
	
	// There are not enough items to fill a full grid (max 12)
	if (startIndex + numItems >= this.productArray.length)
	{
		numItems = this.productArray.length - startIndex;
	}

	if (startIndex == 0)
	{
		// Showing the first block of 12 products
		if (numItems < 8 && layoutType != "uniform")
		{
			// If 8 or less products shown, use the topLeft layout type
			layoutType = "topLeft";
		}
		else if (layoutType == "uniform")
		{
			numRows = Math.ceil(numItems / this.pNumColumns);
		}
	}
	else
	{
		if (numItems < numRows * this.pNumColumns - 6)
		{
			layoutType = "uniform";
		}
		
		// Showing any subsequent block of 12 products
		if (layoutType == "uniform")
		{
			numRows = Math.ceil(numItems / this.pNumColumns);
		}
	}
	
	if (this.pMaxRows > 0 && this.pMaxRows < numRows)
	{
		numRows = this.pMaxRows;
	}

	// Each row needs a layout rule. If more than three rows displayed, loop back to beginning
	var rowStructure = new Array();
	rowStructure[0] = "bigLeftSmallRight";
	rowStructure[1] = "noLeftBigRight";
	rowStructure[2] = "smallLeftNoRight";
	
	// Set layout rules for each row according to overall layout rule
	switch(layoutType.toLowerCase())
	{
		case "topleftbottomright":
			break; // default
		case "bottomlefttopright":
			rowStructure[0] = "smallLeftBigRight";
			rowStructure[1] = "bigLeftNoRight";
			rowStructure[2] = "noLeftSmallRight";
			break;
		case "topleft":
			rowStructure[0] = "bigLeftSmallRight";
			rowStructure[1] = "noLeftSmallRight";
			rowStructure[2] = "allSmall";
			break;
		case "uniform":
			rowStructure[0] = "allSmall";
			rowStructure[1] = "allSmall";
			rowStructure[2] = "allSmall";
			break;
	}
	
	var currentItem = 0;
	var currentItemTranslated = 0;
	var rowPosition = 0;
	var currentRow = 0;
	var isBig;
	var rowType = rowStructure[0];
	var rowSize = 0;
	var componentMarkup = '';
	var alignment = "left";

	// Lay out the products for this group of 12
	for (var i=0; i < numRows; i++)
	{
		rowType = rowStructure[i % 3];
		rowSize = this.pRowSizes[rowType];
		componentMarkup += this.rowStartMarkup();
		for (var j=0; j < rowSize; j++)
		{
			currentItemTranslated = this.pRowOrdering[layoutType][currentItem];
			isBig = this.isCellBig(rowType, j);
			componentMarkup += this.columnStartMarkup(isBig, this.getProductId(currentItemTranslated+startIndex));
			alignment = "left";
			if ( ((rowType=="allSmall" || rowType=="smallLeftBigRight" || rowType=="smallLeftNoRight") && j >= 3) 
			  ||((rowType=="bigLeftSmallRight" ||  rowType=="bigLeftNoRight")  && j >= 2)
			  || ((rowType=="noLeftBigRight" || rowType=="noLeftSmallRight") && j >= 1) )
			{
				alignment = "right";
			}
			if (currentItem < numItems)
			{
				componentMarkup += this.columnContentsMarkup(isBig, this.getProductId(currentItemTranslated+startIndex), currentItemTranslated+startIndex, alignment);
			}
			else
			{
				componentMarkup += this.columnContentsMarkup(isBig, "", -1, alignment);
			}
			componentMarkup += this.columnEndMarkup(isBig);
			currentItem++;
		}
		componentMarkup += this.rowEndMarkup();
	}
	return componentMarkup;
};

// ----------------------------------------------
// Function:	getProductId()
// Author:		Nathan Derksen
// Description:	Get the product id for a particular index in the product array
// Inputs:		<Number> index - The zero-based index of the product of interest
// Returns:		<String>
// ----------------------------------------------
ProductGrid.prototype.getProductId = function(index)
{
	var id = "";
	if (index < this.productArray.length)
	{
		return this.productArray[index].id;
	}
	return id;
};

// ----------------------------------------------
// ----------------------------------------------
ProductGrid.prototype.getProduct = function(index)
{
	if (index < this.productArray.length)
	{
		return this.productArray[index];
	}
	return null;
};

// ----------------------------------------------
// Function:	isCellBig()
// Author:		Nathan Derksen
// Description:	Find out if a particular table cell is a large one or a small one
// Inputs:		<String> rowType - The type of table row currently being looked at: bigLeftSmallRight, bigLeftNoRight
//						smallLeftBigRight, smallLeftNoRight, noLeftBigRight, noLeftSmallRight, and allSmall.
//				<Number> rowPosition - The index of the TD cell to be examined in the current row
// Returns:		<Boolean>
// ----------------------------------------------
ProductGrid.prototype.isCellBig = function(rowType, rowPosition)
{
	var isBig = false;
	switch (rowType)
	{
		case "bigLeftSmallRight":
			if (rowPosition == 0)
			{
				isBig = true;
			}
			break;
		case "bigLeftNoRight":
			if (rowPosition == 0)
			{
				isBig = true;
			}
			break;
		case "smallLeftBigRight":
			if (rowPosition == this.pNumColumns-2)
			{
				isBig = true;
			}
			break;
		case "smallLeftNoRight":
			break;
		case "noLeftBigRight":
			if (rowPosition == this.pNumColumns-4)
			{
				isBig = true;
			}
			break;
		case "noLeftSmallRight":
			break;
		case "allSmall":
			break;
	}
	return isBig;
};

// ---------------------------------------------
// ---------------------------------------------
ProductGrid.prototype.rowStartMarkup = function()
{
	return "<tr>";
};

// ---------------------------------------------
// ---------------------------------------------
ProductGrid.prototype.rowEndMarkup = function()
{
	return "</tr>";
};

// ---------------------------------------------
// ---------------------------------------------
ProductGrid.prototype.columnStartMarkup = function(isBig, id)
{
	return "";
};

// ---------------------------------------------
// ---------------------------------------------
ProductGrid.prototype.columnEndMarkup = function(isBig)
{
	return "</td>";
};

// ---------------------------------------------
// ---------------------------------------------
ProductGrid.prototype.columnContentsMarkup = function(isBig, id, index, alignment)
{
	var contentsHTML = "";
	var flashVars = "";
	var productDetails = this.getProduct(index);

	if (id == "")
	{
		if (isBig == true)
		{
			contents = '<td rowspan="2" colspan="2" class="resultsThumbnailBig imageNotHere" id="cell' + id + '" >&nbsp;</td>';
		}
		else
		{
			contents = '<td class="resultsThumbnailSmall imageNotHere">&nbsp;</td>';
		}
	}
	else if (typeof(id) == "undefined")
	{
		if (isBig == true)
		{
			contents = '<td rowspan="2" colspan="2" class="resultsThumbnailBig" id="cell' + id + '" >&nbsp;</td>';
		}
		else
		{
			contents = '<td class="resultsThumbnailSmall">&nbsp;</td>';
		}
	}
	else if (isBig == true)
	{
		contents = '<td id="cell' + id + '" rowspan="2" colspan="2" class="resultsThumbnailBig" onclick="productClick(\'' + id + '\');" onmouseover="productMouseover(\'' + id + '\', \'' + escape(productDetails.name) +  '\', \'' + alignment + '\', \'' + productDetails.price + '\', \'' + productDetails.largeOverImg + '\', ' + productDetails.isGroup+','+ productDetails.isPurchaseable+ ', true)" onmouseout="productMouseout(\'' + id + '\', \'' + productDetails.largeImg + '\')" onfocus="this.blur()" style="cursor:pointer;">';
		contents += '<img id="img' + id + '" src="' + productDetails.largeImg + '" width="290" height="290" onload="revealProduct(\'' + id + '\')" style="visibility:hidden" galleryimg="no" />';
		contents += '<img id="img' + id + 'over" src="' + productDetails.largeOverImg + '" width="290" height="290" onload="overImageLoaded(\'' + id + '\');" style="display:none" />';
		contents += '</td>';
	}
	else
	{
		contents = '<td id="cell' + id + '" class="resultsThumbnailSmall" onclick="productClick(\'' + id + '\');" onmouseover="productMouseover(\'' + id + '\', \'' + escape(productDetails.name) +  '\', \'' + alignment + '\', \'' + productDetails.price + '\', \'' + productDetails.smallOverImg + '\', ' + productDetails.isGroup+','+ productDetails.isPurchaseable+ ')" onmouseout="productMouseout(\'' + id + '\', \'' + productDetails.smallImg + '\')" onfocus="this.blur()" style="cursor:pointer;">';
		contents += '<img id="img' + id + '" src="' + productDetails.smallImg + '" width="140" height="140" onload="revealProduct(\'' + id + '\')" style="visibility:hidden" galleryimg="no" />';
		contents += '<img id="img' + id + 'over" src="' + productDetails.smallOverImg + '" width="140" height="140" onload="overImageLoaded(\'' + id + '\');" style="display:none" />';
		contents += '</td>';
	}
	return contents;
};


// ----------------------------------------------
// ----------------------------------------------
ProductGrid.prototype.getMaxRows = function()
{
	return this.pMaxRows;
};

// ----------------------------------------------
// ----------------------------------------------
ProductGrid.prototype.setMaxRows = function(numRows)
{
	this.pMaxRows = numRows;
};

// ----------------------------------------------
// Function:	overImageLoaded()
// Author:		Nathan Derksen
// Description:	Function called when a particular mouseover image has completed loading
// Inputs:		<String> id - The product ID that corresponds to the current image
// Returns:		<Nothing>
// ----------------------------------------------
function overImageLoaded(id)
{
	loadedMouseOverImages[id] = true;
	var ids = "";
	for (var item in loadedMouseOverImages)
	{
		ids += item + ":";
	}
}

// ----------------------------------------------
// Function:	productMouseover()
// Author:		Nathan Derksen
// Description:	Function to be called by a mouseover event
// Inputs:		<String> id - The id of the relevant product
// Returns:		<Nothing>
// ----------------------------------------------
function productMouseover(id, name, alignment, price, image, isGroup, isPurchaseable, isBig)
{
//	Debug.windowTrace("productMouseover id: " + id);
	var model = ProductModel.getInstance();

	var tdHandle = document.getElementById("cell" + id);
	var outImage = document.getElementById("img" + id);

	var tdPosition = BrowserUtils.getPosition(tdHandle);

//	tdHandle.style.zIndex = 30;
//	outImage.style.zIndex = 30;

	lastMouseoverId = id;
		
	name = unescape(name);
//	price = Formatters.formatPrice(price, locale);
	var imgSize = (isBig)? "290":"140";
	var divImgStyle = (isBig)?"toolTipImageBig":"toolTipImage";
	var imageHTML = '<div class="'+divImgStyle+'" onclick="productClick(\''+id+'\');"><img src="' + image + '" width="'+imgSize+'" height="'+imgSize+'" /></div>';
	var textHTML = '<div class="toolTipText"><div class="toolTipTitle"><span>' + name + '</span></div>';
	if (price != "")
	{
		textHTML += '<div>'+price+'</div>';
	}
	if (isGroup) {
		if (isPurchaseable) {
			textHTML += '<div style="margin-top:14px;margin-bottom:3px;">'+LABEL_TO_PURCHASE+'</div><div class="forwardToLink" style="margin-left:0px">';
		} else {
			textHTML += '<div style="margin-top:14px;margin-bottom:3px;">'+LABEL_TO_SAVE_FOR_LATER+'</div><div class="forwardToLink" style="margin-left:0px">';
		}
	} else {
		textHTML += '<div class="forwardToLink">';
	}
	textHTML += '<a href="javascript:generateEvent(\'onProductSelected\', \''+id+'\')">'+LABEL_VIEW_DETAILS+'</a></div>';
	if (!isGroup && isAjaxEnabled()) {
		textHTML += '<ul class="iconList" style="margin-left:0px">';
		if (shouldPriceBeVisible() && isPurchaseable) {
			textHTML += '<li class="iconPlus"><a href="javascript:handleGridAddItem(\'' + id + '\');">' + LABEL_ADD_TO_BAG + '</a></li>';
		}
		if (locale != 'en-US-EStr') {
			textHTML += '<li class="iconPlus"><a href="javascript:handleGridSaveItem(\'' + id + '\');">' + LABEL_SAVE_FOR_LATER + '</a></li>';
		}
		textHTML += '</ul>';
	}
	textHTML += '</div>';

	contents = '<div class="toolTipContents">';
	if (alignment == "right")
	{
		contents += textHTML;
		contents += imageHTML;
	}
	else
	{
		contents += imageHTML;
		contents += textHTML;
	}
	contents += '</div>';
	
//	if (price == "") { contents = name;}
//	else { contents = name + "<br>" + price; }
//	ToolTip.getInstance().showToolTip(contents);
//Debug.windowTrace("productToolTipInstance.isVisible: " + productToolTipInstance.isVisible + " contents != productToolTipInstance.getContents(): " + (contents != productToolTipInstance.getContents()));
//Debug.windowTrace("isBig="+isBig+";alignment="+alignment);
		productToolTipInstance.hideToolTip();
		// Only show the tooltip if it is not already visible for this product. Can happen when user moves
		// mouse from tooltip back onto image
		productToolTipInstance.setMouseOutHandler(function() {productTooltipMouseoutFollowup(id, image);});
		var leftPos = tdPosition.left-10;
		if (alignment == "right")
		{
			leftPos = leftPos - 150;
		}

		productToolTipInstance.showToolTip(contents, leftPos, tdPosition.top-10, alignment, id, isBig);

	var overImage = document.getElementById("img" + id + "over");
	var outImage = document.getElementById("img" + id);
	if (overImage)
	{
		if (loadedMouseOverImages[id] == true && loadedMouseOutImages[id] == true)
		{
			outImage.onload = null;
			outImage.src = image;
		}
	}
}

// ----------------------------------------------
// Function:	productMouseout()
// Author:		Nathan Derksen
// Description:	Function to be called by a mouseover event
// Inputs:		<String> id - The id of the relevant product
// Returns:		<Nothing>
// ----------------------------------------------
function productMouseout(id, image)
{
//	ToolTip.getInstance().hideToolTip();
	// If the tooltip is already opened, it will take care of the mouse out event
	if (productToolTipInstance.isVisible == false)
	{
		productMouseoutFollowup(id, image);
	}
	
	var model = ProductModel.getInstance();
	var overImage = document.getElementById("img" + id + "over");
	var outImage = document.getElementById("img" + id);
	
	if (overImage)
	{
		if (loadedMouseOverImages[id] == true && loadedMouseOutImages[id] == true)
		{
			outImage.src = image;
		}
	}
}
// ----------------------------------------------
// ----------------------------------------------
function productMouseoutFollowup(id, image)
{
//	Debug.windowTrace("productMouseoutFollowup id: " + id);
	productToolTipInstance.hideToolTip();
	
	var model = ProductModel.getInstance();
	var tdHandle = document.getElementById("cell" + id);
	var outImage = document.getElementById("img" + id);

//	tdHandle.style.zIndex = 10;
//	outImage.style.zIndex = 10;
}

// ----------------------------------------------
// ----------------------------------------------
function productTooltipMouseoutFollowup(id, image)
{
//	Debug.windowTrace("productMouseoutFollowup id: " + id);
	productToolTipInstance.hideToolTipNow();
	
	var model = ProductModel.getInstance();
	var tdHandle = document.getElementById("cell" + id);
	var outImage = document.getElementById("img" + id);

//	tdHandle.style.zIndex = 10;
//	outImage.style.zIndex = 10;
}

// ----------------------------------------------
// Function:	productClick()
// Author:		Nathan Derksen
// Description:	Function to be called by the user clicking on a thumbnail
// Inputs:		<String> id - The id of the relevant product
// Returns:		<Nothing>
// ----------------------------------------------
function productClick(id)
{
	generateEvent("onProductSelected", id);
//	productToolTipInstance.setVisible(true);
}

// ----------------------------------------------
// Function:	revealProduct()
// Author:		Nathan Derksen
// Description:	Function to be called when a thumbnail image has loaded, causes fade in transition
// Inputs:		<String> id - The id of the relevant product
// Returns:		<Nothing>
// ----------------------------------------------
function revealProduct(id)
{
	loadedMouseOutImages[id] = true;
	massFadeInstance.addTarget("img"+id);
	if (id == lastMouseoverId)
	{
		productToolTipInstance.hideToolTip();
	}
}

// ----------------------------------------------
// ----------------------------------------------
function findPosX(obj)
{
	var curleft = 0;
	if(obj.offsetParent)
	{
		while(1) 
		{
			curleft += obj.offsetLeft;
			if(!obj.offsetParent)
			{
				break;
			}
			obj = obj.offsetParent;
		}
	}
	else if(obj.x)
	{
		curleft += obj.x;
	}
	if (document.all)
	{
		curleft += 10;
	}
	return curleft;
}

// ----------------------------------------------
// ----------------------------------------------
function findPosY(obj)
{
	var curtop = 0;
	if(obj.offsetParent)
	{
		while(1)
		{
			curtop += obj.offsetTop;
			if(!obj.offsetParent)
			{
				break;
			}
			obj = obj.offsetParent;
		}
	}
	else if(obj.y)
	{
		curtop += obj.y;
	}
	return curtop;
}
