// Allow the use of $j shorthand, avoiding conflicts with prototype
var $j = jQuery.noConflict();

// Make sure this code is run only once per page
if(undefined === priceRunnerAlreadyInitialized){
	/*
	 * Finds divs with the class name ".pricerunnerAdContainer" and dynamically
	 * adds ads to these. Passes the data stored in the data-* attributes
	 */
	$j(function(){
		// Loop through ads
		var adDivs = $j('.pricerunnerAdContainer');
		adDivs.each(function() {
			var adDiv = $j(this);
			
			$j.post(
					"/ajax/getpricerunnerad",
					{
						cid : adDiv.attr('data-cid') || "",
						'prodNames[]' : adDiv.attr('data-prodNames').split(",") || "",
						'catIds[]' : adDiv.attr('data-catIds').split(",") || "",
						'catFilters[]' : adDiv.attr('data-catFilters').split(",") || "",
						'catNames[]' : adDiv.attr('data-catNames').split(",") || "",
						adCount : adDiv.attr('data-adCount') || ""				
					},
					function(xml){
						parseXML(xml,adDiv);
					}
			);
		});
	});

	/*********************************************************
	 * Generates ads based on a Pricerunner XML file.
	 * @param xml: The XML file to parse.
	 * @param adDiv: The div to put the generated ads inside.
	 * NOTE: The finished ad will have the following structure:
	 *       <div.pricerunnerAdContainer>
	 *         <h4>Main title</h4>
	 *         <ul.pricerunnerProducts>
	 *         	 (product <li> elements)
	 *         </ul>
	 *         <a.pricerunnerMore>Compare more products</a>
	 *       </div>
	 * NOTE: In the case of several list items, the last one
	 *       will have a class name of "noborder"
	 * NOTE: If no XML file is passed, it will just output the
	 *       contents directly into adDiv
	 *********************************************************/
	function parseXML(xml,adDiv){
		
		// If the result did not contain products, we display single ads where we don't move google ads
		// (i.e. where the google ads are inside the pricerunner div)
		if($j(xml).find("product").size() == 0){
			if(adDiv.attr('data-adCount') == 1 && adDiv.attr('data-moveAds') == 0)
				adDiv.show();
			// Also show the afc_wrapper div (if it exists)
			$j('.afc_wrapper').show();
			return;
		}
		// Otherwise, we clear the current contents
		else adDiv.html("");
		
		// If we need to move the google ads, we add a class name to the afc block
		if(adDiv.attr('data-moveAds') == 1) {
			$j('#wide_afc:first').addClass("afc_moved");
		}
		
		// Extract local data
		var localization = $j(xml).find('localization');
		var moreText = $j(localization).children('comparemore').text();
		var moreLink = $j(localization).children('moreurl').text();
		
		// Create title element (to be filled later)
		var titleEl = $j('<h4/>')
			.appendTo(adDiv);
		
		// Create product list
		var listEl = $j('<ul/>')
			.appendTo(adDiv);
		
		// Create read more link
		$j('<a/>').appendTo(adDiv)
			.addClass('pricerunnerMore')
			.attr('href',moreLink)
			.html(moreText);
		
		var first; // Initialize variable to keep track of whether we got the first listed retailer
		/* Loop through each product node, and create a corresponding
		   list item under listEl */
		var products = $j(xml).find("product");
		products.each(function(i) {
			// Get cheapest retailer with a link
			var retailerArray = getRetailer($j(this)); 
			// First element stores the retailer
			var retailer = retailerArray[0];
			// Second element stores whether or not it was the first
			first = retailerArray[1];
			var product = createProduct($j(this),retailer,localization);
			// Add non-null product to the list
			if(product != null) listEl.append(product);
		});
		// Last product of a multi ad should have no border
		if(products.size() > 1)
			$j(listEl).children('li').last().addClass("noborder");
		
		var title = "";
		// Generate title
		if(products.size() == 1) {
			if(first) title = $j(localization).children('bestprice').text(); // Single ad, cheapest retailer
			else title = $j(localization).children('sponsoredlink').text(); // Single ad, other retailer
		}
		else if(products.size() > 1)
			title = $j(localization).children('popular').text(); // Multiple ad
		// Place title
		titleEl.html(title);
		
		// Show contents
		adDiv.show();
		// Also show the afc_wrapper div (if it exists)
		$j('.afc_wrapper').show();
	}
	
	/*************************************************************
	 * Creates a list element, containing data about a specified
	 * product. The data is extracted from a supplied node from a
	 * pricerunner XML file.
	 * 
	 * @param product: the product node containing product name
	 *        and description
	 * @param retailer: the retailer node containing price and
	 *        product link data
	 * @param localization: the localization node containing
	 *                      various site-specific data
	 *                      
	 * @returns: An element with the following structure:
	 *       	 <li>
	 *             <a><img/></a>
	 *             <h4><a>Title</a></h4>
	 *             <p.description>Description</p>
	 *             <p.price>from: <a>price</a></p>
	 *             <p.rating>Rating: <a><img/>(X reviews)</a></p>
	 *             <a.retailer>Retailer name</a>
	 *           </li>
	 *           The ratings link point to the expert reviews,
	 *           all other links point to the retailer's
	 *           product page.
	 *           If retailer was null, null is returned.
	 *************************************************************/
	function createProduct(product,retailer,localization){
		// If we have no retailer, we return null
		if(retailer == null) return null;
			
		// Extract max name length
		var maxTextLen = parseInt($j(localization).children('textlength').text());
		
		// Extract product data
		var buyURL = retailer.children('link').text(); // Link to product
		var reviewURL = product.children('expertreviews-url').text(); // Link to expert reviews
		var imgURL = product.children('image-url').text(); // Image source
		var prodName = product.children('name').text(); // Product name
		var prodNameTrunc = truncate(prodName,maxTextLen); // Truncated product name
		var desc = product.children('description').text(); // Description
		var descTrunc = truncate(desc,maxTextLen); // Truncated description
		var price = retailer.children('price').text(); // Price
		var numRatings = product.find('rating[type=professional] num-ratings').text(); // Number of ratings
		// Ratings image source (if available)
		if(numRatings != "" && numRatings > 0)
			var ratingsImgURL = generateRatingsImgURL(product.find('rating[type=professional] average').text()); 
		var retailerName = retailer.children('name').text(); // Retailer name
		var retailerNameTrunc = truncate(retailerName,maxTextLen); // Truncated retailer name
		// Extract localization data
		var priceFrom = localization.children('pricefrom').text();
		var rating = localization.children('rating').text();
		var ratingAmount = localization.children('ratingamount').text();
		
		// Create the containing list item element
		productLi = $j('<li/>');
		
		// Default <a> element
		var defA = '<a target="_blank" href="' + buyURL + ' rel="nofollow"></a>';
			
		// Create the image
		$j(defA)
			.appendTo(productLi)
			.addClass('imageLink');
		// Only insert actual image if the URL is present
		if(imgURL != null && imgURL != ""){
			$j('<img/>').appendTo(productLi.children('a'))
				.attr('alt',prodName)
				.attr('title',prodName)
				.attr('src',imgURL);
		}
		
		// Create the title
		$j('<h4/>').appendTo(productLi);
		$j(defA).appendTo(productLi.children('h4'))
			.html(prodNameTrunc);
		
		// Create the description
		$j('<p/>').appendTo(productLi)
			.addClass('description');
		$j(defA).appendTo(productLi.children('p.description'))
			.html(descTrunc);
		
		// Create the price
		$j('<p/>').appendTo(productLi)
			.addClass('price')
			.html(priceFrom + ': ');
		$j(defA).appendTo(productLi.children('p.price'))
			.html(price);
		
		// Create the rating
		if(numRatings != "" && numRatings > 0){
			$j('<p/>').appendTo(productLi)
				.addClass('rating')
				.html(rating + ': ');
			$j(defA).appendTo(productLi.children('p.rating'))
				.attr('href',reviewURL);
			$j('<img/>').appendTo(productLi.find('p.rating a'))
				.attr('src',ratingsImgURL);
			productLi.find('p.rating a').append('(' + numRatings + ' ' + ratingAmount + ')');
		}
		
		// Create retailer link
		$j('<p/>').appendTo(productLi)
			.addClass('retailer');
		$j(defA).appendTo(productLi.children('p.retailer'))
			.html(retailerNameTrunc);
		
		return productLi;
	}
	
	/***********************************************************
	 * Looks for the first retailer containing a link to a 
	 * product page inside the specified node.
	 * @param product: the product node to search
	 * @returns: array: {first, retailer}, where:
	 *           - first is a boolean value storing whether or
	 *             not this was the first (i.e. cheapest)
	 *             retailer listed.
	 *           - retailer is the retailer node, or null
	 *             if none was found
	 ***********************************************************/
	function getRetailer(product){
		// Default to false
		var first = false;
		// Default to null
		var retailer = null;
		// Iterate through each retailer
		product.children('retailer').each(function(i) {
			// If we found a retailer with a link, return it and stop iterating
			if($j(this).children('link').size() > 0){
				retailer = $j(this);
				if(i = 0) first = true; // First retailer
				return false; // Break
			}
		});
		return new Array(retailer, first);
	}
	
	/***************************************************************
	 * Truncates a string
	 * @param str: The string to truncate
	 * @param maxLen: The max length of the output string
	 * @returns: If the string does not exceed the max length, it
	 *           is returned unchanged.
	 *           If it does exceed the max length, it is truncated,
	 *           and "..." is appended to the end.
	 * NOTE: the "..." is counted towards the max length, thus
	 *       truncate("testing",6) returns "tes..."
	 ***************************************************************/
	function truncate(str,maxLen){
		if(str.length <= maxLen) return str;
		return str.substring(0,maxLen-3) + "...";
	}
	
	/****************************************************************
	 * Generates an URL pointing to an image on pricerunner's server
	 * corresponding to the given rating.
	 * @param rating: the rating, as a string containing the rating
	 * @returns: The URL of the image on pricerunner's server.
	 * NOTE: Images contain stars and half-stars, thus the rating
	 *       is rounded to the nearest half integer.
	 *       (i.e. 3.7 will return an image of 3½ stars)
	 ****************************************************************/
	function generateRatingsImgURL(rating){
		// Replace comma with dot
		rating = rating.replace(',','.');
		// Convert to float
		rating = parseFloat(rating);
		// Return null if we didn't get a number between 0 and 5
		if(isNaN(rating) || rating < 0 || rating > 5) return null;
		// Round off to nearest half integer
		rating = Math.round(rating*2)/2;
		// Back to string
		rating += "";
		// Replace dot with underscore
		rating = rating.replace('.','_');
		// Generate URL, return
		return "http://images.pricerunner.com/images/site-gui/listpages/grade_" + rating + ".gif";
	}
}
//Flag pricerunner as initialized
var priceRunnerAlreadyInitialized = true;
