/**
 * Product Details Page. 
 *
 * The script allows user to select and persist products associated with a current viewing product.
 * All products are stored and access from the list 'productList' in memeory.
 * Each update to the list (add, remove, empty) will trigger an event to perist the selection and 
 * dynamically reflect the selection on the page.
 *
 * Each product object consists of a set of consistent fields and described as follow:
 * 	description - discription of the product
 * 	code 		- the part number of the product
 * 	price 		- the price of the product
 * 	soiUid 		- (special offer only) the special offer Id for each special offer products.
 *	key			- the key associated to a product in the product list.
 *	toString	- (for debugging purposes) the string representation of the product - it prints product data.
 *	checkbox	- (optional) the HTML checkbox reference associated to a product.
 *
 * The 'productList' object is a facade to manage the selected product list. 
 * The main product and the page mode is store in the 'config' object. The peristed product and page mode
 * is stored and retrieved as the 'savedConfig' object. The 'config' and 'savedConfig' shares an identical 
 * interface. 
 *
 * The persisted config and selected products are cleared and updated when going to a different product details page ONLY when
 * a product checkbox click event on that different page is fired.
 */

// begin: argos.product.details
argos.product.details.add = {
	EXIT_WARNING_MESSAGE : "To add selected items to your trolley please click the \'Buy or Reserve\' button.",
	productListName : "pdpProductList",
	mode : {standard : "standard", gifting : "gifting"},
	configName: "pdpConfig",
	config: {mode: "standard", product: {}, displayExitWarning: true},
	savedConfig: {mode: null, product: {}, displayExitWarning: true},
	productContainers : {extraslist: "product", producttabs : "product", aswellas : "product"},	
	
	// product hash table
	productList : {
		// private: internal list of products
		products : [],

		// get the size of the list
		size : function() { 
			var len = 0;
			for (var i in this.products) {
					len++;
			}	
			return len; 
		},
		
		// add a product to the list
		add : function(product) {
			this.products[product.key] = product; 
		},
		
		// remove a product with the associated key from the list
		remove : function(key) {			
			delete this.products[key];		
		},
		
		// get a product with the associated key from the list
		get : function(key) {
			return this.products[key];
		},
		
		// empty the list to no products
		empty : function() {
			this.products = [];
		},
		
		// return a list of products in a hash table. 
		// The key is the 'key' property in each product element. i.e. product.key
		list : function() {
			return this.products;
		}
	},
	
	// an event trigger to remove a product and handles UI behavioural changes
	removeEvent : function(key) {
		var details = argos.product.details.add; // namespace reference
		var product = details.productList.get(key);
		details.productList.remove(product.key);				
		argos.utils.persistence.persist(details.productListName, details.productList.list());	
		details.render(details.productList.list());
		product.checkbox.checked = false;
	},
	
	// an event trigger to add a product and handles UI behavioural changes
	addEvent : function(product) {
		var details = argos.product.details.add; // namespace reference
		details.productList.add(product)
		argos.utils.persistence.persist(details.productListName, details.productList.list());	
		details.render(details.productList.list());
	},
	
	// an event trigger to empty the list of product selection and handles UI behavioural changes
	emptyEvent : function() {
		var details = argos.product.details.add; // namespace reference
		details.productList.empty();
		argos.utils.persistence.persist(details.productListName, details.productList.list());	
		details.render(details.productList.list());
	},
	
	// register a click event to an HTML element for add and remove products
	registerClickEvent : function(obj, product) {
		var details = argos.product.details.add; // namespace reference
		$(obj).click(
			function() {
				if (this.checked) {					
					var savedConfig = details.savedConfig;	
					if (!savedConfig || !savedConfig.product || savedConfig.product.code!= details.config.product.code) {					
						argos.utils.persistence.persist(details.configName, details.config);	
						details.savedConfig = details.config;
						details.productList.empty();
					}
					
					details.addEvent(product); 
										
				} else {
					details.removeEvent(product.key); 
				}				
			}
		);
	},
	
	exitEvent: function(event) {		
		var details = argos.product.details.add; // namespace reference	
		var savedProductList = argos.utils.persistence.retrieve(details.productListName);
				
		var hasSavedProducts = false;
		
		if (savedProductList) {
			for (var key in savedProductList) {
				var product = savedProductList[key];
				if (product && product.code) {
					hasSavedProducts = true;
					break;
				}
			}
		}
		
		if (!hasSavedProducts) {
			return;				// no products, exit to its default behaviour
		}
		
		if (hasSavedProducts && details.config.displayExitWarning == true) {
			alert(details.EXIT_WARNING_MESSAGE);
			details.config.displayExitWarning = false;				
			argos.utils.persistence.persist(details.configName, details.config);
			
			$("#footertext p").before('<img src="" width="1" height="1" />');
			event.preventDefault();
		} 
	},
	
	// initialise page
	init : function() {
		var details = argos.product.details.add; // namespace reference
		// exit conditions 
		if( $('.btngiftingbuyreserve').length > 0) return; //product not buyable/not reservable
		
		// get all page products and register click event	
		var pageProductList = details.getProducts(details.productContainers);	
		for (var productKey in pageProductList) {
			var product = pageProductList[productKey];
			// if there is a checkbox for this product
			if (product.checkbox){
				product.checkbox.checked = false;	// clear all browse-auto-checks
				details.registerClickEvent(product.checkbox, product);
			};
		}		
		
		// get main product and assign to config (not persisted)
		var strUtil = argos.utils.string;
		var description = strUtil.trim($("#primaryproductinfo h1").text());
		var code = strUtil.trim($("#primaryproductinfo .partnumber").text());
		var price = strUtil.trim($("#primaryproductinfo .price").text());
		var mainProduct = details.createProduct(description, code, price, null, "mainproduct" + code);
		details.config.product = mainProduct;	
		
		// restore and tick saved product selection if persisted main product is the same as current main product
		details.savedConfig = argos.utils.persistence.retrieve(details.configName);			
		if (details.savedConfig && details.savedConfig.product && details.savedConfig.product.code==mainProduct.code) {
			// retrieve all saved products and tick the appropriate checkboxes on the page
			var savedProductList = argos.utils.persistence.retrieve(details.productListName);
			for (var productKey in savedProductList) {
				var product = savedProductList[productKey];	
					product.checkbox = pageProductList[productKey].checkbox;
					details.productList.add(product);
					// if there is a checkbox for this product
					if(product.checkbox){
						product.checkbox.checked = true;
					};
			}
		}
		
		if (!details.savedConfig) {
			details.config.displayExitWarning = (pdpExitWarning!=false && pdpExitWarning!="false");
		} else if (details.config.displayExitWarning==true && details.savedConfig) {
			details.config.displayExitWarning = (details.savedConfig.displayExitWarning != "false");
		}
		
		if (details.productList.size() > 0) {
			details.render();
		}
	},
	
	// construct a product object
	createProduct : function(productDesc, productCode, productPrice, productSoiUid, key) {
		return {description : productDesc,
				code : productCode,
				price  : productPrice,
				soiUid : productSoiUid,
				key : "", 
				toString : function() {
					var productString = "[Product]";
					productString += "description=" + productDesc;
					productString += ", code=" + productCode;
					productString += ", price=" + productPrice;
					productString += ", soiUid=" + productSoiUid;	
					productString += ", key=" + key;				
					productString += "[/Product]";
					
					return productString;
				}
			};
	},
	
	// parse a HTML DOM element and return a product object filled with parsed data
	getProduct : function(element) {
		var details = argos.product.details.add; // reduce namespace
		
		var product = null;
		
		if (element) {
			var strUtil = argos.utils.string;
			var desc = strUtil.trim($(element).find(".desc").text());
			var code = strUtil.trim($(element).find(".partnum").text());
			var price = strUtil.trim($(element).find(".price").text());
			var soi = $(element).attr("id");	// apply to special offers only
			var checkbox = $(element).find("input:checkbox")[0];
			
			product = details.createProduct(desc, code, price, soi);
			product.checkbox = checkbox;
		}
		
		return product;
	},
	
	/** 
	 * Parse a list of DOM elements with ID and product classname to get a list of products. 
	 * @param containers Config in the format of {id1: className1, id2: className2, ...}
	 * @return hash map of products
	 */
	getProducts : function(containers) {
		var details = argos.product.details.add; // reduce namespace
		
		var products = [];
		if (containers) {
			for (var containerId in containers) {
				var elements = $("#" + containerId).find("." + containers[containerId]);
				for (var i=0; i<elements.length; i++) {
					var product = details.getProduct(elements[i]);
					product.key = containerId;	// key prefix, append the rest depends on product type below	
					
					if (product.soiUid) { 	// special offers products
						product.key += product.soiUid;
					} else { 			// non special offers products
						product.key += product.code;
					}
					
					products[product.key] = product;
				}
			}
		}
		
		return products;		
	},
	
	// render a product
	writeProductLine : function(product, key) {
		var details = argos.product.details.add;	// reduce namespace		
		var productHTML  = "";
		
		if (key == details.config.product.key) {	// render main product (customed)
			productHTML	+= '<tr class="orderline">';
			productHTML	+= '<td colspan="2" class="orderitemdescription orderitemmain" scope="row"><strong>' + product.description + '</strong><span>' + product.code + '</span></td>';
			productHTML	+= '</tr>';
		} else {									// render selected product
			productHTML	+= '<tr class="orderline">';
			productHTML	+= '<td class="orderitemdescription" scope="row"><span class="desc">' + product.description + '</span><span>' + product.code + '</span></td>';
			productHTML	+= '<td class="orderitem" scope="row"><button type="button" onclick="argos.product.details.add.removeEvent(\'' + key + '\');" class="btnremove" title="Remove this product from your order">REMOVE</button></td>';
			productHTML	+= '<input type="hidden" value="prod" />';
			productHTML	+= '</tr>';
		}
		
		return productHTML;
	},
	
	// render selected product container and product selections
	render : function() {
		var details = argos.product.details.add;	// reduce namespace
		
		// Write the table structure
		var orderlistTableHTML = "";
				orderlistTableHTML	+= '<table id="orderlist">';
				orderlistTableHTML	+= '<thead><tr>';
				orderlistTableHTML	+= '<th id="itemdescription" scope="col"><span>Description</span></th>';				
				orderlistTableHTML	+= '<th id="removebutton" scope="col"><span>Remove Button</span></th>';		
				orderlistTableHTML	+= '</tr></thead>';
				orderlistTableHTML	+= '<tbody>';
				orderlistTableHTML	+= '</tbody>';
				orderlistTableHTML	+= '</table>';
				$("#orderitemwrapper").html(orderlistTableHTML);

		// main product to be added to list when first item is added
		// JSON data has same properties as a product object 
		// so it can be passed into writeProductLine		
		var mainProduct = details.config.product;
		// product list message
		var addedItemMsg = "Add these items to my trolley &gt;&gt;&gt;&gt;";
		var productHTML = details.writeProductLine(mainProduct, mainProduct.key);
		
		// add main product to list
		if (details.productList.size() > 0) {
			// product list message display
			$(".productmoreinfo .action .addedtoyour").remove();
			$(".productmoreinfo .action").append('<span class="addedtoyour">' + addedItemMsg + '</span>');
		}
		
		// loop over product list
		// create HTML for each product using details.writeProductLine
		var productList = details.productList.list();
		for (var productKey in productList) {		
			// write HTML table rows with product data
			productHTML += details.writeProductLine(productList[productKey], productKey);
		}

		// output into table
		$("#orderlist tbody").html(productHTML);

		// work out margin for moving #extraproductswrapper using a negative marginup/down when adding/removing items
		// get height of dynamic product line container
		var heightAdj = $(".productmoreinfo").height();
		var productImageHeight = $("#productimage").height();
		
		if (heightAdj > productImageHeight) {
			var heightTotal = 0;			
			if ($.browser.msie) {
				heightTotal = heightAdj - productImageHeight - 24;
			};
			if ($.browser.firefox) {
				heightTotal = heightAdj - productImageHeight - 25;
			};
			if ($.browser.safari) {
				heightTotal = heightAdj - productImageHeight - 23;
			};
			if ($.browser.opera) {
				heightTotal = heightAdj - productImageHeight - 31;
			};		
			
			var marginStr = (heightTotal > 0) ? -heightTotal + "px" : "0px";
			$("#extraproductswrapper").css(
				{marginTop : marginStr}
			);
		}
		
	}// end render()
} // End: argos.product.details.add

$(document).ready(
	function() {
		var details = argos.product.details.add;
		details.init();
		//details.exitEvent();

		// bind exit event to appropriate PDP links
		$('#header a').bind("click", function(event) {details.exitEvent(event);});
		$('.searchGoBtn').bind("click", function(event) {details.exitEvent(event);});		
		$('#footer a').bind("click", function(event) {details.exitEvent(event);});	
		$('#extraslist a').bind("click", function(event) {details.exitEvent(event);});	
		$('.specialofferrow .product a').bind("click", function(event) {details.exitEvent(event);});	
		$('#aswellas .product a').bind("click", function(event) {details.exitEvent(event);});
		$('#alternatives .product a').bind("click", function(event) {details.exitEvent(event);});
		$('.additionalinfo a').bind("click", function(event) {details.exitEvent(event);});
 	}
 ); // end domready
 
 