//init function for Cart

var gMandatoryPrestationList = null;
var gCompleteWheelList = null;
var gProductList = null;
var gOptionalPrestationList = null;

function addToCompleteWheelGroup(groupId, productId) {
	// check if the product has a 'complete wheels' group
	if(groupId==0) {
		return;
	}

	// if it has one 
	if(groupId.length!=0) {
		/* 
		 * then we must push it in a map to be able
		 * to retrieve it from an other product or service
		 * which belongs to the same group. 
		 */
		if(gCompleteWheelList[groupId]==null) {
			gCompleteWheelList[groupId] = new Array();
		}

		/** 
		 * we must alse update the gProductList to be able
		 * to find a group id from the product id
		 */ 

		gProductList[productId]=groupId;
		gCompleteWheelList[groupId].push(productId);
	}
}

function initPrestationList() {
	
	
	if(gMandatoryPrestationList == null) {
		gMandatoryPrestationList = new Array();
	}

	if(gOptionalPrestationList == null) {
		gOptionalPrestationList = new Array();
	} 

	if(gCompleteWheelList == null) {
		gCompleteWheelList = new Array();
	} 

	if(gProductList == null) {
		gProductList = new Array();
	} 

	/*<s:iterator value="cart.productCartLineList">

		// add product id to the complete wheel group if it exists
		addToCompleteWheelGroup("<s:property value='completeWheelGroup' />","<s:property value='productId' />");
				
		gMandatoryPrestationList["<s:property value='productId' />"] = new Array();
		gOptionalPrestationList["<s:property value='productId' />"] = new Array();
		
		<s:iterator value="mandatoryPrestationList">
			gMandatoryPrestationList["<s:property value='[1].productId' />"].push("<s:property value='productId' />");
		</s:iterator>
		
		<s:iterator value="optionalPrestationIdList">
		gOptionalPrestationList["<s:property value='[1].productId' />"].push("<s:property />");
		</s:iterator>
		
	</s:iterator>
	*/
	var jsonActionUrl = gsUrlJson;

	var myXHR = new Request.JSON({url:jsonActionUrl, onSuccess: function(responseJSON, responseTEXT){
		
		if(responseJSON != null) {
			var data = responseJSON.cartResult;
			
			for(var i=0; i<data.productCartLineList.length ;i++) {
				var loProduct = data.productCartLineList[i];
				
				// add product id to the complete wheel group if it exists
				addToCompleteWheelGroup(loProduct.completeWheelGroup,loProduct.productId);
				
				gMandatoryPrestationList[loProduct.productId] = new Array();
				gOptionalPrestationList[loProduct.productId] = new Array();
				
				for(var j=0; j<loProduct.mandatoryPrestationList.length ;j++) {
					gMandatoryPrestationList[loProduct.productId].push(loProduct.mandatoryPrestationList[j].productId);
				}
				for(var k=0; k<loProduct.optionalPrestationIdList.length ;k++) {
					gOptionalPrestationList[loProduct.productId].push(loProduct.optionalPrestationIdList[k]);
				}
			}
		}
	}}).send();
}

function updateTotalPrice(pnTotalPrice) {
	var loDivTotalPrice = $$('div.totalPrice');
	
	if(loDivTotalPrice!=null) {
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = "<span>" + printf("%.2f" + goLabels["Currency_Symbol"],pnTotalPrice);
		} else {
			loPriceToDisplay = "<span>" + printf(goLabels["Currency_Symbol"] + "%.2f",pnTotalPrice);
		}
		loPriceToDisplay = loPriceToDisplay.replace(".", "</span>" + gsDecimalSeparator );
	
		loDivTotalPrice.set('html', loPriceToDisplay);
	}
}

function updateTotalPriceWithRebate(pnTotalPrice) {
	var loDivTotalPrice = $$('div.totalPriceWithRebate');
	
	if(loDivTotalPrice!=null) {
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = "<span>" + printf("%.2f" + goLabels["Currency_Symbol"],pnTotalPrice);
		} else {
			loPriceToDisplay = "<span>" + printf(goLabels["Currency_Symbol"] + "%.2f",pnTotalPrice);
		}
		loPriceToDisplay = loPriceToDisplay.replace(".", "</span>" + gsDecimalSeparator );
	
		loDivTotalPrice.set('html', loPriceToDisplay);
	}
}

function updateTotalDiscount(pnTotalDiscount) {

	var loDivTotalDiscount = $$('div.total-remise-value');
	
	if(loDivTotalDiscount!=null) {
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = printf("%.2f" + goLabels["Currency_Symbol"],pnTotalDiscount);
		} else {
			loPriceToDisplay = printf(goLabels["Currency_Symbol"] + "%.2f",pnTotalDiscount);
		}
		loPriceToDisplay = loPriceToDisplay.replace(".", gsDecimalSeparator );
	
		loDivTotalDiscount.set('text', loPriceToDisplay);
	}
	
	var loDivTotalLbl = $$('div.total-text');
	if (pnTotalDiscount != 0) {
		// if value of total discount is different from 0 we show the total discount row
		showTotalDiscountRow();

		// we update the total text label to display
		
		if (loDivTotalLbl!=null) {
			loDivTotalLbl.set('text', goLabels["Cart_Total_Include_Rebate"]);
		}

	} else {
		// if value of total discount is 0 we hide the total discount row
		removeTotalDiscountRow();

		// we update the total text label to display
		
		if (loDivTotalLbl!=null) {
			loDivTotalLbl.set('text', goLabels["Cart_Total"]);
		}
	}
}

function updateTotalDiscountWithRebate(pnTotalDiscount) {

	var loDivTotalDiscount = $$('div.total-remise-rebate-value');
	
	if(loDivTotalDiscount!=null) {
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = "<span>- " + printf("%.2f" + goLabels["Currency_Symbol"],pnTotalDiscount);
		} else {
			loPriceToDisplay = "<span>- " + printf(goLabels["Currency_Symbol"] + "%.2f",pnTotalDiscount);
		}
		loPriceToDisplay = loPriceToDisplay.replace(".", "</span>" + gsDecimalSeparator );
	
		loDivTotalDiscount.set('html', loPriceToDisplay);
	}
	
	var loDivTotalLbl = $$('div.total-text');
	if (pnTotalDiscount != 0) {
		// if value of total discount is different from 0 we show the total with rebate discount row
		showTotalDiscountWithRebateRow();

		// we update the total text label to display
		
		if (loDivTotalLbl!=null) {
			loDivTotalLbl.set('text', goLabels["Cart_Total_Include_Rebate"]);
		}

	} else {
		// if value of total discount is 0 we remove the total discount with rebate row
		removeTotalDiscountWithRebateRow();

		// we update the total text label to display
		
		if (loDivTotalLbl!=null) {
			loDivTotalLbl.set('text', goLabels["Cart_Total"]);
		}
	}
}

function updateRebatesValues(poRebateCartLineValuesMap) {

	var loDivRebate = null;
	var loPrice = 0.0;

	loDivRebate = $$('div.voucher-code');
	loPrice = poRebateCartLineValuesMap["VC"];
	
	if (loDivRebate!=null) {
		
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = "<span>- " + printf("%.2f" + goLabels["Currency_Symbol"],loPrice);
		} else {
			loPriceToDisplay = "<span>- " + printf(goLabels["Currency_Symbol"] + "%.2f",loPrice);
		}
		loPriceToDisplay = loPriceToDisplay.replace(".", "</span>" + gsDecimalSeparator );
		
		loDivRebate.set('html', loPriceToDisplay);
		
	}

	loDivRebate = $$('div.yield-management');
	loPrice = poRebateCartLineValuesMap["YM"];
	
	if (loDivRebate!=null) {
		
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = "<span>- " + printf("%.2f" + goLabels["Currency_Symbol"],loPrice);
		} else {
			loPriceToDisplay = "<span>- " + printf(goLabels["Currency_Symbol"] + "%.2f",loPrice);
		}
		loPriceToDisplay = loPriceToDisplay.replace(".", "</span>" + gsDecimalSeparator );
		
		loDivRebate.set('html', loPriceToDisplay);
		
	}
	
}

function updateTotalPricePayOnline(poPrice) {

	var loDivRebate = null;
	
	loDivRebate = $$('div.totalPriceSavePayOnline');
	
	if (loDivRebate!=null) {
		
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = "<span>" + printf("%.2f" + goLabels["Currency_Symbol"],poPrice);
		} else {
			loPriceToDisplay = "<span>" + printf(goLabels["Currency_Symbol"] + "%.2f",poPrice);
		}
		loPriceToDisplay = loPriceToDisplay.replace(".", "</span>" + gsDecimalSeparator );
	
		loDivRebate.set('html', loPriceToDisplay);
		
	}
	
}

function getParentDivRow(psHTMLProductId) {
	var parentRows = new Array(); 

	// test if at least there is one span
	if($(psHTMLProductId) == null) {
		return null;
	}

	// if there is, then get all span with this id
	var inputNodes = $$("[id=" + psHTMLProductId + "]"); 

	// browse them to push grandparent rows in the array we'll return
	inputNodes.each(function(curNode) {
		var parentNode = curNode.getParent();
		
		while(parentNode.get("class") != "ligne") {
			parentNode = parentNode.getParent();
		}

		parentRows.push(parentNode);
	});

	return parentRows;
}

/** 
 *  because we can have severals inputs with the same id,
 *  it has to return an array of parent elements contrary 
 *  to a unique returned row.
 */ 
function getParentTableRow(psHTMLProductId) {
	var parentRows = new Array(); 

	// test if at least there is one input
	if($(psHTMLProductId) == null) {
		return null;
	}

	// if there is, then get all inputs with this id
	var inputNodes = $$("[id=" + psHTMLProductId + "]"); 

	// browse them to push parent rows in the array we'll return
	inputNodes.each(function(curNode) {
		var parentNode = curNode.getParent();

		while(parentNode.get("tag") != "tr") {
			parentNode = parentNode.getParent();
		}

		parentRows.push(parentNode);
	});

	return parentRows;
}

function setMandatoryServiceQuantity(psProductId, psPrestationId, pnQuantity) {
	var lsHTMLProductId = "id__" + psProductId + "__" + psPrestationId + "__MS";
	if(pnQuantity != 0) {
		var loDivEl = $$("[id=" + lsHTMLProductId + "]");
		loDivEl.set("text", "x " + pnQuantity);
	} else {
		removeRow(lsHTMLProductId);
	}
}

function setOptionalServiceQuantity(psProductId, pnQuantity) {
	var lsHTMLProductId = "id__" + psProductId + "__OS";

	if(pnQuantity != 0) {
		var loDivEl = $$("[id=" + lsHTMLProductId + "]");
		loDivEl.set("text", "x " + pnQuantity);
	} else {
		removeRow(lsHTMLProductId);
	}
}

function setMandatoryServicePrice(psProductId, psPrestationId, pnPrice) {
	var lsHTMLProductId = "id__" + psProductId + "__" + psPrestationId + "__MS";
	setPrice(lsHTMLProductId, pnPrice);
}

function setOptionalServicePrice(psProductId, pnPrice) {
	var lsHTMLProductId = "id__" + psProductId + "__OS";
	setPrice(lsHTMLProductId, pnPrice);
}

/**
 * this function remove a row from the psProductId which is 
 * constructed following this format :
 *	 "id__" + productId + "__" + type of product
 * 
 * Type of product : 
 *	 OS -> Optional Service
 * 	 MS -> Mandatory Service
 *	 P -> Product
 *					
 */
function removeRow(psHTMLProductId) {
	
	var loRows = getParentDivRow(psHTMLProductId);
	
	if(loRows!=null) {
		loRows.each(function(loRow) {
			if(loRow != null)
				loRow.destroy();
		});
	}
}

/**
 * this function hide the total discount row			
 */
function removeTotalDiscountRow() {

	var loDivEl = $$("[id=total-discount]");
	if(loDivEl!=null) {
		loDivEl.set("style", "display:none;");
		//loDivEl.destroy();
	}
}

/**
 * this function show the total discount row			
 */
function showTotalDiscountRow() {

	var loDivEl = $$("[id=total-discount]");
	if(loDivEl!=null) {
		loDivEl.set("style", "");
	}
}

/**
 * this function hide the total discount with rebate row			
 */
function removeTotalDiscountWithRebateRow() {

	var loDivEl = $$("[id=total-discount-with-rebate]");
	if(loDivEl!=null) {
		loDivEl.set("style","display:none;");
	}
}

/**
 * this function show the total discount with rebate row			
 */
function showTotalDiscountWithRebateRow() {

	var loDivEl = $$("[id=total-discount-with-rebate]");
	if(loDivEl!=null) {
		loDivEl.set("style", "");
	}
}

function setProductQuantity(psProductId, pnQuantity) {
	var lsHTMLProductId = "id__" + psProductId + "__P";
	
	if(pnQuantity != "0") {

		var loSpanEl = $$("[id=" + lsHTMLProductId + "]");

		loSpanEl.set("html", "x " + pnQuantity);
		/*
		var loInputEl = $$("[id=" + lsHTMLProductId + "]");

		loInputEl.set("value", "x " + pnQuantity);
		*/
	} else {
		removeRow(lsHTMLProductId);
	}
}

/**
 * generic method to set price for a service or a product
 */
function setPrice(psHTMLProductId, pnPrice, pnValueOfDiscount) {
	var laRows = getParentDivRow(psHTMLProductId);
	
	laRows.each( function(loRow) {
		
		var loPriceDiv = null;
		
		if(loRow.getChildren().length < 3) {
			return;
		}

		loPriceDiv = loRow.getChildren()[3];
		
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = "<span>" + printf(" %.2f" + goLabels["Currency_Symbol"],pnPrice);
		} else {
			//pnPrice = formatNumberBy3(pnPrice,".",",");
			loPriceToDisplay = "<span>" + printf(" " + goLabels["Currency_Symbol"] + "%.2f",pnPrice);
		}

		loPriceToDisplay = loPriceToDisplay.replace("\.", "</span>" + gsDecimalSeparator);
		loPriceToDisplay = loPriceToDisplay.replace(/ /g, "");

		loPriceDiv.set("html", "<strong>" + loPriceToDisplay + "</strong>");

		// ONLY FOR PAYMENT PAGE
		// if the product has a discount, we update the value of total saving

		var loSavingDiv = null;

		if(loRow.getChildren().length < 4) {
			return;
		}
		
		loSavingDiv = loRow.getChildren()[4]

		if (loSavingDiv != null) {
			if (loSavingDiv.get("class") == "content-save") {

				if (pnValueOfDiscount != 0) {
					// we show the product saving line
					loSavingDiv.set("style", "");
				} else {
					// we hide the product saving line
					loSavingDiv.set("style", "display:none;");
				}
				
				loSavingDiv = loSavingDiv.getChildren()[2];

				if (loSavingDiv.get("class") == "total-remise-article") {
					if(gbIsCurrencySymbolBefore == "false") {
						loPriceToDisplay = "<span>" + printf(" %.2f" + goLabels["Currency_Symbol"],pnValueOfDiscount);
					} else {
						//pnPrice = formatNumberBy3(pnPrice,".",",");
						loPriceToDisplay = "<span>" + printf(" " + goLabels["Currency_Symbol"] + "%.2f",pnValueOfDiscount);
					}
			
					loPriceToDisplay = loPriceToDisplay.replace("\.", "</span>" + gsDecimalSeparator);
					loPriceToDisplay = loPriceToDisplay.replace(/ /g, "");
		
					loSavingDiv.set("html", "<strong>" + loPriceToDisplay + "</strong>");
				}
			}
		}
	});
}

/**
 * generic method to set unit price for a product
 */
function setUnitPrice(psHTMLProductId, pnUnitPrice) {
	var laRows = getParentDivRow(psHTMLProductId);
	
	laRows.each( function(loRow) {
		
		var loUnitPriceDiv = null;
		
		if(loRow.getChildren().length < 1) {
			return;
		}

		loUnitPriceDiv = loRow.getChildren()[1];
		
		if(gbIsCurrencySymbolBefore == "false") {
			loPriceToDisplay = "<span>" + printf(" %.2f" + goLabels["Currency_Symbol"],pnUnitPrice);
		} else {
			//pnPrice = formatNumberBy3(pnPrice,".",",");
			loPriceToDisplay = "<span>" + printf( " " + goLabels["Currency_Symbol"] + "%.2f",pnUnitPrice);
		}

		loPriceToDisplay = loPriceToDisplay.replace("\.", "</span>" + gsDecimalSeparator);
		loPriceToDisplay = loPriceToDisplay.replace(/ /g, "");

		loUnitPriceDiv.set("html", "<strong>" + loPriceToDisplay + "</strong>");
		
	});
}

function setProductPrice(psProductId, pnPrice, pnUnitPrice, pnValueOfDiscount) {
	var lsHTMLProductId = "id__" + psProductId + "__P";
	setPrice(lsHTMLProductId, pnPrice, pnValueOfDiscount);
	setUnitPrice(lsHTMLProductId, pnUnitPrice);
}
	
/**
 * check if the given value is in the provided list
 */
function isInList(pValue, pList) {
	for(i=0; i<pList.length; i++) {
		if(pList[i]==pValue) {
			return true;
		}
	}

	return false;
}

/**
 * return an array with all product id's except 
 * the one given (productId) as parameter which are in the same
 * "complete wheels group" (groupId).   
 */
function findSameGroupProducts(productId, groupId) {
	var groupProductList = gCompleteWheelList[groupId];
	resultArray = new Array();

	// if there is no group groupId : exit with a null returned
	if(groupProductList==null) {
		return null;
	}

	// if there is a group such as the one provided as argument
	// must find other products within the same group
	if(isInList(productId, groupProductList)) {
		// we browse the array to find which other products are in
		// this group
		for(i=0;i<gCompleteWheelList[groupId].length; i++) {
			if(groupProductList[i]!=productId) {
				resultArray.push(groupProductList[i]);
			}
		}

		return resultArray;
	} else {
		// if we reach this part of the code : it means there is a pb !!
		return null;
	}
}

/**
 * This function adds a quantity in a product cart line.
 * 
 * pCwAware is a boolean which ask the function to check if
 * there is associated complete wheels product. If yes it has
 * to be incremented too.
 */
function addProductCw(productId, pCwAware) {
	var jsonActionUrl = gsUrlJson + '/productId/' + productId + '/?method:addProduct=';
	lProductToAdd = new Array();

	var myXHR = new Request.JSON({
		url:jsonActionUrl, 
		onSuccess: function(responseJSON, responseTEXT){
			if(responseJSON == null) {
				if(gbShowCart != "true") {
					displayGeneralMessage("errorMessage", goLabels["Crt_To_Much_Tyre_Items"], goLabels["gmc_title"], 300, 200);
				}
			} else {
				var data = responseJSON.cartResult;

				for(var i=0; i<data.productCartLineList.length;i++) {
					var loProduct = data.productCartLineList[i];
					
					if(loProduct.productId == productId) {

						isCompleteWheel = new Boolean(loProduct.completeWheel);
						isCompleteWheelAware = new Boolean(pCwAware);
						
						// before the real process of this product
						// we need to process the other product which 
						// are in the same group if it is in a group (groupId!=0)
						if((isCompleteWheel==1) && (isCompleteWheelAware==1)) {
							lCwGroup = loProduct.completeWheelGroup;

							lCwProductList = findSameGroupProducts(productId, lCwGroup);

							for(j=0; j<lCwProductList.length; j++) {
								lProductToAdd.push(lCwProductList[j]);
							}
						}
						
						setProductQuantity(productId, loProduct.quantity);
						setProductPrice(productId, loProduct.price, loProduct.unitPrice, loProduct.valueOfDiscount);

						for(var p = 0;p<loProduct.mandatoryPrestationList.length;p++) {
							var lsMsId = loProduct.mandatoryPrestationList[p].productId;
							var lnMsQt = loProduct.mandatoryPrestationList[p].quantity;
							var lnMsPrice = loProduct.mandatoryPrestationList[p].price;
							setMandatoryServiceQuantity(productId, lsMsId, lnMsQt);
							setMandatoryServicePrice(productId, lsMsId, lnMsPrice);
						}

						// update assiociated optional prestations
						// first we browse the list of optional prestation id linked to this product
						for(var loOpIdIndex = 0;loOpIdIndex<loProduct.optionalPrestationIdList.length;loOpIdIndex++) {

							// we get id of this prestation
							var lsOsId = loProduct.optionalPrestationIdList[loOpIdIndex];

							// we try to find it in the global optional prestation list in order to retrieve the
							// quantity 
							for(var loOpIndex = 0; loOpIndex < data.optionalPrestationList.length; loOpIndex++) {
								// if we found it we uptate the quantity in the cart
								if(data.optionalPrestationList[loOpIndex].productId == lsOsId) {
									
									var lnOsQuantity = data.optionalPrestationList[loOpIndex].quantity; 
									var lnOsPrice = data.optionalPrestationList[loOpIndex].price;
									setOptionalServiceQuantity(lsOsId, lnOsQuantity);
									setOptionalServicePrice(lsOsId, lnOsPrice);
								}
							}
						}
						
						updateTotalPrice(data.totalPrice);
						updateTotalPriceWithRebate(data.totalPriceWithRebate);
						updateTotalDiscount(data.totalDiscount);
						updateTotalDiscountWithRebate(data.totalDiscountWithRebate);
						updateRebatesValues(data.rebateCartLineValuesMap);
						updateTotalPricePayOnline(data.totalPriceWithRebateIncludeOnline);
					}
				}

				/** if there is products to add because 
				of the complete wheel groups, do it now */
				if(lProductToAdd.length>0) {
					for(i=0; i<lProductToAdd.length; i++) {
						addProductCw(lProductToAdd[i], false);
					}
				}
			}
		}}).send();
}

// simple version of addProduct. By default it's bmf group aware. Which means
// that if the product is in a bmf group (complete wheels) all product in 
// this group has to be incremented by one too.
function addProduct(productId) {
	addProductCw(productId, true);
}

/**
 * This function removes a quantity in a product cart line.
 */
function decreaseProductCw(productId, pCwAware) {
	var jsonActionUrl = gsUrlJson + '/productId/' + productId + '/?method:decreaseProduct=';
	var lProductToRemoveList = new Array();
	
	var myXHR = new Request.JSON({url:jsonActionUrl, 
		async : false, 
		onSuccess: function(responseJSON, responseTEXT){
		var lbProductFound = false;
		//alert(responseTEXT);	
		if(responseJSON != null) {
			var data = responseJSON.cartResult;
			
			for(var i=0; i<data.productCartLineList.length;i++) {
				var loProduct = data.productCartLineList[i];
				
				if(loProduct.productId == productId) {
					lbProductFound = true;
					
					isCompleteWheel = new Boolean(loProduct.completeWheel);
					isCompleteWheelAware = new Boolean(pCwAware);
					
					// before the real process of this product
					// we need to process the other product which 
					// are in the same group if it is in a group (groupId!=0)
					if((isCompleteWheel==1) && (isCompleteWheelAware==1)) {
						lCwGroup = loProduct.completeWheelGroup;

						lCwProductList = findSameGroupProducts(productId, lCwGroup);

						for(j=0; j<lCwProductList.length; j++) {
							lProductToRemoveList.push(lCwProductList[j]);
						}
					}
						
					if(loProduct.quantity > 0) {
						setProductQuantity(productId, loProduct.quantity);
						setProductPrice(productId, loProduct.price, loProduct.unitPrice, loProduct.valueOfDiscount);

						// update associated mandatory prestations
						for(var p = 0;p<loProduct.mandatoryPrestationList.length;p++) {
							// get id of the mandatory prestation attached to the current product
							var lsMsId = loProduct.mandatoryPrestationList[p].productId;

							// get quantity of the mandatory prestation attached to the current product
							var lnMsQt = loProduct.mandatoryPrestationList[p].quantity;

							// get price of the mandatory prestation attached to the current product
							var lnMsPrice = loProduct.mandatoryPrestationList[p].price;

							setMandatoryServiceQuantity(productId, lsMsId, lnMsQt);
							setMandatoryServicePrice(productId, lsMsId, lnMsPrice);
						}

						// update assiociated optional prestations
						// first we browse the list of optional prestation id linked to this product
						for(var loOpIdIndex = 0;loOpIdIndex<loProduct.optionalPrestationIdList.length;loOpIdIndex++) {

							// we get id of this prestation
							var lsOsId = loProduct.optionalPrestationIdList[loOpIdIndex];

							// we try to find it in the global optional prestation list in order to retrieve the
							// quantity 
							for(var loOpIndex = 0; loOpIndex < data.optionalPrestationList.length; loOpIndex++) {
								// if we found it we uptate the quantity in the cart
								if(data.optionalPrestationList[loOpIndex].productId == lsOsId) {
									
									var lnOsQuantity = data.optionalPrestationList[loOpIndex].quantity; 
									var lnOsPrice = data.optionalPrestationList[loOpIndex].price;
									setOptionalServiceQuantity(lsOsId, lnOsQuantity);
									setOptionalServicePrice(lsOsId, lnOsPrice);
								}
							}
						}
					} 
				}
			}

			// the product was removed from cart so we must find out which prestation 
			// was linked to this product and remove or decrease prestation from the cart 
			// on the page
			if(!lbProductFound) {

					// should we remove also product of the same complete 
					// wheel product if there is one
					if(gProductList[productId]!=null) {
						// we update the quantity of the product to none which means remove it 
						// from the cart
						
						// but before we remove cw linked product too
						lCwGroupId =  gProductList[productId];
						lCwGroupProduct = gCompleteWheelList[lCwGroupId];
						
						for(indexProdList=0; indexProdList<lCwGroupProduct.length; indexProdList++) {
							// in other words : if we are not on the same line than
							// the one we are removing
							if(lCwGroupProduct[indexProdList] != productId) {
								decreaseProductCw(lCwGroupProduct[indexProdList], false);
							}
						}
					}
				setProductQuantity(productId, 0);

				// if we had a mandatory prestation associated with this removed product
				if(gMandatoryPrestationList[productId]!=null) {
					for(var cindex = 0;cindex<gMandatoryPrestationList[productId].length;cindex++) {
						setMandatoryServiceQuantity(productId, gMandatoryPrestationList[productId][cindex], 0);
					}
				}
			} 

			// if there was associated optional prestation to the removed product
			// we have to update the quantity
				if((gOptionalPrestationList!=null) && (gOptionalPrestationList[productId]!=null)) {
				// we browse the global table of optional prestation for this product
				for(var loCopIndex = 0;loCopIndex<gOptionalPrestationList[productId].length;loCopIndex++) {
					//alert(gMandatoryPrestationList[productId][cindex]);
					
					var lbOPFound = false;
					
					for(var loOPListIndex = 0; loOPListIndex < data.optionalPrestationList.length; loOPListIndex++) {
						if(data.optionalPrestationList[loOPListIndex].productId == gOptionalPrestationList[productId][loCopIndex]) {
							setOptionalServiceQuantity(gOptionalPrestationList[productId][loCopIndex], data.optionalPrestationList[loOPListIndex].quantity);
							lbOPFound = true;
							break;
						}
					}

					if(!lbOPFound) {
						setOptionalServiceQuantity(gOptionalPrestationList[productId][loCopIndex], 0);
					}
				}
			}

			/** if there is products to decrease because 
			of the complete wheel groups, do it now */
			if((pCwAware==1) && (isCompleteWheel==1)) {
				if(lProductToRemoveList.length>0) {
					for(i=0; i<lProductToRemoveList.length; i++) {
						decreaseProductCw(lProductToRemoveList[i], false);
					}
				} else {
					updateTotalPrice(data.totalPrice);
					updateTotalPriceWithRebate(data.totalPriceWithRebate);
					updateTotalDiscount(data.totalDiscount);
					updateTotalDiscountWithRebate(data.totalDiscountWithRebate);
					updateRebatesValues(data.rebateCartLineValuesMap);
					updateTotalPricePayOnline(data.totalPriceWithRebateIncludeOnline);
				}
			} else {
				updateTotalPrice(data.totalPrice);
				updateTotalPriceWithRebate(data.totalPriceWithRebate);
				updateTotalDiscount(data.totalDiscount);
				updateTotalDiscountWithRebate(data.totalDiscountWithRebate);
				updateRebatesValues(data.rebateCartLineValuesMap);
				updateTotalPricePayOnline(data.totalPriceWithRebateIncludeOnline);
			}
		}
	}}).send();
}

/**
 * This function adds a quantity in a optional prestation cart line.
 */
function addOptionalPrestation(prestationId) {
	var jsonActionUrl = gsUrlJson + '/productId/' + prestationId + '/?method:addOptionalPrestation=';

	var myXHR = new Request.JSON({
		url:jsonActionUrl, 
		onSuccess: function(responseJSON, responseTEXT){
			if(responseJSON == null) {
				if(gbShowCart != "true") {
					displayGeneralMessage("errorMessage", goLabels["Crt_To_Much_Tyre_Items"], goLabels["gmc_title"], 300, 200);
				}
			} else {
				var data = responseJSON.cartResult;
				
				for(var i=0; i<data.optionalPrestationList.length;i++) {
					var loPrestation = data.optionalPrestationList[i];
					
					if(loPrestation.productId == prestationId) {
						setOptionalServiceQuantity(prestationId, loPrestation.quantity);
						setOptionalServicePrice(prestationId, loPrestation.price);
						
						updateTotalPrice(data.totalPrice);
						updateTotalPriceWithRebate(data.totalPriceWithRebate);
						updateTotalDiscountWithRebate(data.totalDiscountWithRebate);
						updateRebatesValues(data.rebateCartLineValuesMap);
						updateTotalPricePayOnline(data.totalPriceWithRebateIncludeOnline);
					}
				}
			}
		}}).send();
}

/**
 * This function removes a quantity in an optional prestation cart line.
 */
function decreaseOptionalPrestation(prestationId) {
	var jsonActionUrl = gsUrlJson + '/productId/' + prestationId + '/?method:decreaseOptionalPrestation=';
	var myXHR = new Request.JSON({url:jsonActionUrl, async : false, onSuccess:function(responseJSON, responseTEXT){
		var lbOptionalPrestationFound = false;
		if(responseJSON != null) {
			var data = responseJSON.cartResult;
			
			for(var i=0; i<data.optionalPrestationList.length;i++) {
				var loPrestation = data.optionalPrestationList[i];
				
				if(loPrestation.productId == prestationId) {
					lbOptionalPrestationFound = true;
					
					if(loPrestation.quantity > 0) {
						setOptionalServiceQuantity(prestationId, loPrestation.quantity);
						setOptionalServicePrice(prestationId, loPrestation.price);
					} 
				}
			}

			if(!lbOptionalPrestationFound) {

				// we update the quantity of the optional prestation to none which means remove it 
				// from the cart
				setOptionalServiceQuantity(prestationId, 0);

			} 
			
			// we update the total amount for the cart from
			// the JSON field 'totalPrice' returned.
			updateTotalPrice(data.totalPrice);
			updateTotalPriceWithRebate(data.totalPriceWithRebate);
			updateTotalDiscountWithRebate(data.totalDiscountWithRebate);
			updateRebatesValues(data.rebateCartLineValuesMap);
			updateTotalPricePayOnline(data.totalPriceWithRebateIncludeOnline);
		}
	}}).send();
}

// simple version of decreaseProduct. By default it's bmf group aware. Which means
// that if the product is in a bmf group (complete wheels) all product in 
// this group has to be decremented by one too.
function decreaseProduct(productId) {
	decreaseProductCw(productId, true);
}

/**
 * This function removes an optionnal prestation line.
 */
function removeOptionalPrestation(productId) {		
	var jsonActionUrl = gsUrlJson + '/productId/' + productId + '/?method:removeOptionalPrestation=';
	
	var myXHR = new Request.JSON({url:jsonActionUrl, onSuccess:function(responseJSON, responseTEXT){	
		var data = responseJSON.cartResult;

		removeRow("id__" + productId + "__OS");

		updateTotalPrice(data.totalPrice);
		updateTotalPriceWithRebate(data.totalPriceWithRebate);
		updateRebatesValues(data.rebateCartLineValuesMap);
		updateTotalPricePayOnline(data.totalPriceWithRebateIncludeOnline);
	}}).send();
}