﻿// ----------------------------------------------
// 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:""}];
	}
	
	var numThumbnails = this.pMaxRows * this.pNumColumns;
	var thumbnailsToPad = numThumbnails - this.productArray.length;

	for (var i = 0; i < thumbnailsToPad; i++)
	{
		this.productArray.push({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()
{
	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 (j >= 3)
			{
				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);
//Debug.windowTrace("columnContentsMarkup id: " + id + " alignment: " + alignment);
	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.largeImg + '\')" 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 += '</td>';
	}
	else
	{
		contents = '<td id="cell' + id + '" class="resultsThumbnailSmall" onclick="productClick(\'' + id + '\');" onmouseover="productMouseover(\'' + id + '\', \'' + escape(productDetails.name) +  '\', \'' + alignment + '\', \'' + productDetails.smallImg + '\')" 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 += '</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, image)
{
//	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 imageHTML = '<div class="toolTipImage"><a href="javascript:handleViewDetails(\'' + id + '\');"><img src="' + image + '" width="140" height="140" /></a></div>';
	var textHTML = '<div class="toolTipText"><div class="toolTipTitle"><span>' + name + '</span></div>';
	textHTML += '<ul class="blueBulletList">';
	textHTML += '<li class="bullet"><a href="javascript:handleViewDetails(\'' + id + '\');">' + LABEL_VIEW_DETAILS + '</a></li>';
	textHTML += '<li class="bullet"><a href="javascript:handleAddImage(\'' + id + '\');">' + LABEL_ADD_IMAGE + '</a></li>';
	textHTML += '</ul>';
	textHTML += '<div id="addImageResultsHolder" style="display:none"><span>' + LABEL_ADD_IMAGE_RESULTS + '</span></div>';
	textHTML += '<div id="addImageErrorHolder" style="display:none"><span>' + LABEL_ADD_IMAGE_ERROR + '</span></div></div>';

	
	contents = '<div class="toolTipContents">';
	if (alignment == "right")
	{
		contents += textHTML;
		contents += imageHTML;
	}
	else
	{
		contents += imageHTML;
		contents += textHTML;
	}
	contents += '</div>';

//Debug.windowTrace("productToolTipInstance.isVisible: " + productToolTipInstance.isVisible + " contents != productToolTipInstance.getContents(): " + (contents != productToolTipInstance.getContents()));

//	if (productToolTipInstance.isVisible == false || contents != productToolTipInstance.getContents())
//	{
		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);});
	
		if (alignment == "right")
		{
			productToolTipInstance.showToolTip(contents, tdPosition.left-160, tdPosition.top-10, alignment, id);
		}
		else
		{
			productToolTipInstance.showToolTip(contents, tdPosition.left-10, tdPosition.top-10, alignment, id);
		}
//	}
}

// ----------------------------------------------
// 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)
{
//	Debug.windowTrace("productMouseout id: " + id + " visible: " + productToolTipInstance.isVisible);
	// If the tooltip is already opened, it will take care of the mouse out event
	if (productToolTipInstance.isVisible == false)
	{
		productMouseoutFollowup(id, 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);
	handleViewDetails(id);
}

// ----------------------------------------------
// 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;
}
