/* Search Results */

function handleResultOnMouseOver(result)
{
	highlight(result, "hover");
}

function handleResultOnMouseOut(result)
{
	unhighlight(result);
}

/* Lists */

function handleListRowOnMouseOver(tr)
{
	highlight(tr, "hover");
}

function handleListRowOnMouseOut(tr)
{
	unhighlight(tr);
}

/******************************************************************************
 **********                    Image Browser                         **********
 ******************************************************************************/

function ListingImageBrowser(maxImageHeight, maxImageWidth, imageRoot)
{
	this.maxImageHeight = maxImageHeight;
	
	this.maxImageWidth = maxImageWidth;
	
	this.imageRoot = imageRoot;
	
	// Dimensions of the average listing image are landscape oriented with a
	// 4x3 aspect ration. If the first listing image has not yet been loaded,
	// these are the dimensions we'll use. In most cases, this will prevent page
	// resizing when the image finally loads. We'll round down because that's
	// what image resizing utility does to ensure that an image fits within a
	// certain size.
	
	this.getDefaultImageWidth = function()
	{
		return this.maxImageWidth;
	};
	
	this.getDefaultImageHeight = function()
	{
		return Math.floor((this.getDefaultImageWidth() / 4) * 3);
	};
	
	// Currently selected image. This image may or may not have loaded.
	
	this.selectedImage = null;
	
	// Requested images (array of initialized ListingImage objects). These
	// images may be at various stages of loading.
	
	this.images = new Array();
	
	this.getImage = function(imageID)
	{
		for (var i in this.images)
		{
			var image = this.images[i];
			
			if (image.imageID == imageID)
			{
				return image;
			}
		}
		
		return this.createListingImage(imageID);
	};
	
	this.createListingImage = function(imageID)
	{
		var image = new ListingImage(imageID, this.maxImageHeight,
				this.maxImageWidth, imageRoot);
		
		this.images.push(image);
		
		return image;
	};
	
	/**************************************************************************
	 **********                  Callable Actions                    **********
	 **************************************************************************/
	
	this.displayListingImage = function(imageID)
	{
		if (disregardImageClick(imageID))
		{
			return;	
		}
		
		// Verify and set the image dimensions of the loading image and
		// containing elements before changing the element display. This
		// will prevent unnecessary resizing.
		
		this.checkDimensions();
		
		this.hideListingImage();
		
		this.showLoadingImage();
		
		this.selectImage(imageID);
		
	};
	
	
	this.selectImage = function(imageID)
	{
		// Set the selected image before we download it so that multiple clicks
		// on the image thumbnails do not pile up while we're loading the first
		// image.
		
		this.selectedImage = this.getImage(imageID);
		
		var listingImage = this.getListingImage();
		
		listingImage.src = this.selectedImage.imageSource;
	};
	
	
	var disregardImageClick = function(imageID)
	{
		// We're not currently loading images. We'll go through with the
		// request.
		
		if (this.selectedImage == null)
		{
			return false;
		}
		
		// Only allow one image to load at a time to keep from piling up
		// requests to the server.
		
		if (!this.selectedImage.loaded)
		{
			return true;
		}
		
		// Don't bother swapping images if the user has clicked the same image
		// that's currently selected. This prevents an unnecessary call to the
		// server, and flash on the screen.
		
		if (this.selectedImage.imageID == imageID)
		{
			return true;
		}
		
		return false;
	};
	
	this.handleListingImageOnLoadEvent = function()
	{
		var image = this.getListingImage();

		this.hideLoadingImage();
		
		this.showListingImage();
		
		this.checkDimensions();
		
		// The last thing we do is flag the image as loaded. That way, we
		// (hopefully) avoid concurrency issues.
		
		this.selectedImage.loaded = true;
	};
	
	
	/**************************************************************************
	 **********                       Zooming                        **********
	 **************************************************************************/
	
	this.zoomToImage = function()
	{
		// Ignore clicks on the zoom icon until we have a selected image.
		
		if (this.selectedImage == null)
		{
			return;
		}
		
		window.location = this.getZoomImageUrl();
	};
	
	this.getZoomImageUrl = function()
	{
		if (this.selectedImage == null)
		{
			return;
		}
		
		// FIXME: Hard coded reference to the listing image page.
		
		var zoomUrl = "../listing/image.cfm?imageID=" + this.selectedImage.imageID
		
		return zoomUrl;
	};
	
	
	/**************************************************************************
	 **********                       Sizing                         **********
	 **************************************************************************/
	
	this.checkDimensions = function()
	{
		// Get the image dimensions for the listing image.
		
		var listingImageDimensions = this.getListingImageDimensions();
		
		// Any container divs will be the size of the image plus 2 pixels for
		// the border.
		
		var containerHeight = listingImageDimensions.height + 2;
		
		var containerWidth = listingImageDimensions.width + 2;
		
		// NOTE: We're sizing the inner elements first and working our way out.
		
		this.sizeListingImageContainer(containerHeight, containerWidth);
		
		this.sizeLoadingImageContainer(containerHeight, containerWidth);
		
		this.sizeImageBrowserNavigation(containerHeight, containerWidth);
		
		this.sizeImageBrowser(containerHeight, containerWidth);
		
		// If this is the first time this function is called, then we'll need to
		// display the image browser. We've defered this so that it avoid
		// shifting objects more than necessary.
		
		if (!this.isImageBrowserDisplaying())
		{
			this.showImageBrowser();
		}
	};
	
	this.getListingImageDimensions = function()
	{
		var dimensions = new Array();
		
		dimensions.width = this.getDefaultImageWidth();
		dimensions.height = this.getDefaultImageHeight();
		
		var listingImage = this.getListingImage();
		
		if (listingImage == null)
		{
			return dimensions;
		}
		
		// Use a minimum of 10 pixels as a sanity check. This also prevents
		// us from inadvertantly using the initial clear dot dimensions.
		
		if (!isNaN(listingImage.height) && listingImage.height > 10)
		{
			dimensions.height = listingImage.height;
		}
		
		if (!isNaN(listingImage.width) && listingImage.width > 10)
		{
			dimensions.width = listingImage.width;
		}
		
		return dimensions;
	};
	
	this.getLoadingImageDimensions = function()
	{
		var dimensions = new Array();
		
		// Dimensions of the loading image. We could just hard code these, but we
		// might as well make this calculation dynamic in case we change the loading
		// image for any reason.
		
		// FIXME: Hard coded reference to the loading image dimensions.
		
		dimensions.height = 30;
		dimensions.width = 100;
		
		var loadingImage = this.getLoadingImage();
		
		if (loadingImage == null)
		{
			return dimensions;
		}
		
		// Use 10 pixels as a sanity check.
		
		if (!isNaN(loadingImage.height) && loadingImage.height > 10)
		{
			dimensions.height = loadingImage.height;
		}
		
		if (!isNaN(loadingImage.width) && loadingImage.width > 10)
		{
			dimensions.width = loadingImage.width;
		}
		
		return dimensions;
	};
	
	this.sizeImageBrowser = function(minHeight, minWidth)
	{
		// Make our browser large enough to contain the image.
		
		var imageBrowser = this.getImageBrowser();
		
		// We're only interested in the width because the image browser height
		// will depend on alot of things (thumbnails, zoom image, listing image
		// margins, etc.).
		
		if (imageBrowser.clientWidth >= minWidth)
		{
			return;
		}
		
		imageBrowser.style.width = minWidth + "px";
	};
	
	this.sizeImageBrowserNavigation = function(minHeight, minWidth)
	{
		// Make sure our thumbnail container resizes to the correct width. We
		// don't have to worry about height because the thumbnails will wrap and
		// force the container to the correct height.
		
		var imageNavigation = this.getImageBrowserNavigation();
		
		// Because the thumbnails can be turned off, we need to check to make
		// sure they exist.
		
		if (imageNavigation == null)
		{
			return;
		}
		
		// Only allow the image browser navigation to grow wider. This
		// prevents unnecessary resizing for portrait images, which are
		// the exception.
		
		if (imageNavigation.clientWidth >= minWidth)
		{
			return;
		}
		
		imageNavigation.style.width = minWidth + "px";
	};
	
	this.sizeListingImageContainer = function(minHeight, minWidth)
	{
		// Make sure the image browser is the corrent height and width. This
		// prevents unnecessary element shifting as the page reflows for the new
		// content.
		
		var imageContainer = this.getImageBrowserContent();
		var resized = false;
		
		// Don't allow the listing image container to shrink in width. Most
		// images will be constrained by their width because most images are
		// landscaped. By maintaining the width, we allow portrait oriented
		// images to be center aligned within the width of the landscaped
		// images.
		
		if (imageContainer.clientWidth < minWidth)
		{
			imageContainer.style.width = minWidth + "px";
		}
		
		if (imageContainer.clientHeight < minHeight)
		{
			imageContainer.style.height = minHeight + "px";
			
			resized = true;
		}
		else if (minHeight < (imageContainer.clientHeight * 0.80))
		{
			// NOTE: Only shrink the image content area if the new height is
			// less than 90% of the current area to avoid unnecessary resizes.
			
			imageContainer.style.height = minHeight + "px";
			
			resized = true;
		}
	};
	
	this.sizeLoadingImageContainer = function(minHeight, minWidth)
	{
		// The loading image will be smaller than the actual image. We need to
		// set the padding on the loading image to force it to the size of the
		// listing image it's replacing.
		
		var imageContainer = this.getImageBrowserContent();
		
		var loadingImageDimensions = this.getLoadingImageDimensions();
		
		// Determine the padding required to make the loading image as large as
		// the listing image. First, we'll determine the total padding on either
		// axis. Then we'll divide that by two and round off to get one side.
		// Then, we'll assign the difference to the other side. This method
		// should take care of rounding errors with odd numbers.
		
		// NOTE: clientWidth and clientHeight will start out at zero during the
		// first load. We can generalize this state and say that, if the
		// difference is a negative number, we want to use the default image
		// width and height.
		
		var horizontalDifference = imageContainer.clientWidth - loadingImageDimensions["width"];
		
		if (horizontalDifference < 0)
		{
			horizontalDifference = this.getDefaultImageWidth() - loadingImageDimensions["width"];
		}
		
		var verticalDifference = imageContainer.clientHeight - loadingImageDimensions["height"];
		
		if (verticalDifference < 0)
		{
			verticalDifference = this.getDefaultImageHeight() - loadingImageDimensions["height"];
		}
		
		var topOffset = Math.ceil(horizontalDifference / 2);
		
		var leftOffset = Math.ceil(verticalDifference / 2);
		
		this.positionLoadingImage(topOffset, leftOffset);
		
	};
	
	this.positionLoadingImage = function(topOffset, leftOffset)
	{
		var loadingImage = this.getLoadingImage();
		
		loadingImage.style.top = topOffset + "px";
		
		loadingImage.style.left = leftOffset + "px";
	};
	
	
	/**************************************************************************
	 **********                       Display                        **********
	 **************************************************************************/
	
	this.showImageBrowser = function()
	{
		this.getImageBrowser().style.display = "block";
	};
	
	this.isImageBrowserDisplaying = function()
	{
		if (this.getImageBrowser().style.display != "block")
		{
			return false;
		}
		else
		{
			return true;
		}
	};
	
	this.showLoadingImage = function()
	{
		this.getLoadingImageContainer().style.display = "block";
	};
	
	this.hideLoadingImage = function()
	{
		this.getLoadingImageContainer().style.display = "none";
	};
	
	this.showListingImage = function()
	{
		this.getListingImageContainer().style.display = "block";
	};
	
	this.hideListingImage = function()
	{
		this.getListingImageContainer().style.display = "none";
	};
	
	
	/**************************************************************************
	 **********                  Object Accessors                    **********
	 **************************************************************************/
	
	this.getImageBrowser = function()
	{
		return document.getElementById("imageBrowser");
	};
	
	this.getImageBrowserNavigation = function()
	{
		return document.getElementById("imageBrowserNavigation");
	};
	
	this.getImageBrowserContent = function()
	{
		return document.getElementById("imageBrowserContent");
	};
	
	this.getLoadingImageContainer = function()
	{
		return document.getElementById("loadingImageContainer");
	};
	
	this.getListingImageContainer = function()
	{
		return document.getElementById("listingImageContainer");
	};
	
	this.getListingImage = function()
	{
		return document.getElementById("listingImage");
	}
	
	this.getLoadingImage = function()
	{
		return document.getElementById("loadingImage");
	};
	
}

// Stores information about the image and it's display, including its
// bounding container dimensions.

function ListingImage(imageID, maxImageHeight, maxImageWidth, imageRoot)
{
	this.imageID = imageID;
	
	this.maxImageHeight = maxImageHeight;
	
	this.maxImageWidth = maxImageWidth;
	
	this.getListingImageUrl = function()
	{
		var imageUrl = imageRoot;
		
		imageUrl += "imageGenerator/index.cfm";
		imageUrl += "?imageID=" + this.imageID;
		imageUrl += "&transformation=constrain";
		imageUrl += "&imageWidth=" + this.maxImageWidth;
		imageUrl += "&imageHeight=" + this.maxImageHeight;
		
		return imageUrl;
	};
	
	this.imageSource = this.getListingImageUrl();
	
	this.image = new Image();
	
	this.image.src = this.imageSource;
	
	this.loaded = false;
}
