/// <reference path="dpr.global.js"/>
/// <reference path="dpr.util.js"/>
/// <reference path="dpr.images.js"/>

/// <summary>functions to construct and render the various buy-boxes (list of product links to affiliates)</summary>
dpr.buybox = {};

dpr.buybox.buildBuyBoxHtml = function (targetElementId, productJson)
{
	/// <summary
	/// 
	/// </summary>
	/// <param name="targetElementId" mayBeNull="false" optional="false" type="string">the id of the DOM element within which the DOM element will be rendered (all innerHTML will be replaced)</param>
	/// <param name="productJson" mayBeNull="false" optional="false" type="string">JSON formatted product data.</param>
	
	try
	{
		var product = eval("(" + productJson + ")");
		var targetElement = document.getElementById(targetElementId);
		
		// default zone
		var defaultZone = dpr.buybox.getCurrentZone();
		
		// header
		var newInnerHtml = '';
		
		// determine whether product has listings for this zone
		var productForZone = dpr.buybox.getFilteredProduct(product, ['*'], defaultZone, true, true);
		if (productForZone.variants.length != 0)
		{
			// zone data
			newInnerHtml += '<div id="buyBoxData_' + product.dpSKU + '_zones" class="buybox_html">';
			newInnerHtml += dpr.buybox.buildBuyBoxZoneHtml(product, defaultZone, true);
			newInnerHtml += '</div>';
			
			// zone picker (hidden for the moment)
			newInnerHtml += '<div class="buybox_zonePicker"><select onchange="dpr.util.hideAllChildrenExcept(\'buyBoxData_' + product.dpSKU + '_zones\', this.options[this.selectedIndex].value);">';
			for (var i = 0; i < dpr.shippingZones.length; i++) 
			{
				newInnerHtml += '<option value="buyBoxData_' + product.dpSKU + '_zones_' + dpr.shippingZones[i].code + '"' + (dpr.shippingZones[i] == defaultZone ? ' selected="selected"' : '') + '>' + dpr.shippingZones[i].code + '</option>';
			}
			newInnerHtml += '</select></div>';
		}
		else
		{
			// 'no listings'
			newInnerHtml = '<h4>Support this site, buy ' + (product.name == null || product.name == undefined || product.name == '' ? 'this product' : 'the ' + product.name) + ' from one of our retailers</h4><p align="center"><a href="' + dpr.clickThroughPath + '?dpr=' + product.dpSKU + '&source=NoListingsHtml" target="_blank"><b>Click here to check price / order now</b></a></p>';
			
		}
		
		targetElement.innerHTML = newInnerHtml;
	}
	catch (err)
	{
		dpr.util.displayErrorInPage(err, targetElement, 'buy-box could not be rendered');
	}
}

dpr.buybox.buildBuyBoxZoneHtml = function (product, shipZone, isInitiallyVisible)
{
	/// <summary>
	/// Builds html to display HTML buy box for a particular shippingZone
	/// </summary>
	/// <param name="product" mayBeNull="false" optional="false" type="anonymous(product)">the product to display listings for. the product may contain listings for other zones, these will not be rendered</param>
	/// <param name="shipZone" mayBeNull="false" optional="false" type="anonymous(shippingZone)">the zone which listings must be shippable to in order to be displayed</param>
	/// <param name="isInitiallyVisible" mayBeNull="false" optional="false" type="bool">Determines whether the list will be initially visible (useful when multiple zones are to be rendered exclusively</param>
	/// <returns>html for buy box</returns>
	
	var newInnerHtml = '<div id="buyBoxData_' + product.dpSKU + '_zones_' + shipZone.code + '" style="display:' + (isInitiallyVisible ? 'block' : 'none') + '">';
	for (var i=0; i<shipZone.affiliates.length; i++)
	{
		// get shippable listings
		var shippableProduct = dpr.buybox.getFilteredProduct(product, [shipZone.affiliates[i]], shipZone, true, true);
		var elementId = 'buyBoxData_' + product.dpSKU + '_zones_' + shipZone.code + '_' + shipZone.affiliates[i];
		newInnerHtml += '<div id="' + elementId + '">';
		newInnerHtml += (shippableProduct.merchants.length == 1) ? dpr.buybox.buildBuyBoxMerchantMajor(shippableProduct, elementId) : dpr.buybox.buildBuyBoxVariantMajor(shippableProduct, elementId);
		newInnerHtml += '</div>';
	}
	newInnerHtml += '</div>';
	
	return newInnerHtml;
}

dpr.buybox.buildBuyBoxText = function (targetElementId, productJson)
{
	/// <summary>
	/// replaces the innerHTML of the specified dom element with a simple list of links to listings 
	/// which can be shipped to the users current zone.
	/// </summary>
	
	try
	{
		var product = eval("(" + productJson + ")");
		var defaultZone = dpr.buybox.getCurrentZone();
		var shippableProducts = dpr.buybox.getFilteredProduct(product, ['*'], defaultZone, false, false);
		var newInnerHtml = '<ul class="buybox_text">';
		var listedCount = 0;
		var maxListings = dpr.initialMaxListingsText;
		if (listedCount < (maxListings - 1))
		{
			for (var a=0; a<defaultZone.affiliates.length && listedCount <= maxListings; a++)
			{
				var affiliateProducts = dpr.buybox.getFilteredProduct(product, [defaultZone.affiliates[a]], defaultZone, false, false);
				for (var i=0; i<affiliateProducts.merchants.length && listedCount <= maxListings; i++)
				{
					for (var j=0; j<affiliateProducts.merchants[i].listings.length && listedCount < maxListings; j++)
					{
						var listing = affiliateProducts.merchants[i].listings[j];
						newInnerHtml += '<li><a href="' + dpr.clickThroughPath + '?id=' + listing.id + '&source=BuyBoxText" target="_blank">';
						newInnerHtml += (listing.price.show == true) ? listing.price.symbol + dpr.util.formatCurrency(listing.price.amount) : 'too low to display';
						newInnerHtml += '</b> at ' + listing.name + '</a></li>';
						listedCount++;
					}
				}
			}
		}
		if (listedCount >= maxListings) newInnerHtml += '<li><a href="http://www.dpreview.com/shop/merchants.asp?id=' + product.dpSKU + '&affiliate=1">Click here for more</a></li>';
		
		// 'no price'
		if (listedCount == 0) newInnerHtml += '<li><a href="' + dpr.clickThroughPath + '?dpr=' + product.dpSKU + '&source=NoListingsText" target="_blank">Click here to check price / order now</a></li>';
		
		newInnerHtml += '</ul>';
		
		
		var targetElement = document.getElementById(targetElementId);
		targetElement.innerHTML = newInnerHtml;
	}
	catch (err)
	{
		dpr.util.displayErrorInPage(err, targetElement, 'buy-box listings could not be displayed');
	}
}

dpr.buybox.buildAveragePrice = function (targetElementId, productJson)
{
	/// <summary>
	/// renders the average price for listings of the specified product which can be 
	/// shipped to the current shipping zone.
	/// </summary>
	
	try
	{
		var product = eval("(" + productJson + ")");
		var defaultZone = dpr.buybox.getCurrentZone();
		var targetElement = document.getElementById(targetElementId);
		var avgPrice = dpr.buybox.calculateAveragePriceForZone(product, defaultZone);
		if (avgPrice != -1) targetElement.innerHTML = defaultZone.symbol + dpr.util.formatCurrency(avgPrice);
	}
	catch (err)
	{
		dpr.util.displayErrorInPage(err, targetElement, 'average price could not be displayed');
	}
}

dpr.buybox.calculateAveragePriceForZone = function (product, zone)
{
	/// <summary>
	/// Determines the average price of listings for the specified product which can be shipped to the specified zone.
	/// </summary>
	
	var vanillaProducts = dpr.buybox.getFilteredProduct(product, ['*'], zone, false, false);
	var total = 0;
	var count = 0;
	var avgPrice = -1;
	for (var i=0; i<vanillaProducts.variants.length; i++)
	{
		for (var j=0; j<vanillaProducts.variants[i].listings.length; j++)
		{
			var listing = vanillaProducts.variants[i].listings[j];
			
			if (dpr.buybox.listingCanShipTo(listing, zone) && listing.isKit == false && listing.isAcc == false && listing.price.show == true)
			{
				if (listing.price.nation == zone.currencyCode) 
				{
					total += listing.price.amount;
					count++;
				}
			}
		}
	}
	if (count != 0) avgPrice = total/count;
	return avgPrice;
}

dpr.buybox.getCurrentZone = function ()
{
	/// <summary>
	/// determines which shippingZone the user has been assigned (or has chosed)
	/// </summary>
	
	var defaultZoneCode = dpr.util.getCookie("geoloc");
	if (defaultZoneCode == null || defaultZoneCode == '' || typeof defaultZoneCode == undefined) defaultZoneCode = 'US'; // default to US if missing or invalid
	else defaultZoneCode = defaultZoneCode.toUpperCase();
	
	var defaultZone = dpr.getGenericShippingZone(defaultZoneCode);
	for (var i=0; i<dpr.shippingZones.length; i++)
	{
		if (dpr.shippingZones[i].code == defaultZoneCode) defaultZone = dpr.shippingZones[i];
	}
	return defaultZone;
}

dpr.buybox.getFilteredProduct = function (product, affiliates, shipZone, includeKit, includeAccessory, sort)
{
	/// <summary>
	/// produces a copy of the object containing only the variants, and within them only the listings, which 
	/// can be shipped to the specified zone.
	/// </summary>
	
	var newProduct = {name: product.name, dpSKU: product.dpSKU, variants: new Array(), merchants: new Array()};
	for (var i=0; i<product.variants.length; i++)
	{
		var varientListings = (sort && sort === true && product.variants[i].listings.length > 1) ? product.variants[i].listings.sort(dpr.buybox.sortListingsByCustom) : product.variants[i].listings;
		
		var theVarient = null;
		for (var j=0; j<varientListings.length; j++)
		{
			var listing = varientListings[j];
			// is affiliate acceptable
			var isAcceptableAffiliate = false;
			for (var k=0; k<affiliates.length; k++)
			{
				if (affiliates[k] == '*' || affiliates[k] == listing.affiliate) 
				{
					isAcceptableAffiliate = true;
					break;
				}
			}
			
			if (isAcceptableAffiliate == true && dpr.buybox.listingCanShipTo(listing, shipZone) && (includeKit == true || listing.isKit == false) && (includeAccessory == true || listing.isAcc == false))
			{
				// create newVariant if necessary
				if (theVarient == null)
				{
					theVarient = {name: product.variants[i].name, listings: new Array()};
					newProduct.variants.push(theVarient);
				}
				theVarient.listings.push(listing);
				
				// add listing to list of merchants
				var theMerchant = null;
				for (var k=0; k<newProduct.merchants.length; k++)
				{
					if (newProduct.merchants[k].affiliate == listing.affiliate && newProduct.merchants[k].name == listing.name)
					{
						theMerchant = newProduct.merchants[k];
						break;
					}
				}
				if (theMerchant == null)
				{
					theMerchant = {affiliate: listing.affiliate, merchantId: listing.merchantId, rating: listing.rating, name: listing.name, logo: listing.logo, listings: new Array()};
					newProduct.merchants.push(theMerchant);
				}
				theMerchant.listings.push(listing);
			}
		}
	}
	
	return newProduct;
}

dpr.buybox.sortVariantsByCustom = function (a, b)
{
	a.isMain = a.listings.length > 0 && a.listings[0].isKit == false && a.listings[0].isAcc == false;
	b.isMain = b.listings.length > 0 && b.listings[0].isKit == false && b.listings[0].isAcc == false;
	if (a.isMain == true && b.isMain == false)
	{
		// a is main, b is not, therefore a should come first
		return -1;
	}
	else if (b.isMain == true && a.isMain == false)
	{
		// b is main, a is not, b should come first
		return 1;
	}
	else if (a.isMain == true && b.isMain == true)
	{
		// both are main, sort by price ascending
		return dpr.buybox.sortListingsByPrice(a.listings[0], b.listings[0]);
	}
	else
	{
		// both are kits or accessories, sort by proce descending
		return dpr.buybox.sortListingsByPrice(a.listings[0], b.listings[0]) * -1;
	}
}

dpr.buybox.sortListingsByCustom = function (a, b)
{
	var output = 0;
	a.isMain = (a.isKit == false && a.isAcc == false);
	b.isMain = (b.isKit == false && b.isAcc == false);
	if (a.isMain == true && b.isMain == false)
	{
		// a is main, b is not, therefore a should come first
		return 1;
	}
	else if (b.isMain == true && a.isMain == false)
	{
		// b is main, a is not, b should come first
		return -1;
	}
	else if (a.isMain == true && b.isMain == true)
	{
		// both are main, sort by price ascending
		return dpr.buybox.sortListingsByPrice(a, b);
	}
	else
	{
		// both are kits or accessories, sort by proce descending
		return dpr.buybox.sortListingsByPrice(a, b) * -1;
	}
}

dpr.buybox.sortListingsByPrice = function (a, b)
{
	var output = 0;
	if (a.price.show == false)
	{
		output = (b.price.show == false) ? 0 : -1;
	}
	else if (b.price.show == false)
	{
		// if a's price can be shown but b's can't, assume b is lower
		output = 1;
	}
	else
	{
		// both prices can be shown, evaluate
		var usdA = dpr.buybox.getUsEquivalientPrice(a);
		var usdB = dpr.buybox.getUsEquivalientPrice(b);
		output = ((usdA.amount < usdB.amount) ? -1 : ((usdA.amount > usdB.amount) ? 1 : 0));
	}
	return output;
}


dpr.buybox.getUsEquivalientPrice = function (listing)
{
	var output = {show:false};
	if (listing.price.show == true)
	{
		if (listing.price.nation == 'USD')
		{
			// price is already in USD
			output = listing.price;
		}
		else
		{
			var buysUsDollars = dpr.buybox.getUsConversionRate(listing.price.nation);
			output = {show:true,amount:(listing.price.amount * buysUsDollars),nation:'USD',symbol:'$'};
		}
	}
	return output;
}


dpr.buybox.getUsConversionRate = function (currencyCode)
{
	for (i = 1; i < dpr.shippingZones; i++)
	{
		if (currencyCode == dpr.shippingZones[i].currencyCode) return dpr.shippingZones[i].buysUsDollars;
	}
	return 1;
}


dpr.buybox.buildBuyBoxVariantMajor = function (shippableProduct, elementIdPrefix)
{
	/// <summary>
	/// assumes all variants and listings can be shipped to the specified zone
	/// </summary>
	
	var newInnerHtml = '';
	
	// Truncate fix by Phil, 20/Oct/08
	var cleanName = '';
	
	// generate buy box tables
	if (shippableProduct.variants.length != 0)
	{
	
		// determine which variant to show initially
		var selectedVariantIndex = 0;
		for (i = 1; i < shippableProduct.variants.length; i++)
		{
			// choose based on max listings
			if (shippableProduct.variants[i].listings.length > shippableProduct.variants[selectedVariantIndex].listings.length)
			{
				selectedVariantIndex = i;
			}
		}
		
		newInnerHtml += '<h4>Support this site, buy the <span id="' + elementIdPrefix + '_selectedVariantName">' + shippableProduct.variants[0].name + '</span> from one of our ' + (dpr.buybox.getCurrentZone().code != 'US' ? 'international ' : '') + 'affiliate retailers</h4>';
		newInnerHtml += '<div id="' + elementIdPrefix + '_variants">';
		for (i = 0; i < shippableProduct.variants.length; i++)
		{
			var variant = shippableProduct.variants[i];
			newInnerHtml += '<div id="' + elementIdPrefix + '_variants_' + i + '" style="display:' + (i == selectedVariantIndex ? "block" : "none") + ';">';
			newInnerHtml += '<table id="' + elementIdPrefix + '_' + i + '_data" class="table-buybox footer_buybox">';
			newInnerHtml += '<thead><tr><th colspan="2">Store</th><th style="width:100px;">Rating</th><th style="width:100px;">Price</th></tr></thead><tbody>';
			for (j = 0; j < variant.listings.length; j++)
			{
				var listing = variant.listings[j];
				var linkUrl = dpr.clickThroughPath + '?id=' + listing.id + '&source=BuyBoxHtml';
		
				// hide listings after initial max
				newInnerHtml += '<tr style="display:' + (j < dpr.initialMaxMerchants ? '' : 'none') + ';">';
					
				// logo
				newInnerHtml += '<td style="width:100px;" height="30" align="center">';
				if (listing.logo != '') newInnerHtml += '<a href="' + dpr.clickThroughPath + '?id=' + listing.id + '&source=BuyBoxHtml" target="_blank"><img src="' + listing.logo + '" border="0" alt="' + listing.name + ' logo" /></a>';
				newInnerHtml += '</td>';
				// link
				newInnerHtml += '<td style="padding-left: 5px;"><a href="' + dpr.clickThroughPath + '?id=' + listing.id + '&source=BuyBoxHtml" target="_blank"><b>' + listing.name + '</b></a></td>';
				// stars
				newInnerHtml += '<td align="center" style="width:100px;">';
				if (listing.rating != 0)
				{
					for (k = 1; k <= 5; k++)
					{
						if (k * 100 <= listing.rating) newInnerHtml += '<img src="' + dpr.images.star_on_full + '" alt="star"/>';
						else if (k * 100 > listing.Rating && (k - 1) * 100 < listing.rating) newInnerHtml += '<img src="' + dpr.images.star_on_half + '" alt="half star"/><img src="' + dpr.images.star_off_half + '" alt="missing half star"/>';
						else newInnerHtml += '<img src="' + dpr.images.star_off_full + '" alt="missing star" />';
					}
				}
				newInnerHtml += '</td>';
				// price
				newInnerHtml += '<td align="right" style="width:100px;"><a href="' + dpr.clickThroughPath + '?id=' + listing.id + '&source=BuyBoxHtml" target="_blank"><b>';
				if (listing.price.show == true)
				{
					newInnerHtml += '<a href="' + linkUrl + '" target="_blank" style="font-weight:bold;">' + listing.price.symbol + dpr.util.formatCurrency(listing.price.amount) + '</a>';
				}
				else
				{
					newInnerHtml += '<a href="' + linkUrl + '" target="_blank" style="font-weight:bold;" title="' + dpr.message_ToLowTowDisplay_short + '">too low to display</a>';
				}
				newInnerHtml += '</b></a>&nbsp;</td>';
				
				newInnerHtml += '</tr>';
			}
			// 'more merchants' link
			if (variant.listings.length > dpr.initialMaxMerchants) newInnerHtml += '<tr id="' + elementIdPrefix + '_' + i + '_merchclick" style="hiddenmerchclickstyle"><td style="text-align:center;" colspan="4"><a href="javascript:dpr.buybox.showMoreMerchants(\'' + elementIdPrefix + '_' + i + '_data\', \'' + elementIdPrefix + '_' + i + '_merchclick\');"><b>Click here to see all ' +  variant.listings.length + ' merchants</b></a></td></tr>';
			newInnerHtml += '</tbody></table></div>';
		}
		newInnerHtml += '</div>'; // end variants div
		
		// variant selector
		if (shippableProduct.variants.length > 1)
		{
			newInnerHtml += '<div id="skuSelector">Other options: <select onchange="dpr.util.hideAllChildrenExcept(\'' + elementIdPrefix + '_variants\', this.options[this.selectedIndex].value);document.getElementById(\'' + elementIdPrefix + '_selectedVariantName\').innerHTML = this.options[this.selectedIndex].text;">';
			for (i = 0; i < shippableProduct.variants.length; i++) 
			{
				// Truncate fix by Phil, 20/Oct/08
				cleanName=shippableProduct.variants[i].name;
				if (cleanName.length>70) {
					cleanName=cleanName.substring(0,20) + '... ...' + cleanName.substring(cleanName.length-50,cleanName.length);
				}
				//
				
				newInnerHtml += '<option value="' + elementIdPrefix + '_variants_' + i + '" ' + (i == selectedVariantIndex ? "selected=\"selected\"" : "") + '>' + cleanName + '</option>';
			}
			newInnerHtml += '</select></div>';
		}
	}
	
	return newInnerHtml;
}


dpr.buybox.buildBuyBoxMerchantMajor = function (shippableProduct, elementIdPrefix)
{
	var theMerchant = shippableProduct.merchants[0];
	var newInnerHtml = '<div class="footer_buybox">';
	var maxListings = theMerchant.name == 'Amazon.com' ? dpr.initialMaxListingsAmazon : dpr.initialMaxMerchants;
	
	// sort by variants
	shippableProduct.variants = shippableProduct.variants.sort(dpr.buybox.sortVariantsByCustom);

	// header and logo
	if (theMerchant.logo != null && theMerchant.logo != '') 
	{
		newInnerHtml += '<img src="' + theMerchant.logo + '" alt="' + theMerchant.name + ' logo" class="floatingLogo" />';
	}
	newInnerHtml += '<h4>Buying options for this product from ' + theMerchant.name + '</h4>';
	
	// listings
	newInnerHtml += '<table cellpadding="0" cellspacing="0" class="table-buybox footer_buybox" id="' + elementIdPrefix + '_data">';
	newInnerHtml += '<thead><tr><th>Description</th><th style="width:100px;">Price</th></tr></thead><tbody>';
	for (var i=0; i<shippableProduct.variants.length; i++)
	{
	    var listing = null;
	    for (var j = 0; j < shippableProduct.variants[i].listings.length; j++) {
	        if (shippableProduct.variants[i].listings[j].name == theMerchant) listing = shippableProduct.variants[i].listings[j];
	    }
	    
		if (listing == null) listing = shippableProduct.variants[i].listings[0];
		var linkUrl = dpr.clickThroughPath + '?id=' + listing.id + '&source=BuyBoxHtml';

		// split particulars from title
		var title = null;
		title = listing.name2;
		
		if (title == null)
		    title = shippableProduct.variants[i].name;
		var particulars = '';
		var firstConjunction = title.toLowerCase().search(/\W(with|w\/|w \/|and|\+|for|\( *[including]+\.*)(\W|$)/);
		if (firstConjunction != -1) 
		{
			title = title.substr(0, firstConjunction);
			particulars = shippableProduct.variants[i].name.substr(firstConjunction, shippableProduct.variants[i].name.length - firstConjunction);
		}
		
		newInnerHtml += '<tr style="display:' + (i < maxListings ? '' : 'none') + ';" class="amazon_listing' + (listing.isKit == true ? ' kit' : (listing.isAcc == true ? ' accessory' : ' main')) + '">';
		// title & particulars
		newInnerHtml += '<td class="title" style="padding:2px;vertical-align:top;"><a href="' + linkUrl + '" style="font-weight:bold;" title="' + title + '" target="_blank">' + title + '</a>';
		if (particulars != '') newInnerHtml += '<span class="particulars">' + particulars + '</span>';
		newInnerHtml += '</td>';
		// price
		newInnerHtml += '<td class="price">';
		if (listing.price.show == true)
		{
			newInnerHtml += '<a href="' + linkUrl + '" target="_blank">' + listing.price.symbol + dpr.util.formatCurrency(listing.price.amount) + '</a>';
		}
		else
		{
			newInnerHtml += '<a href="' + linkUrl + '" target="_blank" title="' + dpr.message_ToLowTowDisplay_short + '">too low to display</a>';
		}
		newInnerHtml += '</td></tr>';
		
	}
	
	// 'more merchants' link
	if (shippableProduct.variants.length > maxListings) newInnerHtml += '<tr id="' + elementIdPrefix + '_merchclick" style="hiddenmerchclickstyle"><td style="text-align:center;" colspan="4"><a href="javascript:dpr.buybox.showMoreMerchants(\'' + elementIdPrefix + '_data\', \'' + elementIdPrefix + '_merchclick\');"><b>Click here to see all ' +  shippableProduct.variants.length + ' options</b></a></td></tr>';
	
	newInnerHtml += '</tbody></table></div>';
	
	return newInnerHtml;
}


dpr.buybox.listingCanShipTo = function (listing, zone)
{
	var isIncluded = false;
	for (var i=0; i<listing.canShipTo.length; i++) 
	{
		if (listing.canShipTo[i] == '*' || listing.canShipTo[i] == zone.code) 
		{
			isIncluded = true;
			break;
		}
	}
	var isExcluded = false;
	for (var i=0; i<listing.canShipTo.length; i++) 
	{
		if (listing.canShipTo[i] == '-' + zone.code) 
		{
			isExcluded = true;
			break;
		}
	}
	return (isIncluded == true && isExcluded == false);
}


dpr.buybox.showMoreMerchants = function (tableToExpandId, commandRowId)
{
	var tableToExpand = document.getElementById(tableToExpandId);
	var commandRow = document.getElementById(commandRowId);
	
	// show all rows of tableToExpand (except command row)
	var theChild = null;
	for (i = 0; i<tableToExpand.childNodes[1].childNodes.length; i++)
	{
		theChild = tableToExpand.childNodes[1].childNodes[i];
		theChild.style.display = (theChild.id == commandRowId) ? 'none' : '';
	}
}


dpr.buybox.getData = function (dpcode, callbackFunction)
{
	try
	{
		var request = dpr.util.GetXmlHttpRequest();
		if (request!=null)
		{
			var uri = dpr.shopDataPath + '?dp=' + dpcode + '&t=' + dpr.util.getRecentMilestoneFormatted(dpr.affiliateDataExpiryHours, dpr.affiliateDataExiryOffsetMinutes);
			request.onreadystatechange = function() 
			{
				if (request.readyState == 4)
				{
					if (request.status == 200 && request.responseText)
					{
						callbackFunction(request.responseText, dpcode);
					}
					else
					{
						dpr.util.logError('xhr response error, status: ' + request.status);
					}
				}
			}
			request.open("GET", uri, true);
			request.send(null);
		}
		else
		{
			dpr.util.logError('browser does not support ajax');
		}
	}
	catch (err)
	{
		dpr.util.logError('getData failed', err);
	}
}


dpr.buybox.buildAdBox = function (targetElementId, productJson, affiliates)
{
	/// <summary>
	/// replaces the innerHTML of the specified dom element with a basic HTML (table-formatted) list of offers,
	/// which can be shipped to the user's current zone, from the specified affiliates
	/// </summary>
	
	try
	{
		var product = eval("(" + productJson + ")");
		var defaultZone = dpr.buybox.getCurrentZone();
		var shippableProducts = dpr.buybox.getFilteredProduct(product, affiliates, defaultZone, false, false);
		var newInnerHtml = '';
		var maxListings = dpr.initialMaxListingsText;
		if (shippableProducts.variants.length != 0)
		{
			newInnerHtml = '<div class="adBox160"><h4>Best prices for the ' + shippableProducts.name + '</h4>';
			newInnerHtml += '<table cellpadding="0" cellspacing="0">';
			var listedCount = 0;
			for (j = 0; j < shippableProducts.variants[0].listings.length && listedCount < maxListings; j++)
			{
			
				var listing = shippableProducts.variants[0].listings[j];
				
				// prepare merchant name
				var merchantName = listing.name;
				merchantName = merchantName.replace(/\.com$/, '');
				while (/[A-Z][a-z]+[A-Z]/.test(merchantName))
				{
					var camelIndex = merchantName.search(/[a-z][A-Z]/);
					merchantName = merchantName.substring(0, camelIndex + 1) + ' ' + merchantName.substring(camelIndex + 1);
				}
			
				var url = dpr.clickThroughPath + '?id=' + listing.id + '&source=AdBox';
				newInnerHtml += '<tr class="' + (j % 2 == 0 ? "even" : "odd") + '">';
				newInnerHtml += '<td class="description"><div><a href="' + url + '" target="_blank" title="' + merchantName + '">' + merchantName + '</a></div></td>';
				newInnerHtml += '<td class="price"><a href="' + url + '" target="_blank">' + ((listing.price.show == true) ? (listing.price.symbol + dpr.util.formatCurrency(listing.price.amount)) : 'too low to display') + '</a></td>';
				newInnerHtml += '</tr>';
				listedCount++;
			}
			if (listedCount >= maxListings) newInnerHtml += '<tr><td colspan="2" class="more"><a href="http://www.dpreview.com/shop/merchants.asp?id=' + product.dpSKU + '&affiliate=1">Click here for more</a></td></tr>';
			
			// 'no price'
			if (listedCount == 0) newInnerHtml += '<li><a href="' + dpr.clickThroughPath + '?dpr=' + product.dpSKU + '&source=NoListingsText" target="_blank">Click here to check price / order now</a></li>';
			
			newInnerHtml += '</table></div>';
		}
		
		var targetElement = document.getElementById(targetElementId);
		targetElement.innerHTML = newInnerHtml;
	}
	catch (err)
	{
		dpr.util.displayErrorInPage(err, targetElement, 'ad-box listings could not be displayed');
	}
}



dpr.buybox.buildBuyBoxLogo = function (targetElementId, productJson)
{
	/// <summary>
	/// replaces the innerHTML of the specified dom element with img (merchant logo) links to listings 
	/// which can be shipped to the users current zone.
	/// </summary>
	
	try
	{
		var product = eval("(" + productJson + ")");
		var defaultZone = dpr.buybox.getCurrentZone();
		var shippableProducts = dpr.buybox.getFilteredProduct(product, ['*'], defaultZone, true, false, true);
		var newInnerHtml = '<table border="0" cellpadding="0" cellspacing="5" class="buybox_logos">';
		var listedCount = 0;
		var maxListings = dpr.initialMaxListingsLogos;
		if (listedCount < (maxListings - 1))
		{
			for (var a=0; a<defaultZone.affiliates.length && listedCount < maxListings; a++)
			{
				var affiliateProducts = dpr.buybox.getFilteredProduct(product, [defaultZone.affiliates[a]], defaultZone, true, false, true);
				for (var i=0; i<affiliateProducts.variants.length && listedCount < maxListings; i++)
				{
					for (var j=0; j<affiliateProducts.variants[i].listings.length && listedCount < maxListings; j++)
					{
						var listing = affiliateProducts.variants[i].listings[j];
						if (listing.isAcc == false && listing.isKit == false)
						{
							var linkUrl = dpr.clickThroughPath + '?id=' + listing.id + '&source=BuyBoxLogos';
							newInnerHtml += '<tr>';
							newInnerHtml += '<td class="img"><a href="' + linkUrl + '" target="_blank">' + (listing.logo != null && listing.logo != '' ? '<img src="' + listing.logo + '" border="0" alt="' + listing.name + ' logo" />' : listing.name) + '</a></td>';
							newInnerHtml += '<td class="price"><a href="' + linkUrl + '" target="_blank">' + (listing.price.show == true ? listing.price.symbol + dpr.util.formatCurrency(listing.price.amount) : 'too low to display') + '</a></td>';
							newInnerHtml += '</tr>';
							listedCount++;
						}
					}
				}
		
				// if we haven't filled our quota with body-only variants, try kits
				if (listedCount < maxListings)
				{
					for (var i=0; i<affiliateProducts.variants.length && listedCount < maxListings; i++)
					{
						for (var j=0; j<affiliateProducts.variants[i].listings.length && listedCount < maxListings; j++)
						{
							var listing = affiliateProducts.variants[i].listings[j];
							if (listing.isKit == true)
							{
								var linkUrl = dpr.clickThroughPath + '?id=' + listing.id + '&source=BuyBoxLogos';
								newInnerHtml += '<tr>';
								newInnerHtml += '<td><a href="' + linkUrl + '" target="_blank"><img src="' + listing.logo + '" border="0" alt="' + listing.name + ' logo" /></a></td>';
								newInnerHtml += '<td><a href="' + linkUrl + '" target="_blank">' + (listing.price.show == true ? listing.price.symbol + dpr.util.formatCurrency(listing.price.amount) : 'too low to display') + '</a></td>';
								newInnerHtml += '</tr>';
								listedCount++;
							}
						}
					}
				}
			}
		}
		
		
		if (listedCount >= maxListings) newInnerHtml += '<tr><td colspan="2"><a href="http://www.dpreview.com/shop/merchants.asp?id=' + product.dpSKU + '&affiliate=1">Click here for more</a></td></tr>';
		
		// 'no price'
		if (listedCount == 0) 
		{
			newInnerHtml += '<tr><td colspan="2"><a href="' + dpr.clickThroughPath + '?dpr=' + product.dpSKU + '&source=NoListingsLogos" target="_blank">Click here to check price / order now</a></td></tr>';
		}

		newInnerHtml += '</table>';
		
		
		var targetElement = document.getElementById(targetElementId);
		targetElement.innerHTML = newInnerHtml;
	}
	catch (err)
	{
		dpr.util.displayErrorInPage(err, targetElement, 'buy-box listings could not be displayed');
	}
}