/**
 * 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",
	bundleListName : "pdpBundleList",
	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"},	
	bundleContainers : { producttabs: "bundle"},
	fixedElement : { 0 : "#addfurtheritemswarning" }, // Scrolling Warning box for IE6 
	targetURL : "",
	
	bundleList : { 
		// private: internal list of bundles
		bundles : [],

		// get the size of the list
		size : function() { 
			var len = 0;
			for (var i in this.bundles) {
					len++;
			}	
			return len; 
		},
		
		// add a product to the list
		add : function(bundle) {
			this.bundles[bundle.key] = bundle; 
		},
		
		// remove a product with the associated key from the list
		remove : function(key) {			
			delete this.bundles[key];		
		},
		
		// get a product with the associated key from the list
		get : function(key) {
			return this.bundles[key];
		},
		
		// empty the list to no products
		empty : function() {
			this.bundles = [];
		},
		
		// 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.bundles;
		}
	},
	
	// 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, objValue, bundleKey) {
		var details = argos.product.details.add; // namespace reference
		var product = details.productList.get(key);
		var bundles = details.bundleList.bundles;
		
		// find out if products are part of a bundle and remove bundle and uncheck box if so
		if (((key) != null) && ((bundles) != null)) { 
			
			for(x in bundles) { 
				if (key.match(x)) { 
					
					var bundlecheckbox = $('#'+x)[0];
					bundlecheckbox.checked = false;
					details.bundleList.remove(x);
					argos.utils.persistence.persist(details.bundleListName, details.bundleList.list());
				
				}
			}
				
		}
		
		if(product){	
			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, obj.value); 
				}				
			}
		);
	},
	// register a click event to an HTML element for add and remove BUNDLE products
	registerBundleClickEvent : function(obj, bundle) {
		var details = argos.product.details.add; // namespace reference
		var objValue = obj.value;
		var bundleItems = objValue.split(",");
		
		$(obj).click(
			function() {				
				
				for (x in bundleItems) {
					var key = bundleItems[x];
					var offerprod = details.getProduct($("#"+key).get(0));
					offerprod.key = "producttabs"+offerprod.soiUid;
					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(offerprod);
						offerprod.checkbox.checked = true; // check the bundle's product checkbox, to enable exitEvent warning to appear
						details.bundleList.add(bundle);
						// add bundle list to cookie "bundleListName"
						argos.utils.persistence.persist(details.bundleListName, details.bundleList.list());
						
					} else {
						details.bundleList.remove(bundle.key);
						// add bundle list to cookie "bundleListName" with bundle.key removed from list
						argos.utils.persistence.persist(details.bundleListName, details.bundleList.list());
						details.removeEvent(offerprod.key, offerprod.checkbox.value, bundle.key);
					}
				}			
			}
		);
	},
	

	// Scrolling Warning box for IE6 
	registerScrollEvent : function (window){
		var details = argos.product.details.add; // namespace reference	
		
		for(elementId in details.fixedElement){
		
			var element = details.fixedElement[elementId];
			//var element = document.getElementById("addfurtheritemswarning");			
			var ob = element.style;
			element.realignElement = function () { 
				details.moveElement(element);				
			};	
			element.style.position = "absolute";
	        element.targetLeft = 	271;
	        element.targetTop = 	293;
	        element.targetRight = 	0;
	        element.targetBottom = 	0;
	        
	        details.fixedElement[elementId] = element ;
			
		}
		
		$(window).scroll(
			function () {				
				details.moveFixedElements();
			}
		);
	}, 
	
	moveElement : function (fixedElement){
		var details = argos.product.details.add; // namespace reference	
		details.computeShifts(fixedElement);
	  
	    if (fixedElement.currentX != fixedElement.shiftX
	        || fixedElement.currentY != fixedElement.shiftY)
	    {        
	        fixedElement.currentX = fixedElement.shiftX;
	        fixedElement.currentY = fixedElement.shiftY;
	        
	        fixedElement.style.top = fixedElement.currentY;
	        fixedElement.style.left = fixedElement.currentX;
	    }
	
	    fixedElement.style.right = '';
	    fixedElement.style.bottom = '';
	},	
	
	computeShifts : function(fixedElement){
	    fixedElement.shiftX =document.documentElement.scrollLeft;
	    fixedElement.shiftX += fixedElement.targetLeft;
	    fixedElement.shiftY = document.documentElement.scrollTop;
		fixedElement.shiftY += fixedElement.targetTop;
	},
	
	moveFixedElements : function () {
		var details = argos.product.details.add; // namespace reference			
		for(elementId in details.fixedElement){
			var element = details.fixedElement[elementId];
			element.realignElement();
		}
	},
	
	// Scrolling Warning box for IE6 ends
	
	exitEvent: function(event,targetURL) {		
	
		var details = argos.product.details.add; // namespace reference	
		//var savedProductList = argos.utils.persistence.retrieve(details.productListName);

		var hasSelectedProducts = false;
	
		var pageProductList = details.getProducts(details.productContainers);	
		for (var productKey in pageProductList) {
			var product = pageProductList[productKey];
			
			if (product.checkbox && product.checkbox.checked==true) {
				hasSelectedProducts = true;
				break;
			}
		}		
				
					
		if (!hasSelectedProducts) {
			return;	// no product selected, continue
		}
		
		if (hasSelectedProducts && details.config.displayExitWarning == true) {
			event.preventDefault();
			var eventTarget = event.srcElement || event.target;
			
			details.genWarningBox();
				
			// has users clicked on a link or search form submit
			if(eventTarget.tagName == "A") {
				$(".cancelessentialitems").click(function() {
					//set the cancel anchor to the target URL
					//window.location = eventTarget.href;
					window.location.href = eventTarget.href;
				});	
			} else if(eventTarget.className == "searchGoBtn") {	
				$(".cancelessentialitems").click(function() {
					// simply submit the search form
					$("#sb").submit();
				});
			} else if(eventTarget.tagName == "IMG") {	
				$(".cancelessentialitems").click(function() {
					// use URL to redirect					
					window.location.href = targetURL;
					
				});
			}
			
			$("#addfurtheritemswarning .additems").click(function() {
					//submit to trolley			
					$("#pdpForm").submit();
			});
			
			details.config.displayExitWarning = false;				
			argos.utils.persistence.persist(details.configName, details.config);
			
			$("#footertext p").before('<img src="" width="1" height="1" />');
		} 
	},
	
	// initialise page
	init : function() {
		var details = argos.product.details.add; // namespace reference
		
		// hide checkboxes for bundle products
		$(".bundle .descriptionone li:first-child").each(function(){
			$(this).addClass("jsHide");
		});
		
		// show bundle checkbox(s)
		$(".bundleaction").show();
			
		
		// 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);
		
		// get all page bundles
		var pageBundleList = details.getBundles(details.bundleContainers);
		
		
			
		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);
			};
		}
		
		
		for (var bundleKey in pageBundleList) {
			var bundle = pageBundleList[bundleKey];
			var bundlecheckbox = $("#" + bundle.key);
			details.registerBundleClickEvent(bundlecheckbox[0], bundle);
		}		
		
		// 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;
					};
			}
			
			// retrieve saved bundles and check the relevant checkboxes
			var savedBundleList = argos.utils.persistence.retrieve(details.bundleListName);
			for (var bundleId in savedBundleList) {
				var bundle = savedBundleList[bundleId]
				var bundleCheckbox = $('#'+bundleId)[0]; // get the checkbox with corresponding id
				bundleCheckbox.checked = true;
				details.bundleList.add(bundle); // add saved bundles into bundleList
				argos.utils.persistence.persist(details.bundleListName, details.bundleList.list()); // add bundle list to cookie "bundleListName"
			}
			
		}
		
		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();
		}
		
		var browserUtil = argos.utils.browser;
		if(!browserUtil.supportsPositionFixed()){
			for(elementId in details.fixedElement){				
				details.fixedElement[elementId] = $(details.fixedElement[elementId])[0];
			}
			details.registerScrollEvent(window);
		}
	},
	
	
	// generate warning box
	genWarningBox : function() {
		
		var addFurtherItemsHTML = '<p class="message">You ticked some items on this page, but didn&#39;t click the &#39;Buy or Reserve&#39; buttton to add them to your trolley.</p>';
		addFurtherItemsHTML += '<p class="prompt">Add items to your trolley?</p>';
		addFurtherItemsHTML += '<input class="additems" type="image" value="Yes, add items now" src="/wcsstore/argos/en_US/images/p1/pdp_warn_add_itmes.gif" />';
		addFurtherItemsHTML += '<a href="#" title="Don&#39;t add items" class="cancelessentialitems"><img alt="Don&#39;t add items" src="/wcsstore/argos/en_US/images/p1/pdp_warn_ignore_itmes.gif" /></a>';
		
		$("#addfurtheritemswarning").html(addFurtherItemsHTML) ;
		$("#addfurtheritemswarning").show();
		
	},
	
	
	// 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;
				}
			};
	},
	
	createBundle : function (containerId, bundleKey, product, checkbox){
	
		return {
				key : bundleKey
		};
	},
	
	// 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 HTML DOM element and return a bundle object filled with parsed data
	getBundle : function(containerId, element) {
		var details = argos.product.details.add; // reduce namespace		
		var bundle = null;
		
		if (element) {
			var product = $(element);
			var checkbox = $(element).find("input:checkbox")[0]; 
						
			var bundleId = $(element).attr("id");
			var bundleKey = bundleId.substring(bundleId.lastIndexOf("-"), bundleId);
			
			bundle = details.createBundle(containerId, bundleKey, product, checkbox);
			
			bundle.checkbox = checkbox;
			
		}
		
		return bundle;
	},
	
	
	/** 
	 * 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
						//eg: producttabssoi2-1						
						product.key += product.soiUid;
					} else { 			// non special offers products
						product.key += product.code;
					}
					products[product.key] = product;
				}
			}
		}
		
		return products;		
	},
	
	/** 
	 * 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
	 */
	getBundles : function(bundleContainers) {
		var details = argos.product.details.add; // reduce namespace
		//bundleContainers = details.bundleContainers;
		var bundles = [];
		var bundleproducts = [];
		if (bundleContainers) {
			for (var containerId in bundleContainers) {
				var elements = $("#" + containerId).find("." + bundleContainers[containerId]);
				for (var i=0; i<elements.length; i++) {
					var bundle = details.getBundle(containerId, elements[i]);
					bundles[bundle.key] = bundle;
					bundle.products = elements[i];
				}
				
			}
		}
		
		return bundles;		
	},
	
	// 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	+= '<td class="orderitem" scope="row"><a onclick="argos.product.details.add.removeEvent(\'' + key + '\');" class="remove" title="Remove this product from your order">Don&#39;t add</a></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";
		var addedItemExpl = "The following items will be added to your trolley when you click &#39;Buy or Reserve'";
		
		var productHTML = details.writeProductLine(mainProduct, mainProduct.key);
		
		// extract correct action html for addessentialextras bar 
		var actionHTML = "";
			actionHTML += $(".productmoreinfo #withoutessentialextras").html();
		
		// add main product to list
		if (details.productList.size() > 0) {
			// product list message display
			$(".productmoreinfo .action .addedtoyour").remove();
			$(".productmoreinfo .action .addedtoyourexpl").remove();
			$(".productmoreinfo .action").append('<span class="addedtoyour">' + addedItemMsg + '</span><span class="addedtoyourexpl">' + addedItemExpl + '</span>');
					
			//update essentialextras actionbar
			$("#addessentialextras").addClass("action");
			$("#addessentialextras").addClass("clearfix");
			$("#addessentialextras").html(actionHTML);
			$("#addessentialextras .addedtoyour").remove();
			$("#addessentialextras .addedtoyourexpl").remove();
			
			$(".productmoreinfo #withoutessentialextras .btngiftingbuyreserve").hide();
			$(".productmoreinfo #withoutessentialextras .btnaddtogiftlist").hide();
			$(".productmoreinfo #withoutessentialextras .btnbuyreserve").hide();
			
			$(".productmoreinfo #addessentialextras .btngiftingbuyreserve").show();
			$(".productmoreinfo #addessentialextras .btnaddtogiftlist").show();
			$(".productmoreinfo #addessentialextras .btnbuyreserve").show();
			$(".productmoreinfo #addessentialextras").show();
		
		}
		
		
		
		// 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,this.href);});
		$('.searchGoBtn').bind("click", function(event) {details.exitEvent(event);});		
		$('#footer a').bind("click", function(event) {details.exitEvent(event,this.href);});	
		$('#extraslist a').bind("click", function(event) {details.exitEvent(event,this.href);});
		$('.specialofferrow .product a').bind("click", function(event) {details.exitEvent(event,this.href);});
		$('#aswellas .product a').bind("click", function(event) {details.exitEvent(event,this.href);});
		$('#alternatives .product a').bind("click", function(event) {details.exitEvent(event,this.href);});
		$('.additionalinfo a').bind("click", function(event) {details.exitEvent(event,this.href);});
 	}
 ); // end domready
 
 

 