//-----------------------------------------------------------------
// Licensed Materials - Property of IBM
//
// WebSphere Commerce
//
// (C) Copyright IBM Corp. 2008, 2009 All Rights Reserved.
//
// US Government Users Restricted Rights - Use, duplication or
// disclosure restricted by GSA ADP Schedule Contract with
// IBM Corp.
//-----------------------------------------------------------------

/** 
 * @fileOverview This file provides utility functions for the order check-out pages.
 */

dojo.require("dojox.collections.ArrayList");
dojo.require("wc.widget.Tooltip");


/**
 * The functions defined in this class are used for managing order information update during check-out.
 *
 * @class This CheckoutHelperJS class defines all the variables and functions for the page(s) used in the check-out process to udpate order related information, such as address, shipping method, shipping instruction, etc.
 * 
 */
CheckoutHelperJS={

	/* Global variable declarations */
	
	/** 
	 * This variable stores the ID of the language that the store currently uses. Its default value is set to -1, which corresponds to United States English.
	 * @private
	 */
	langId: "-1",
	
	/** 
	 * This variable stores the ID of the current store. Its default value is empty.
	 * @private
	 */
	storeId: "",
	
	/** 
	 * This variable stores the ID of the catalog. Its default value is empty.
	 * @private
	 */
	catalogId: "",
	
	/** 
	 * This variable stores the shipment type, either 1 for single shipment or 2 for multiple shipment. Its default value is set to empty.
	 * @private
	 */
	shipmentTypeId:"",
	
	
	/** 
	 * This array stores the item IDs in an order. It is used to save the item IDs before an address is edited or created during the order check-out.
	 * @private
	 */
	orderItemIds:[],
	
	/** 
	 * This constant stores the amount of time in milliseconds that the <code>updateCartWait</code> function needs to wait before updating the shopping cart.
	 * @private
	 * @constant
	 * @see CheckoutHelperJS.updateCartWait
	 */
	updateWaitTimeOut:1500,
	
	/** 
	 * This array stores the number of key press events after a shopper has modified the quantity of an item in the shopping cart.
	 * @private
	 * @see CheckoutHelperJS.updateCartWait
	 */
	keyPressCount:{},
	
	/** 
	 * This variable stores the true/false value that indicates if the 'AjaxCheckout' feature is enabled.
	 * When it is true, virtually all information on the order check-out pages is updated using services.
	 * It is set to true by default.
	 * 
	 * @private
	 */
	ajaxCheckOut:true,
	
	/**
	 * This array stores the address ID before it is updated by the user during the order check-out.
	 * @private
	 */
	selectedAddressesArray:{},
	
	/**
	 * This variable stores the value that indicates if the payment method input has been changed by the user.
	 *
	 * @private
	 */
	dataDirty:false,
	
	/**
	 * This variable stores a value that indicates if the value of a shipping information related input field or the quantity of an item has been changed by the user.
	 * Its default value is set to false.
	 *
	 * @private
	 */
	fieldDirtyFlag:false,
	
	/** 
	 * This constant stores the String value representing a date that the service understands to reset a requested shipping date.
	 * @private
	 * @constant
	 */
	resetRequestedShipDateValue:"1970-01-01T00:00:00.000Z",
	
	/**
	 * This variable stores the value that indicates if the current page is the Shopping Cart page. It is used to determine what page to redirect to after a service call has been successfully performed.
	 *
	 * @private
	 */
	shoppingCartPage:false,
	
	/**
	 * This variable stores the value that indicates if the requested shipping date has recently been updated. It is used to determine if certain area of the page needs to be refreshed.
	 */
	RequestShippingDateAction:false,
	
	
	/**
	 * This function updates the input associative array params with the input key-value pair. 
	 * If the toArray value is true, this function creates an associative array for duplicate entries; otherwise it overwrites the existing array.
	 * The function is used for updating input parameters before passing them to a service call.
	 *
	 * @param {Array} params The associative array to update.
	 * @param {String} key The key to search for in the array.
	 * @param {String} value The new value to update with when the key has been found in the array.
	 * @param {Boolean} toArray If the value is true, then the function creates a new array for duplicate entries. If the value is false, no new array will be created, the existing array will be overwritten.
	 * @param {Integer} index The index in the array in which the value should be updated.
	 *
	 * @returns {Array} params The updated associative array.
	 */
	updateParamObject:function(params, key, value, toArray, index){
		if(params == null){
			params = [];
		}
		
		if(params[key] != null && toArray){
			if(dojo.lang.isArrayLike(params[key])){
				//3rd time onwards
				if(index != null && index != ""){
					//overwrite the old value at specified index
					params[key][index] = value;
				}else{
					params[key].push(value);
				}
			}else{
				//2nd time
				var tmpValue = params[key];
				params[key] = [];
				params[key].push(tmpValue);
				params[key].push(value);
			}
		}else{
			//1st time
			if(index != null && index != "" && index != -1){
				//overwrite the old value at specified index
				params[key+"_"+index] = value;
			}else if(index == -1){
				var i = 1;
				while(params[key + "_" + i] != null){
					i++;
				}
				params[key + "_" + i] = value;
			}else{
				params[key] = value;
			}
		}
		return params;
	},
	
	
	/**
	 * This function shows or hides the request shipping date input field depending on the state of the corresponding checkbox.
	 * If the checkbox is unchecked, and the 'AjaxCheckout' feature is enabled, the <code>OrderItemAddressShipMethodUpdate</code> service will be called to update the shipping information.
	 *
	 * @param {String} checkBoxName The ID of the request shipping date checkbox.
	 * @param {String} divName The name of the div element that contains the request shipping date input field.
	 * @param {String} suffix The suffix that is appended after the divName. It is usually the order item ID.
	 */
	checkRequestShippingDateBox:function(checkBoxName, divName, suffix){
		var thisCheckBoxName;
		var thisDivName;
		
		if(suffix != null && suffix != ""){
			checkBoxName = checkBoxName + "_" + suffix;
			divName = divName + "_" + suffix;
		}
		
		var checkBox = dojo.byId(checkBoxName);
		
		if(checkBox.checked){
			dojo.byId(divName).style.visibility = "visible";
			dojo.byId(divName).style.display = "block";
		}else{
			// If the checkbox is unchecked, hide the input field
			dojo.byId(divName).style.visibility = "hidden";
			dojo.byId(divName).style.display = "none";
		}
		
		var addressId, shipModeId = "";
		if(this.shipmentTypeId == "1"){
			addressId = document.getElementById("singleShipmentAddress").value;
			shipModeId = document.getElementById("singleShipmentShippingMode").value; 
		}else if(this.shipmentTypeId == "2"){
			addressId = document.getElementById("MS_ShipmentAddress_" + suffix).value;
			shipModeId = document.getElementById("MS_ShippingMode_" + suffix).value;
		}else{
			console.debug("shipmentTypeId is undefined. Single shipment has Id 1; multiple shipment has Id 2.");
		}
		
		// Delete the requestedShippingDate if the checkBox is unchecked and the checkout flow is AJAX
		if(!checkBox.checked && this.isAjaxCheckOut()){
			var params = [];
			params["storeId"] = this.storeId;
			params["catalogId"] = this.catalogId;
			params["langId"] = this.langId;
			params.orderId = ".";
			this.updateParamObject(params, "addressId", addressId, false, -1);
			this.updateParamObject(params, "shipModeId", shipModeId, false, -1);

			if(dijit.byId("requestedShippingDate") != null || dijit.byId("MS_requestedShippingDate_" + suffix) != null){
				this.updateParamObject(params, "requestedShipDate", this.resetRequestedShipDateValue, false, -1);
			}

			var orderItemId = null;
			var qty = null;
			var totalItems = document.getElementById("totalNumberOfItems").value;
			for(var i = 0; i < totalItems; i++){
				qty = document.getElementById("qty_" + (i+1)).value;
				orderItemId = document.getElementById("orderItem_" + (i+1)).value;
				// we need atleast one orderItemId..this is the limitation of order service..
				if(qty != -1){
					if(this.shipmentTypeId == "1"){
						// Single Shipment
						this.updateParamObject(params, "orderItemId", orderItemId, false, -1);
						break;
					}else if(this.shipmentTypeId == "2"){
						// Multiple Shipment
						if(suffix != null && suffix != "" && orderItemId == suffix){
							this.updateParamObject(params, "orderItemId", orderItemId, false, -1);
							break;
						}
					}else{
						console.debug("shipmentTypeId is undefined. Single shipment has Id 1; multiple shipment has Id 2.");
					}
				}
			}

			//For handling multiple clicks
			if(!submitRequest()){
				return;
			}   
			cursor_wait();			
			CheckoutHelperJS.RequestShippingDateAction = true;
			wc.service.invoke("OrderItemAddressShipMethodUpdate", params);
		}
	},
	
	
	/**
	 * This function shows or hides the shipping instruction input field depending on the state of the corresponding checkbox.
	 * If the checkbox is unchecked, and the 'AjaxCheckout' feature is enabled, the <code>OrderShippingInfoUpdate</code> service will be called to update the shipping information.
	 * Note that order items that have the same ship-to address and shipping method will share the same shipping instruction.
	 *
	 * @param {String} checkBoxName The ID of the shipping instruction checkbox.
	 * @param {String} divName The name of the div element that contains the shipping instruction input field.
	 * @param {String} suffix The suffix that is appended after the divName. It is usually the order item ID.
	 */
	checkShippingInstructionsBox:function(checkBoxName,divName,suffix){
		//var divName = "shippingInstructionsDiv";
		var thisCheckBoxName;
		var thisDivName;
		
		if(suffix != null && suffix != ""){
			thisCheckBoxName = checkBoxName + "_" + suffix;
			thisDivName = divName + "_" + suffix;
		}else{
			thisCheckBoxName = checkBoxName;
			thisDivName = divName;
		}
		
		var thisCheckBox = dojo.byId(thisCheckBoxName);
		
		if(thisCheckBox.checked){
			dojo.byId(thisDivName).style.visibility = "visible";
			dojo.byId(thisDivName).style.display = "block";
		}else{
			// If the checkbox is unchecked, hide the input field
			dojo.byId(thisDivName).style.visibility = "hidden";
			dojo.byId(thisDivName).style.display = "none";
		}
		
		// Update other shipping instructions div with same addressId and shipModeId..
		var addressId, shipModeId = "";
		if(this.shipmentTypeId == "1"){
			addressId = document.getElementById("singleShipmentAddress").value;
			shipModeId = document.getElementById("singleShipmentShippingMode").value; 
		}else if(this.shipmentTypeId == "2"){
			var orderItemId,tempAddressId,tempShipModeId = "";
			
			//get current div's shipModeId and addressId..
			addressId = document.getElementById("MS_ShipmentAddress_"+suffix).value;
			shipModeId = document.getElementById("MS_ShippingMode_"+suffix).value;

			var totalItems = document.getElementById("totalNumberOfItems").value;
			for(var i = 0; i < totalItems; i++){
				if(document.getElementById("qty_"+(i+1)) != null && document.getElementById("qty_"+(i+1)).value != -1){
					orderItemId = document.getElementById("orderItem_"+(i+1)).value;
					tempAddressId = document.getElementById("MS_ShipmentAddress_" + orderItemId).value;
					tempShipModeId = document.getElementById("MS_ShippingMode_" + orderItemId).value;
					if(tempShipModeId == shipModeId && tempAddressId == addressId){
						var tempDivName = divName + "_" + orderItemId;
						var tempCheckBoxName = checkBoxName + "_" + orderItemId;
						if(thisCheckBox.checked){
							dojo.byId(tempDivName).style.visibility = "visible";
							dojo.byId(tempDivName).style.display = "block";
							dojo.byId(tempCheckBoxName).checked = "checked";
						}
						else{
							//User doesnt want to specify shipping instructions and requested ship date..hide this div..
							dojo.byId(tempDivName).style.visibility = "hidden";
							dojo.byId(tempDivName).style.display = "none";
							dojo.byId(tempCheckBoxName).checked = "";
						}
					}
				}
			}
		}else{
			console.debug("shipmentTypeId is undefined. Single shipment has Id 1; multiple shipment has Id 2.");
		}
		
		// Delete shippingInstructions if the checkBox is unchecked and the checkout flow is AJAX
		if(!thisCheckBox.checked && this.isAjaxCheckOut()){
			var params = [];
			params["storeId"] = this.storeId;
			params["catalogId"] = this.catalogId;
			params["langId"] = this.langId;
			params.orderId = ".";
			
			var orderItemId = null;
			if(this.shipmentTypeId == "1"){
				if(document.getElementById("shipInstructions") != null){
					this.updateParamObject(params, "shipInstructions", "", false);
					document.getElementById("shipInstructions").value = "";
				}
				orderItemId = document.getElementById("orderItem_1").value;
				this.updateParamObject(params, "addressId", addressId, false);				
				this.updateParamObject(params, "orderItemId", orderItemId, false);
						
			} else if(this.shipmentTypeId == "2"){
				if(suffix != null && suffix != ""){
					if(document.getElementById("MS_shipInstructions_" + suffix) != null){
						this.updateParamObject(params, "shipInstructions", "", false);
						document.getElementById("MS_shipInstructions_" + suffix).value = "";
					}
					this.updateParamObject(params, "addressId", addressId, false, -1);
					this.updateParamObject(params, "orderItemId", suffix, false);
					this.setShippingInstuctionsForAllOtherItems(addressId,shipModeId,"");									
				}
			} else {
				console.debug("shipmentTypeId is undefined. Single shipment has Id 1; multiple shipment has Id 2.");
			}
			
			//For handling multiple clicks
			if(!submitRequest()){
				return;
			}   
			cursor_wait();			
			wc.service.invoke("OrderShippingInfoUpdate", params);
		}
	},
	
	
	/**
	 * This function sets the shipment type for the current page.
	 *
	 * @param {Integer} shipmentTypeId The shipment type ID, 1 for single shipment or 2 for multiple shipment.
	 *
	 * @see CheckoutHelperJS.getShipmentTypeId
	 */
	initializeShipmentPage:function(shipmentTypeId){
		this.shipmentTypeId = shipmentTypeId;
	},
	
	
	/**
	 * This function sets the common parameters for the current page, i.e. language ID, store ID and catalog ID.
	 *
	 * @param {Integer} langId The ID of the language that the store currently uses.
	 * @param {Integer} storeId The ID of the current store.
	 * @param {Integer} catalogId The ID of the catalog.
	 */
	setCommonParameters:function(langId,storeId,catalogId){
		this.langId = langId;
		this.storeId = storeId;
		this.catalogId = catalogId;
	},
	
	
	/**
	 * This function deletes an order item from the shopping cart.
	 * If forWishlist is true, then the item is added to the wish list subsequently by calling the <code>AjaxDeleteOrderItemFromCart</code> service.
	 *
	 * @param {Integer} orderItemId The ID of the order item to delete.
	 * @param {Boolean} forWishlist If the value is true, then the item is added to the wish list.
	 */
	deleteFromCart:function(orderItemId,forWishlist){ 
		if(!this.isAjaxCheckOut())return;
		
		var params = [];
		params.storeId = this.storeId;
		params.catalogId = this.catalogId;
		params.langId = this.langId;
		params.orderId = ".";
		params.orderItemId = orderItemId;
		
		var x = document.getElementById("totalNumberOfItems").value;
		var y = x;
		//Now remove free items from this total number of items count.. 
		//x = total items and y = totalItems - totalFreeItems
		for(var i = 0; i < x; i++){
			qty = document.getElementById("qty_"+(i+1)).value;
			if(qty == -1){
				y = y - 1;
			}
		}
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}   
		cursor_wait();			  
		if(y == 1){
			wc.service.invoke("AjaxDeleteOrderItem1", params);
		}else{
			if(forWishlist){
				wc.service.invoke("AjaxDeleteOrderItemFromCart", params);
			}else{
				if(this.shoppingCartPage){
					wc.service.invoke("AjaxDeleteOrderItem", params);
				}else{
					wc.service.invoke("AjaxDeleteOrderItemForShippingBillingPage", params);
				}
			}
		}
	},
	
	
	/**
	 * This function deletes an order item from the shopping cart then adds it to the wish list by calling the <code>AjaxInterestItemAddAndDeleteFromCart</code> service.
	 * It is used for the "Move to Wish List" button.
	 *
	 * @param {Integer} catEntryIdentifier The ID of the catalog entry.
	 * @param {Integer} orderItemId The ID for the order item to remove.
	 */
	addToWishListAndDeleteFromCart:function(catEntryIdentifier,orderItemId){
		if(!this.isAjaxCheckOut())return;
		
		var params = [];
		params.catEntryId = catEntryIdentifier;
		params.URL = "SuccessfulAJAXRequest";
		params.orderItemId = orderItemId;
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}
		cursor_wait();			  
		wc.service.invoke("AjaxInterestItemAddAndDeleteFromCart", params);
	},
	
	
	/**
	 * This function is used to update the ship-to address ID of all items in the current order when the user chooses to add a new address during order check-out.
	 * This function calls the <code>AjaxUpdateOrderItemsAddressId</code> service.
	 *
	 * @param {Integer} addressId The ID of the newly created address.
	 */
	updateAddressIdOFItemsOnCreateEditAddress:function(addressId){
		var params = [];
		params.orderId = ".";
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		var orderItemId = null;
		for(var i = 0; i < this.orderItemIds.length; i++){
			orderItemId = this.orderItemIds[i];
			this.updateParamObject(params,"orderItemId",orderItemId,false,-1);
			this.updateParamObject(params,"addressId",addressId,false,-1);
		}
              
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}              
		cursor_wait();			  
		wc.service.invoke("AjaxUpdateOrderItemsAddressId", params);
	},
	
	
	/**
	 * This function is used to save the current order items list when the user edits an existing address or creates a new address during order check-out.
	 *
	 * @param {Integer} orderItemId The order item ID.
	 * @param {String} addressId The ID of the address.
	 *
	 * @private
	 */
	saveOrderItemsList:function(orderItemId,addressId){
		if(orderItemId == '-1'){
			//Creating or editing shipping address for single shipment, get all the orderItemIds in the order..       
			var totalItems = document.getElementById("totalNumberOfItems").value;
			for(var i = 0; i < totalItems; i++){
				this.orderItemIds[i] = document.getElementById("orderItem_"+(i+1)).value;
			}
		}else if(orderItemId == 0 && this.shipmentTypeId == "1"){
			// Editing or creating billing address.. If it's single shipment type, then we need to save all orderItem Id's.
			// If the shipping address is same as this billing address which is edited, then after editing this addressId will change, so we need to update the orderItemIds.
			if (document.getElementById("singleShipmentAddress")) {
				if(addressId == document.getElementById("singleShipmentAddress").value){       
					var totalItems = document.getElementById("totalNumberOfItems").value;
					for(var i = 0; i < totalItems; i++){
						this.orderItemIds[i] = document.getElementById("orderItem_"+(i+1)).value;
					}
				}else {
					this.orderItemIds = [];
				}
			} else {
				this.orderItemIds = [];
			}
			return;
		}else{
			// OrderItemId is passed..so it's multiple shipment, get all the orderItemIds with the same address...
			// This section is for multiple shipment and create/edit both shipping/billing address...
			var totalItems = document.getElementById("totalNumberOfItems").value;
			var temp = null;
			var orderItemId = null;
			var j = 0;
			for(var i = 0; i < totalItems; i++){
				orderItemId = document.getElementById("orderItem_"+(i+1)).value;
				if (document.getElementById("MS_ShipmentAddress_"+orderItemId)){
					temp = document.getElementById("MS_ShipmentAddress_"+orderItemId).value;
					if(temp == addressId){
						//Add this to our list..
						this.orderItemIds[j++] = orderItemId;
					}
				}
			}
		}
	},
	
		
	/**
	 * By convention, all items in an order that have the same shipping address and shipping mode share the same shipping instruction.
	 * This function is used to update the shipping instruction of all items that have the same shipping address and shipping mode.
	 *
	 * @param {Integer} addressId The shipping address ID.
	 * @param {Integer} shipModeId The shipping mode ID.
	 * @param {String} shipInstructions The shipping instruction.
	 */
	setShippingInstuctionsForAllOtherItems:function(addressId,shipModeId,shipInstructions){
	
		var orderItemId,addressId1,shipModeId1 = "";
		var totalItems = document.getElementById("totalNumberOfItems").value;
		for(var i = 0; i < totalItems; i++){
			if(document.getElementById("qty_"+(i+1)) != null && document.getElementById("qty_"+(i+1)).value != -1){
				orderItemId = document.getElementById("orderItem_"+(i+1)).value;
				addressId1 = document.getElementById("MS_ShipmentAddress_"+orderItemId).value;
				shipModeId1 = document.getElementById("MS_ShippingMode_"+orderItemId).value;
				if(shipModeId1 == shipModeId && addressId1 == addressId){
					document.getElementById("MS_shipInstructions_"+orderItemId).value = shipInstructions;
				}
			}
		}
	},
	
	
	/**
	 * When a user toggles the 'ship as complete' checkbox, the same will be updated at the server side by invoking the <code>OrderShippingInfoUpdate</code> service.
	 * This function is used when the 'AjaxCheckout' feature is enabled.
	 *
	 * @param {DOM Element} checkBox The 'ship as complete' checkbox object.
	 */
	shipAsComplete:function(checkBox){
		if(!this.isAjaxCheckOut())return;
		var params = [];
		params.orderId = ".";
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		if(checkBox.checked){
			this.updateParamObject(params,"ShipAsComplete","Y",true);
		}else{
			this.updateParamObject(params,"ShipAsComplete","N",true);
		}
		orderItemId = document.getElementById("orderItem_1").value;
		this.updateParamObject(params,"orderItemId",orderItemId,false);
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}               
		cursor_wait();
		wc.service.invoke("OrderShippingInfoUpdate", params);
	},
	
	
	/**
	 * When there is an invalid address ID in an order, this function updates all items to use the valid address ID by invoking the <code>AjaxSetAddressIdOfOrderItems</code> service.
	 *
	 * @param {Integer} addressId A valid address ID.
	 */
	updateAddressIdForOrderItem:function(addressId){
		if(addressId == null || addressId.length == 0){
			return true;
		}
		
		var params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		
		this.updateParamObject(params,"addressId",addressId,false);
		wc.service.invoke("AjaxSetAddressIdOfOrderItems", params);    
	},
	
	
	/**
	 * When there is an invalid shipping mode ID in an order, this function updates all items to use the valid shipping mode ID by invoking the <code>AjaxSetShipModeIdForOrder</code> service.
	 *
	 * @param {Integer} shipModeId A valid shipping mode ID.
	 */
	updateShipModeIdForOrder:function(shipModeId){
		var params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params["shipModeId"] = shipModeId;
		wc.service.invoke("AjaxSetShipModeIdForOrder", params);
	},
	
	
	/**
	 * This function is used to apply a promotion code to the order.
	 *
	 * @param {String} formName	The name of the promotion code entry form.
	 * @param {String} returnView	The name of the view that the server should redirect the browser to after a promotion code is applied.
	 */
	applyPromotionCode:function(formName,returnView) {
		var form = document.forms[formName];
		if (trim(form.promoCode.value) == "") {
			MessageHelper.formErrorHandleClient(form.promoCode.id, MessageHelper.messages["PROMOTION_CODE_EMPTY"]);
			return;
		}
		if(this.isAjaxCheckOut()){
			service = wc.service.getServiceById('AjaxPromotionCodeManage');
			service.formId = formName;
			//URL is required for web1.0 style of request.. if defined, set them back to null so that it works
			//well with ajax style requests...
			if (form.URL != null ){
				form.URL.value = "";
			}
                     
			//For handling multiple clicks
			if(!submitRequest()){
				return;
			}                      
			cursor_wait();
			wc.service.invoke('AjaxPromotionCodeManage');
		}else{
			//Invoke normal web1.0 kind of server call..submit the PromotionCodeForm..
			//we need errorViewName in web1.0 style of request..if we define it directly in form, then when we use web2.0 style of
			//request it wont work..it submits to this errorView instead of AjaxActionErrorResponse. So define it here..
			if(returnView == null || returnView == "" || returnView == "undefined"){
				returnView = "OrderShippingBillingView";
			}
			var input = document.createElement("INPUT");
			input.setAttribute("type", "hidden");
			input.setAttribute("name", "errorViewName");
			input.setAttribute("value", returnView);
			form.appendChild(input);
			form.URL.value = "OrderCalculate?updatePrices=1&calculationUsageId=-1&URL="+returnView;
			
			//For handling multiple clicks
			if(!submitRequest()){
				return;
			}
			
			form.submit();
		}
	},
	
	
	/**
	 * This function is used to remove a promotion code from the order.
	 *
	 * @param {String} formName	The name of the promotion code entry form.
	 * @param {String} promoCode	The promotion code to remove.
	 * @param {String} returnView	The name of the view that the server should redirect the browser to after a promotion code is applied.
	 */
	removePromotionCode:function(formName, promoCode,returnView) {
		var form = document.forms[formName];
		form.taskType.value='R';
		form.promoCode.value=promoCode;
		
		if(this.isAjaxCheckOut()){
			service = wc.service.getServiceById('AjaxPromotionCodeManage');
			service.formId = formName;
			
			//For handling multiple clicks
			if(!submitRequest()){
				return;
			}                      
			cursor_wait();
			wc.service.invoke('AjaxPromotionCodeManage');
		}else{
			if(returnView == null || returnView == "" || returnView == "undefined"){
				returnView = "OrderShippingBillingView";
			}
			//Invoke normal web1.0 kind of server call..submit the PromotionCodeForm..
			form.URL.value = "OrderCalculate?updatePrices=1&calculationUsageId=-1&URL="+returnView;
			
			//For handling multiple clicks
			if(!submitRequest()){
				return;
			}
			form.submit();
		}
	},
	
	
	/**
	 * If a customer has a coupon in his/her coupon wallet that has not been applied to an order then this function can be used to apply that coupon to the current order.
	 *
	 * @param {String} formName The name of the form that performs the action to apply the coupon, and holds the parameters to pass to the service.
	 * @param {String} returnView The view to return to after the request has been processed.
	 * @param {Integer} couponId The unique ID of the coupon. This is set into the form to be sent to the service.
	 */
	applyCoupon:function(formName,returnView,couponId) 
	{
		var form = document.forms[formName];
		form.couponId.value = couponId;
		form.taskType.value= "A";
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}                                 
		if(this.isAjaxCheckOut())
		{
			service = wc.service.getServiceById('AjaxCouponsAddRemove');
			service.formId = formName;                 
			cursor_wait();
			wc.service.invoke('AjaxCouponsAddRemove');
		}
		else
		{
			form.URL.value = "OrderCalculate?updatePrices=1&calculationUsageId=-1&URL="+returnView;
			form.submit();
		}
	},
	
	
	/**
	 * If a customer has a coupon in his/her coupon wallet that has been applied to an order then this function can be used to remove that coupon from the current order.
	 *
	 * @param {String} formName The name of the form that performs the action to remove the coupon from the order, and holds the parameters to pass to the service.
	 * @param {String} returnView The view to return to after the request has been processed.
	 * @param {Integer} couponId The unique ID of the coupon. This is set into the form to be sent to the service.
	 */
	removeCouponFromOrder:function(formName,returnView,couponId)
	{
		var form = document.forms[formName];
		
		form.couponId.value = couponId;
		form.taskType.value= "R";
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}                   
		if(this.isAjaxCheckOut())
		{
			service = wc.service.getServiceById('AjaxCouponsAddRemove');
			service.formId = formName;
			cursor_wait();
			wc.service.invoke('AjaxCouponsAddRemove');
		}
		else
		{
			form.URL.value = "OrderCalculate?updatePrices=1&calculationUsageId=-1&URL="+returnView;
			form.submit();
		}
	},

	
	/**
	 * Sets the ajaxCheckOut variable to indicate if the 'AjaxCheckout' feature is enabled.
	 * 
	 * @param {Boolean} ajaxCheckOut A true/false value that indicates if the 'AjaxCheckout' feature is enabled.
	 *
	 * @see CheckoutHelperJS.isAjaxCheckOut
	 */
	setAjaxCheckOut:function(ajaxCheckOut){
		this.ajaxCheckOut = ajaxCheckOut;
	},
	
	
	/**
	 * Returns the ajaxCheckOut variable that indicates if the 'AjaxCheckout' feature is enabled.
	 * 
	 * @returns {Boolean} ajaxCheckOut A true/false value that indicates if the 'AjaxCheckout' feature is enabled.
	 *
	 * @see CheckoutHelperJS.setAjaxCheckOut
	 */
	isAjaxCheckOut:function(){
		return this.ajaxCheckOut;
	},
	
	
	/**
	 * This function is used to submit the order by invoking the <code>AjaxSubmitOrder</code> service.
	 *
	 * @param {Integer} orderId The order ID.
	 * @param {String} userType The type of the current user.
	 * @param {String} addressListForMailNotification The list of emails spearated by space. Order confirmation will be sent to these emails.
	 */
	checkoutOrder:function(orderId,userType,addressListForMailNotification){
		params = [];
		params["orderId"] = orderId;
		params["notifyMerchant"] = 0;
		params["notifyShopper"] = 0;
		params["notifyOrderSubmitted"] = 1;
		if(userType == 'G'){
			//append the user-entered email to addressListForMailNotification for guest users only.   
			var payInStoreEmailAddress = document.getElementById('PayInStoreEmailAddress');
			if(payInStoreEmailAddress != null){
				if(payInStoreEmailAddress.value=="" || payInStoreEmailAddress.value==null){
					MessageHelper.formErrorHandleClient(payInStoreEmailAddress, MessageHelper.messages["ERROR_EmailEmpty"]);
					return;
				}else if(!MessageHelper.isValidUTF8length(payInStoreEmailAddress.value, 256)){ 
					MessageHelper.formErrorHandleClient(payInStoreEmailAddress, MessageHelper.messages["ERROR_EmailTooLong"]);
					return;
				}else if(!MessageHelper.isValidEmail(payInStoreEmailAddress.value)){
					MessageHelper.formErrorHandleClient(payInStoreEmailAddress, MessageHelper.messages["ERROR_INVALIDEMAILFORMAT"]);
					return;
				}else {
					//addressListForMailNotification is separated by space. Append a space before appending the value of payInStoreEmailAddress
					addressListForMailNotification += ' ' + payInStoreEmailAddress.value;
				}
			}
			
			//addressListForMailNotification contains list of emailId's spearated by space.. remove leading or trailing spaces..
			addressListForMailNotification = trim(addressListForMailNotification);
			
			//Get the space separated email list in an array...
			var emailList = [];
			emailList = addressListForMailNotification.split(" ");
			
			//Now from this array, remove repeated email Id's.. keep only unique email Id's
			var uniqueList = [];
			for(var j = 0; j < emailList.length; j++){
				uniqueList[emailList[j]] = emailList[j];
			}
			
			//Get the total length of unique email id's list..
			var totalLength = 0;
			for(i in uniqueList){
				totalLength = totalLength + 1;
			}
			
			//Convert the unique List array into comma separated values...
			var temp = "";
			var k = 0;
			for(i in uniqueList){
				k = k + 1;
				temp = temp + uniqueList[i];
				if( k < totalLength){
					//If not last value, add , before next value..
					temp = temp + ",";
				}
			}
			//For guest user send the email list..
			params["notify_EMailSender_recipient"] = temp;
		} else {
			params["notify_EMailSender_recipient"] = addressListForMailNotification;
		}
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}                 
		cursor_wait();
		wc.service.invoke("AjaxSubmitOrder",params);
	},
	
	
	/**
	 * When a user wants to create a new address during order check-out, this function can be used.
	 * 
	 * @param {Integer} orderItemId The order item ID for a multiple shipment scenario, or 0 to indicate a shipping address needs to be created, or 1 to indicate a billing address needs to be created.
	 * @param {String} addressType The type of the address to be created.
	 */
	createAddress:function(orderItemId,addressType){
		this.saveOrderItemsList(orderItemId,"-1");
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}                 
		var checkForOpera = true; //require a check of whether the browser is opera or not
		cursor_wait(checkForOpera);
		wc.render.updateContext('editShippingAddressContext', {'shippingAddress':'-1','addressType':addressType});
		//Hide the mainContents (contains shipping/billing details, shop cart details, promotion details, orderDetails)
		this.showHideDivs('editAddressContents','mainContents');
	},
	
	
	/**
	 * This function is used to show an area and hide an area on the current page.
	 *
	 * @param {String} showArea The ID of the area to show.
	 * @param {String} hideArea The ID of the area to hide.
	 * 
	 * @private
	 */
	showHideDivs:function(showArea,hideArea){
		document.getElementById(hideArea).style.display = "none";
		document.getElementById(showArea).style.display = "block";
	},
	
	
	/**
	 * Restores the previous address details when a user cancels editing an existing address or cancels creating a new address.
	 *
	 * @see CheckoutHelperJS.cancelEditAddress
	 */
	restorePreviousAddressDetails:function(){
		var valueRestored = false;
		
		//For non-Ajax flow
		//Restore previous shipping address values from arrray	if value is available
		if(!this.isAjaxCheckOut()){
			//Use the addresses saved in local array...server will be updated with these new addresses once user clicks on update button..
			for(i in this.selectedAddressesArray){
				if(document.getElementById(i).value == -1){
					//IF createAddress is selected in this box, then restore it to previously selected value..
					document.getElementById(i).value = this.selectedAddressesArray[i];
					valueRestored = true;
					
					//Single shipment only
					//The shipping address details does not update automatically when the select box value is set
					//Manually update the address details
					if(this.shipmentTypeId == "1"){
						this.displayAddressDetails(document.getElementById("singleShipmentAddress"),'Shipping');
					}	                           
				}
			}
		}       
		
		//For Ajax flow or non-Ajax flow when the previous shipping address is not available in the array
		if(this.isAjaxCheckOut() || !valueRestored){
			//Save the addresses present on server side only.. on change of address the server will be updated in ajax checkout..so can use 
			//the address from server side only..
			if(this.shipmentTypeId == "2"){
				for(var i = 0; i < this.orderItemIds.length; i++){
				    	//Get the orderItemId
				    	var orderItemId = this.orderItemIds[i];
					var element = document.getElementById("MS_ShipmentAddress_"+orderItemId);
					
					if(element != null && element.value == -1){
						//IF createAddress is selected in this box, then restore it to previously selected value..
						element.value = document.getElementById("addressId_"+orderItemId).value;
					}
				}
			} else if(this.shipmentTypeId == "1"){
				var element = document.getElementById("singleShipmentAddress");
		 		if (element != null && document.getElementById("addressId_all")) {
					element.value = document.getElementById("addressId_all").value;
					
					//Manually update the shipping address details for non-Ajax/Single shipment flow
					if(!this.isAjaxCheckOut()){
						this.displayAddressDetails(element,'Shipping');
					}
				}
			}
		}
		
		//Restore the original billing address(es) that was updated on the server
		for(var i = 1; i < 4; i++){
			//Find the payment forms that are present on the page
			if(document.getElementById("PaymentForm"+i) != null){
				var paymentForm = document.getElementById("PaymentForm"+i);
				//Restore the selected billing address if it "create address" was selected
				if(paymentForm.billing_address_id.value == -1){
					paymentForm.billing_address_id.value = document.getElementById("selectedAddressId_"+i).value;
					
					if(!this.isAjaxCheckOut()){
						CheckoutPayments.displayBillingAddressDetailsWeb10(paymentForm.billing_address_id,i);
					}                                   
				}
			}
		}              
	},
	
	
	/**
	 * This function is used when a user edits an existing shipping address during check-out.
	 *
	 * @param {String} addressSelectBoxName The ID of the address drop-down object.
	 * @param {Integer} orderItemId The item ID. It is required in the a multiple shipment scenario.
	 * @param {String} profileshipping The name of the quick checkout profile shipping address.
	 * @param {String} profilebilling The name of the quick checkout profile billing address.
	 */
	editAddress:function(addressSelectBoxName,orderItemId,profileshipping,profilebilling){
		var addressBox = document.getElementById(addressSelectBoxName);
		
		//We need to save order Items having this addressId..bcs if user edits this address then the id of this address changes..
		//so all order items needs to be udpated with new id..
		this.saveOrderItemsList(orderItemId,addressBox.value);
		
		// the quick checkout address nick name is hardcoded here..it should be same as that used in quick checkout profile page..
		if(addressBox.options[addressBox.selectedIndex].text == profileshipping || addressBox.options[addressBox.selectedIndex].text == profilebilling){
			if(addressSelectBoxName != null){
				MessageHelper.formErrorHandleClient(addressSelectBoxName, MessageHelper.messages["ERROR_QUICKCHECKOUT_ADDRESS_CHANGE"]);
			} else{
				MessageHelper.displayErrorMessage(MessageHelper.messages["ERROR_QUICKCHECKOUT_ADDRESS_CHANGE"]);
			}
			return;
		}
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}   
		//Update the display area context..
		cursor_wait();
		wc.render.updateContext('editShippingAddressContext', {'shippingAddress':addressBox.value});
		
		//Hide the mainContents (contains shipping/billing details, shop cart details, promotion details, orderDetails)
		this.showHideDivs('editAddressContents','mainContents');
	},
	
	
	/**
	 * This function is used when a user edits an existing billing address during check-out.
	 *
	 * @param {Integer} orderItemId The item ID.
	 * @param {Integer} paymentArea The payment area number that this billing address belongs to.
	 * @param {String} profileshipping The name of the quick checkout profile shipping address.
	 * @param {String} profilebilling The name of the quick checkout profile billing address.
	 */
	editBillingAddress:function(orderItemId,paymentArea,profileshipping,profilebilling){
		var form = document.forms["PaymentForm"+paymentArea];
		var addressBox = form.billing_address_id;
		
		//We need to save order Items having this addressId..bcs if user edits this address then the id of this address changes..
		//so all order items needs to be udpated with new id..
		this.saveOrderItemsList(orderItemId,addressBox.value);
		
		// the quick checkout address nick name is hardcoded here..it should be same as that used in quick checkout profile page..
		if(addressBox.options[addressBox.selectedIndex].text == profileshipping || addressBox.options[addressBox.selectedIndex].text == profilebilling){
			if(addressBox != null){
				MessageHelper.formErrorHandleClient(addressBox, MessageHelper.messages["ERROR_QUICKCHECKOUT_ADDRESS_CHANGE"]);              			
			} else {              		
				MessageHelper.displayErrorMessage(MessageHelper.messages["ERROR_QUICKCHECKOUT_ADDRESS_CHANGE"]);
			}
			return;
		}
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}   
		//Update the display area context..
		cursor_wait();
		wc.render.updateContext('editShippingAddressContext', {'shippingAddress':addressBox.value});
		
		//Hide the mainContents (contains shipping/billing details, shop cart details, promotion details, orderDetails)
		this.showHideDivs('editAddressContents','mainContents');
	},
	
	
	/**
	 * When a user cancels editing an address, this function is called to hide the address entry form and show the original main content of the page, then calls restorePreviousAddressDetails to restore the previous address.
	 *
	 * @see CheckoutHelperJS.restorePreviousAddressDetails
	 */
	cancelEditAddress:function(){
		this.showHideDivs('mainContents','editAddressContents');
		this.restorePreviousAddressDetails();
	},
	
	
	/**
	 * This function gets the shipment type Id for the order. Shipment type Id 1 is for single shipment, 2 for multiple shipment.
	 *
	 * @see CheckoutHelperJS.initializeShipmentPage
	 */
	getShipmentTypeId:function(){
		return this.shipmentTypeId;
	},
	
	
	/**
	 * Sets the dataDiry flag to indicate if the payment method input has been changed by the user.
	 *
	 * @param {Boolean} flag A true/false value to indicate if the payment method input has been changed.
	 *
	 * @see CheckoutHelperJS.isPaymentDataDirty
	 */
	paymentDataDirty:function(flag){
		this.dataDirty = flag;
	},
	
	/**
	 * Returns the dataDiry flag that indicates if the payment method input has been changed by the user.
	 *
	 * @param {Boolean} flag A true/false value to indicate if the payment method input has been changed.
	 *
	 * @see CheckoutHelperJS.paymentDataDirty
	 */
	isPaymentDataDirty:function(){
		return this.dataDirty;
	},
	
	
	/**
	 * Start DOM/BOPIS functions
	 **/
	
	/**
	 * Shows the address details of the store pick-up location selected by a user and hides the details of all other addresses.
	 * All store pick-up locations on the HTML page shuold have "addressDetails_<storelocationId>" as ID.
	 *
	 * @param {DOM Element} addressSelectBox The select drop-down object that contains all available store pick-up addresses.
	 */
	displayStoreAddressDetails:function(addressSelectBox){
		var selectedAddressId = addressSelectBox.value;
		for(j=0; j < addressSelectBox.options.length; j++){
			if(addressSelectBox.options[j].value == selectedAddressId){
				dojo.byId("addressDetails_"+addressSelectBox.options[j].value).style.display = "block";
			}
			else{
				dojo.byId("addressDetails_"+addressSelectBox.options[j].value).style.display = "none";
			}
		}
	},
	
	
	/**
	 * Updates all order items in the current order with the store pick-up location and the pick-up in store shipping mode by invoking the <code>AjaxUpdateOrderItem</code> service.
	 * This function is used when the 'AjaxCheckout' feature is enabled.
	 *
	 * @param {DOM Element} addressSelectBox The select drop-down object that contains all available store pick-up addresses.
	 */
	updateStoreAddressForAllItems:function(addressSelectBox){
		if(!this.isAjaxCheckOut())return;
		var addressId = addressSelectBox.value;
		
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		
		var orderItemId = null;
		var totalItems = document.getElementById("totalNumberOfItems").value;
		var addressId = document.getElementById("singleShipmentAddress").value;
		for(var i = 0; i < totalItems; i++){
			orderItemId = document.getElementById("orderItem_"+(i+1)).value;
			this.updateParamObject(params,"orderItemId",orderItemId,false,-1);
			this.updateParamObject(params,"physicalStoreId",addressId,false,-1);
		}
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}                 
		cursor_wait();
		wc.service.invoke("AjaxUpdateOrderItem", params);
	},
	
	
	/**
	 * Updates a single order item in the current order with the shipping mode and store pick-up location or personal address selected by the user by invoking the <code>AjaxUpdateOrderItem</code> service. 
	 * The different sections in the page that contain the shipping method selection, advanced shipping options, store pick up location, and shipping addresses will be shown or hidden depending on the selection made on the shippingModeSelectBox object.
	 * This function is used when the 'AjaxCheckout' feature is enabled.
	 *
	 * @param {DOM Element} shippingModeSelectBox The select drop-down object that contains all available shipping modes.
	 * @param {Integer} orderItemId The ID of the item to update.
	 * @param {String} pickUpInStoreShipMode The identifier for the pick-up in store shipping mode.
	 */
	updateShippingModeAndAddressForOrderItem:function(shippingModeSelectBox, orderItemId, pickUpInStoreShipMode){
		if(!this.isAjaxCheckOut())return;
		
		var selectedShippingMode = shippingModeSelectBox.value;
		if (pickUpInStoreShipMode == selectedShippingMode) {
			document.getElementById("MS_ShipMode_Section_"+orderItemId).className = "nodisplay";
			document.getElementById("MS_ShipAdvancedOptions_Section_"+orderItemId).className = "nodisplay";
			document.getElementById("MS_ShippingAddress_Section_"+orderItemId).className = "nodisplay";
			document.getElementById("MS_StoreAddress_Section_"+orderItemId).className = "";
		} else {
			document.getElementById("MS_ShipMode_Section_"+orderItemId).className = "";
			document.getElementById("MS_ShipAdvancedOptions_Section_"+orderItemId).className = "";
			document.getElementById("MS_ShippingAddress_Section_"+orderItemId).className = "";
			document.getElementById("MS_StoreAddress_Section_"+orderItemId).className = "nodisplay";
		}
		
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params["orderId"] = ".";
		params["orderItemId"] = orderItemId;
		params["shipModeId"] = selectedShippingMode;
		
		if (pickUpInStoreShipMode == selectedShippingMode) {
			var physicalStoreId = document.getElementById("MS_StoreSelectBox_"+orderItemId).value;
			params["physicalStoreId"] = physicalStoreId;
		} else {
			if (document.getElementById("MS_ShipmentAddress_"+orderItemId)) {
				var addressId = document.getElementById("MS_ShipmentAddress_"+orderItemId).value;
				params["addressId"] = addressId;
			}
		}
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}                 
		cursor_wait();			  
		wc.service.invoke("AjaxUpdateOrderItem", params);
	},
	
	
	/**
	 * Updates a single order item in the current order with the store pick-up location selected by the user by invoking the <code>AjaxUpdateOrderItem</code> service.
	 * This function is used when the 'AjaxCheckout' feature is enabled.
	 * 
	 * @param {DOM Element} storeAddressSelectBox The select drop-down object that contains all available store pick-up locations.
	 * @param {Integer} orderItemId The ID of the order item to update.
	 */
	updateStoreAddressForOrderItem:function(storeAddressSelectBox, orderItemId){
		if(!this.isAjaxCheckOut())return;
		
		var selectedPickUpStoreId = storeAddressSelectBox.value;
		
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params["orderId"] = ".";
		params["orderItemId"] = orderItemId;
		params["physicalStoreId"] = selectedPickUpStoreId;
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}                 
		cursor_wait();
		wc.service.invoke("AjaxUpdateOrderItem", params);
	},
       
	/**
	 * End DOM/BOPIS functions
	 **/
	
	
	
	/**
	 * Sets fieldDirtyFlag to indicates if the value of a shipping information related input field or the quantity of an item has been changed by the user.
	 *
	 * @param {Boolean} value A true/false value that indicates if the value of a shipping information related input field or the quantity of an item has been changed by the user.
	 *
	 * @see CheckoutHelperJS.getFieldDirtyFlag
	 */
	setFieldDirtyFlag: function(value){
		this.fieldDirtyFlag = value;
	},
	
	
	/**
	 * Returns fieldDirtyFlag that indicates if the value of a shipping information related input field or the quantity of an item has been changed by the user.
	 *
	 * @returns {Boolean} fieldDirtyFlag A true/false value that indicates if the value of a shipping information related input field or the quantity of an item has been changed by the user.
	 *
	 * @see CheckoutHelperJS.setFieldDirtyFlag
	 */
	getFieldDirtyFlag: function(){
		return this.fieldDirtyFlag;
	},
	
	
	
	/************************************************************
	 * The following methods are used on the Shopping Cart page
	 ************************************************************/
	
	/**
	 * This function updates the total on the shopping cart page when the quantity of an item has been changed. It is used when the "AjaxCheckOut" feature is enabled.
	 * It updates the total by calling <code>updateCart</code> after <code>updateWaitTimeOut</code> milliseconds have passed.
	 *
	 * @param {DOM Element} quantityBox The quantity input text field.
	 * @param {Integer} orderItemId The ID of the order item to update.
	 * @param {Object} event A keyboard event object.
	 * 
	 * @see CheckoutHelperJS.updateCart
	 */
	updateCartWait:function(quantityBox, orderItemId,event) {
		if(event.keyCode == dojo.keys.TAB)return;
		if(!this.isAjaxCheckOut()){ 
			return;
		}
		
		//Key pressed.. update the flag
		if(this.keyPressCount[orderItemId] == null && isNaN(this.keyPressCount[orderItemId])){
			this.keyPressCount[orderItemId] = 0;
		}
		this.keyPressCount[orderItemId] = parseInt(this.keyPressCount[orderItemId]) + 1;       
		setTimeout(dojo.hitch(this,"updateCart",quantityBox,orderItemId,this.keyPressCount[orderItemId]),this.updateWaitTimeOut);
	},
	
	
	/**
	 * This function updates the total on the shopping cart page when the quantity of an item has been changed. It is used when the "AjaxCheckOut" feature is enabled.
	 * It updates the shopping cart by calling the <code>AjaxUpdateOrderItem</code> service.
	 *
	 * @param {DOM Element} quantityBox The quantity input text field.
	 * @param {Integer} orderItemId The ID of the order item to update.
	 * @param {Integer} keyPressCountValue The count of keyPress events. If there are more keyPress events after this event was fired, then this function just returns without doing anything.
	 */
	updateCart:function(quantityBox, orderItemId,keyPressCountValue){
		if(keyPressCountValue < this.keyPressCount[orderItemId]){
			//User has pressed one more key..that key press call will update the server..no work for me..
			return;
		}
		var quantity = (quantityBox.value);
		if(quantity != null && quantity.length > 0 && !isNaN(quantity)){
			/* It's a number..Parse it...Without the above isNaN check, in IE parseInt parses strings like '41ab' as 41..
			So check if its a number first and then parse it..*/
			quantity = parseInt(quantity);
		}
		if(quantity != null && quantity.length > 0 && quantity == 0){
			//In IE, if quantity is null, then quantity == 0 check evaluates to true..so having too many checks above..
			//We can call AjaxUpdateOrderItem service and set qty == 0, which will delete item from cart.. but calling
			//deleteFromCart will ensure that empty shop cart page is displayed in case if this is the last item..something we get for free..
			this.deleteFromCart(orderItemId);
		}else if(isNaN(quantity) || ((!isNaN(quantity)) && quantity < 0) || quantity == null || quantity.length == 0){
			//Its not a number OR its a number and its negative OR its a null OR its an empty string..
			MessageHelper.displayErrorMessage(MessageHelper.messages["QUANTITY_INPUT_ERROR"]);
		} else {
			//Its a positive valid number > 0...Update the qty at server side..
			var params = [];
			params.orderId = ".";
			params["storeId"] = this.storeId;
			params["catalogId"] = this.catalogId;
			params["langId"] = this.langId;
			this.updateParamObject(params,"orderItemId",orderItemId,false,-1);
			this.updateParamObject(params,"quantity",quantity,false,-1);
			
			//For handling multiple clicks
			if(!submitRequest()){
				return;
			}                     
			cursor_wait();
			wc.service.invoke("AjaxUpdateOrderItem",params);
		}
	},
	
	
	/**
	 * When the 'AjaxCheckout' feature is disabled, on page load, this function registers all item quantity fields on the 'Shopping Cart' page to the Dojo event listener. 
	 * If any of the fields has been changed by the user, the user will be asked to update the shopping cart before proceeding to the next page.
	 */
	initDojoEventListenerShoppingCartPage:function(){
		// If empty shopping cart, no need to add anything to event listener
		if(document.getElementById("totalNumberOfItems") != null){
			var totalItems = document.getElementById("totalNumberOfItems").value;
			
			if(totalItems != null && totalItems > 0){
				for(var i = 0; i < totalItems; i++){
					var object = dojo.byId("quantity_" + (i+1));
					if(object != null){
						dojo.connect(object, 'onchange', setDirtyFlag);
					}
				}
			}else{
				console.debug("error: element 'totalNumberOfItems' was expected but undefined.");
				return;
			}
		}
	},
	
	
	/**
	 * Validates the quantity of all items on the 'Shopping Cart' page.
	 * This function is used when the 'AjaxCheckout' feature is disabled.
	 *
	 * @param {DOM Element} form The form object that contains the table of order items.
	 */
	updateShoppingCart:function(form) {
		var totalItems = document.getElementById("totalNumberOfItems").value;
		if(totalItems != null){
			for(var i = 0; i < totalItems; i++){
				//Update qty for all items
				if (form["quantity_"+(i+1)]) {
					var v = form["quantity_"+(i+1)].value;                            
					
					if(v=="" || isNaN(v) || v < 0) {
						//Its empty or not a valid number or its a negative number...
						MessageHelper.formErrorHandleClient(document.getElementById("quantity_"+(i+1)).id,MessageHelper.messages["QUANTITY_INPUT_ERROR"]);
						return;
					}
				}
			}
			
			//For handling multiple clicks
			if(!submitRequest()){
				return;
			}
			
			form.submit();
			this.setFieldDirtyFlag(false);
		}else{
			console.debug("error: element 'totalNumberOfItems' was expected but undefined.");
			return;
		}
	},
	
	
	/**
	 * Updates the shopping cart in a 'quick check-out' scenario by invoking the <code>QuickCheckOutOrderCopy</code> service.
	 *
	 * @param {Integer} quickOrderId The ID of the quick check-out order.
	 */
	updateCartWithQuickCheckoutProfile:function(quickOrderId){
		var params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.toOrderId = ".";
		params["shippingAddressFromOrderProfile"] = "1";
		params["shippingModeFromOrderProfile"] = "1";
		params["URL"] = "dummy";
		params["payInfoFrom"] = quickOrderId;
		
		wc.service.declare({
			id: "QuickCheckOutOrderCopy",
			actionId: "QuickCheckOutOrderCopy",
			url: "AjaxOrderCopy",
			successHandler: function(serviceResponse) {
				cursor_clear();
				document.location.href="OrderProcessServiceOrderPrepare?storeId="+CheckoutHelperJS.storeId+"&catalogId="+CheckoutHelperJS.catalogId+"&langId="+CheckoutHelperJS.langId+"&orderId=.&URL=OrderShippingBillingView?langId="+CheckoutHelperJS.langId+"&storeId="+CheckoutHelperJS.storeId+"&catalogId="+CheckoutHelperJS.catalogId+"&quickCheckoutProfileForPayment=true";
			},
			failureHandler: function(serviceResponse) {
				if (serviceResponse.errorMessage) {
					MessageHelper.displayErrorMessage(serviceResponse.errorMessage);
				} else {
					if (serviceResponse.errorMessageKey) {
						MessageHelper.displayErrorMessage(serviceResponse.errorMessageKey);
					}
				}
				cursor_clear();
			}
		});
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}                 
		cursor_wait();
		wc.service.invoke("QuickCheckOutOrderCopy",params);
	},
	
	
	/************************************************************
	 * End Shopping Cart page specific functions
	 ************************************************************/
	
	
	
	/**************************************************************
	 * The following methods are used on the Single Shipment page
	 **************************************************************/
	
	/**
	 * Helper function used for adding a new address in a single shipment scenario.
	 *
	 * @param {String} addressType The type of the selected address.
	 */
	addNewShippingAddress:function(addressType){
		//using JavaScript DOM to simulate the drop down selection */
		var dropdown = document.getElementById('singleShipmentAddress');
		dropdown.value=-1;
		this.displayAddressDetails(dropdown,addressType);
	},
	
	
	/**
	 * This function is used to update the address of all order items in a single shipment checkout-out scenario.
	 * It is used when the "AjaxCheckout" feature is enabled.
	 *
	 * @param {DOM Element} addressSelectBox The select drop-down object that contains all available addresses.
	 */
	updateAddressForAllItems:function(addressSelectBox){
		//Save it in local array..
		if(addressSelectBox.value != -1){
			this.selectedAddressesArray[addressSelectBox.name] =  addressSelectBox.value;
		}
		
		if(!this.isAjaxCheckOut())return;
		var addressId = addressSelectBox.value;
		if(addressId == -1){
			return;
		}
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		
		var addressId = document.getElementById("singleShipmentAddress").value;
		this.updateParamObject(params,"addressId",addressId,false);
		
		var enabledShipInstructions = false;
		var shipInstructions;
		
		//Check if Shipping Instructions is enabled
		if(document.getElementById("shipInstructions") != null){
			shipInstructions = document.getElementById("shipInstructions").value;
			
			reWhiteSpace = new RegExp(/^\s+$/);
			if(reWhiteSpace.test(shipInstructions)){
				shipInstructions = "";
			}
			enabledShipInstructions = true;
		}
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}              
		cursor_wait(); 
		
		//If Shipping Instructions is enabled & there are some shipping instructions entered
		//Update both the shipping address and shipping instructions
		//Else only update shipping address	  
		if(!enabledShipInstructions || shipInstructions == undefined || shipInstructions == "") {
			wc.service.invoke("OrderItemAddressShipMethodUpdate", params);               		
		} else {
			wc.service.invoke("OrderItemAddressShipInstructionsUpdate", params); 
		}                                             
	},
	
	
	/**
	 * This function is used to update the shipping mode of all order items in a single shipment checkout-out scenario.
	 * It is used when the "AjaxCheckout" feature is enabled.
	 *
	 * @param {DOM Element} addressSelectBox The select drop-down object that contains all available shipping modes.
	 */
	updateShipModeForAllItems:function(shipmentSelectBox){
		
		if(!this.isAjaxCheckOut())return;
		var shipModeId = shipmentSelectBox.value;
		if(shipModeId == -1){
			return;
		}
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		
		this.updateParamObject(params,"shipModeId",shipModeId,false);
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}             
		cursor_wait();			   
		wc.service.invoke("OrderItemAddressShipMethodUpdate", params);
	},
	
	
	/**
	 * This function updates the shipping instruction for items in the order. It is used in a single shipment check-out scenario.
	 * It is used when "AjaxCheckout" feature is enabled. It calls the <code>OrderShippingInfoUpdate</code> service.
	 */
	updateShippingInstructionsForAllItems:function(){
		if(!this.isAjaxCheckOut())return;
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		
		var orderItemId = null;
		var shipInstructions = document.getElementById("shipInstructions").value;
		
		reWhiteSpace = new RegExp(/^\s+$/);
		if(reWhiteSpace.test(shipInstructions)){
			shipInstructions = "";
		}
		
		//Validate the length of the shipping instructions
		if(!MessageHelper.isValidUTF8length(shipInstructions, 4000)){
			MessageHelper.formErrorHandleClient(document.getElementById("shipInstructions").id, MessageHelper.messages["ERROR_ShippingInstructions_TooLong"]); 
			return;						
		}		
		
		orderItemId = document.getElementById("orderItem_1").value;
		this.updateParamObject(params,"orderItemId",orderItemId,false);
		this.updateParamObject(params,"shipInstructions",shipInstructions,false);

		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}		
		cursor_wait();		
		wc.service.invoke("OrderShippingInfoUpdate", params);
	},
	
	
	/**
	 * This function validates the specified requested shipping date then calls {@link CheckoutHelperJS.updateShippingDateForAllItems} to update the date for all items in the current order in a single shipment scenario.
	 *
	 * @param {dijit.form.DateTextBox} jsDate The dijit.form.DateTextBox object containing the requested shipping date specified by the user. 
	 *
	 * @see CheckoutHelperJS.updateRequestedShipDateForThisItem
	 */

	updateRequestedShipDate:function(jsDate){
		if(jsDate == null || jsDate.getDisplayedValue() == null)
			return;
		
		var now = new Date();
				
		if(jsDate.compare(jsDate.getValue(), now) <= 0){
			// >0 --> jsDate is larger than now, i.e. a future date
			// <0 --> jsDate is smaller than now, i.e. a past date
			// ==0 --> both dates are exactly the same
			if(document.getElementById('requestedShippingDate') != null){
				MessageHelper.formErrorHandleClient(document.getElementById('requestedShippingDate').id, MessageHelper.messages["REQUESTED_SHIPPING_DATE_OUT_OF_RANGE_ERROR"]);
			}else{
				MessageHelper.displayErrorMessage(MessageHelper.messages["REQUESTED_SHIPPING_DATE_OUT_OF_RANGE_ERROR"]);
			}
			return;
		}
			
		if(!this.isAjaxCheckOut())
			return;
              
		var t = ""; 
		if(jsDate.getDisplayedValue() != ""){
			t = dojo.date.stamp.fromISOString(jsDate);
			//Set the time to 12pm to handle cases where daylight savings cause a date shift
			t.setHours(12);
			// set requested ship date in zulu time, from dojo: zulu - if true, UTC/GMT is used for a timezone
			t = dojo.date.stamp.toISOString(t, {selector: "%Y-%m-%dT%H:%m:%S.%SZ", zulu: true,milliseconds:true});
		}else if(jsDate.getDisplayedValue() == ""){
			t = this.resetRequestedShipDateValue;
		}
              
		//Close the calendar..
		jsDate._close();
		this.updateShippingDateForAllItems(t);
	},
	
	
	/**
	 * This function updates the requested shipping date for all items in the order. It is called by {@link CheckoutHelperJS.updateRequestedShipDate}.
	 * It calls the <code>OrderItemAddressShipMethodUpdate</code> service.
	 *
	 * @param {String} date The String representation of the date object, see {@link CheckoutHelperJS.updateRequestedShipDate}.
	 */
	updateShippingDateForAllItems:function(date){
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		
		this.updateParamObject(params,"requestedShipDate",date,false);

		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}		
		cursor_wait();
		wc.service.invoke("OrderItemAddressShipMethodUpdate", params);
	},
	
	
	/**
	 * Displays the details of an address in a single shipment check-out scenario.
	 *
	 * @param {DOM Element} addressSelectBox The address select drop-down object.
	 * @param {String} addressType The type of the selected address.
	 */
	displayAddressDetails:function(addressSelectBox,addressType){
		if(!this.isAjaxCheckOut()){
			//This is needed, so that previously displayed address details are hidden now..
			this.displayAddressDetailsWeb10(addressSelectBox,addressType);
		}
		else{
			//Display selected address details..
			if(addressSelectBox.value != -1){
				//For handling multiple clicks
				if(!submitRequest()){
					return;
				}     
				var checkForOpera = true; //require a check of whether the browser is opera or not
				cursor_wait(checkForOpera);							                   
				wc.render.updateContext('shippingAddressContext', {'shippingAddress':addressSelectBox.value});
			}
			else{
				this.createAddress(-1,addressType);
			}
		}
	},
	
	
	/**
	 * Displays the details of a selected address and hides the details all other addresses. If a user selects 'create address', then {@link CheckoutHelperJS.createAddress} will be called.
	 * This is used when the 'AjaxCheckout' feature is disabled.
	 * This function is called from {@link CheckoutHelperJS.displayAddressDetails}.
	 * 
	 * @param {DOM Element} addressSelectBox The address select drop-down object.
	 * @param {String} addressType The type of the selected address.
	 *
	 * @private
	 *
	 * @see CheckoutHelperJS.displayAddressDetails
	 */
	displayAddressDetailsWeb10:function(addressSelectBox,addressType){
		var selectedAddressId = addressSelectBox.value;
		for(j=0; j < addressSelectBox.options.length; j++){
			if(addressSelectBox.options[j].value == selectedAddressId){
				dojo.byId("addressDetails_"+addressSelectBox.options[j].value).style.display = "block";
			}
			else{
				dojo.byId("addressDetails_"+addressSelectBox.options[j].value).style.display = "none";
			}
		}
		//Now if its a create Address..
		if(selectedAddressId == -1){
			//We can use ajax service here also... pass -1, for single shipment..
			this.createAddress(-1,addressType);
		}
	},
	
	
	/**
	 * When the 'AjaxCheckout' feature is disabled, on page load, this function registers all item quantity fields and all shipping information related input fields on the single shipment Shipping & Billing page to the Dojo event listener. 
	 * If any of the fields has been changed by the user, the user will be asked to update the shopping cart before proceeding to the next page.
	 */
	initDojoEventListenerSingleShipmentPage:function(){                     
		var totalItems = document.getElementById("totalNumberOfItems").value;
		
		if(totalItems != null && totalItems > 0){
			if(dojo.byId("singleShipmentAddress") != null){
				dojo.connect(dojo.byId("singleShipmentAddress"), 'onchange', setDirtyFlag);
			}
			if(dojo.byId("WC_ShippingAddressSelectSingle_div_2") != null){
				dojo.connect(dojo.byId("WC_ShippingAddressSelectSingle_div_2"), 'onclick', setDirtyFlag);
			}
			if(dojo.byId("singleShipmentShippingMode") != null){
				dojo.connect(dojo.byId("singleShipmentShippingMode"), 'onchange', setDirtyFlag);
			}
			if(dojo.byId("shipAsComplete") != null){
				dojo.connect(dojo.byId("shipAsComplete"), 'onclick', setDirtyFlag);
			}
			if(dojo.byId("shippingInstructionsCheckbox") != null){
				dojo.connect(dojo.byId("shippingInstructionsCheckbox"), 'onclick', setDirtyFlag);
			}
			if(dojo.byId("requestShippingDateCheckbox") != null){
				dojo.connect(dojo.byId("requestShippingDateCheckbox"), 'onclick', setDirtyFlag);
			}
			if(dojo.byId("shipInstructions") != null){
				dojo.connect(dojo.byId("shipInstructions"), 'onchange', setDirtyFlag);
			}
			
			for(var i = 0; i < totalItems; i++){
				var object = dojo.byId("qty_" + (i+1));
				if(object != null){
					dojo.connect(object, 'onchange', setDirtyFlag);
				}
			}
		}else{
			console.debug("error: element 'totalNumberOfItems' was expected but undefined.");
			return;
		}
	},
	
	
	/**
	 * Updates the shopping cart on the single shipment 'Shipping & Billing' page.
	 * This function is used when the 'AjaxCheckout' feature is disabled.
	 *
	 * @param {DOM Element} form The form object that contains the shopping cart.
	 */
	updateSingleShipmentShoppingCart:function(form){
		var formAction = 'OrderChangeServiceShipInfoUpdate?';
		var updateShippingURL = 'OrderChangeServiceShipInfoUpdate?';
		
		var instructions = null;
		var t = null;
		
		
		// Get the specified shipping instructions if the flex flow option is enabled
		if(dojo.byId('shippingInstructionsCheckbox') != null){
			if(dojo.byId('shippingInstructionsCheckbox').checked){
				if(document.getElementById("shipInstructions") != null && document.getElementById("shipInstructions").value != null){
					//Validate the length of the shipping instructions
					if(MessageHelper.isValidUTF8length(document.getElementById("shipInstructions").value, 4000)){
						instructions = document.getElementById("shipInstructions").value;
					} else {
						MessageHelper.formErrorHandleClient(document.getElementById("shipInstructions").id,MessageHelper.messages["ERROR_ShippingInstructions_TooLong"]); 
						return;						
					}
				}
			}else{
				if(document.getElementById("shipInstructions") != null){
					instructions = "";
				}
			}
		}
		
		// Get the requested shipping date if the flex flow option is enabled
		if(dojo.byId('requestShippingDateCheckbox') != null){
			var jsDateObj = dijit.byId("requestedShippingDate");
			if(dojo.byId('requestShippingDateCheckbox').checked){
				if(jsDateObj != null && jsDateObj.getDisplayedValue() != null){
					var now = new Date();
					if(jsDateObj.compare(jsDateObj.getValue(), now) <= 0){
						// >0 --> jsDate is larger than now, i.e. a future date
						// <0 --> jsDate is smaller than now, i.e. a past date
						// ==0 --> both dates are exactly the same
						if(document.getElementById('requestedShippingDate') != null){
							MessageHelper.formErrorHandleClient(document.getElementById('requestedShippingDate').id, MessageHelper.messages["REQUESTED_SHIPPING_DATE_OUT_OF_RANGE_ERROR"]);
						}else{
							MessageHelper.displayErrorMessage(MessageHelper.messages["REQUESTED_SHIPPING_DATE_OUT_OF_RANGE_ERROR"]);
						}
						return;
					}
					var t = ""; 
					if(jsDateObj.getDisplayedValue() != ""){
						t = dojo.date.stamp.fromISOString(jsDateObj);
						//Set the time to 12pm to handle cases where daylight savings cause a date shift
						t.setHours(12);						
						// set requested ship date in zulu time, from dojo: zulu - if true, UTC/GMT is used for a timezone
						t = dojo.date.stamp.toISOString(t, {selector: "%Y-%m-%dT%H:%m:%S.%SZ", zulu: true,milliseconds:true});
					}else if(jsDateObj.getDisplayedValue() == ""){
						t = this.resetRequestedShipDateValue;
					}
				}
			}else{
				if(jsDateObj != null){
					t = this.resetRequestedShipDateValue;
				}
			}
		}
		
		//Update addressId for all items
		if(document.getElementById("singleShipmentAddress").value != -1){
			updateShippingURL = updateShippingURL + "addressId=" + document.getElementById("singleShipmentAddress").value;
		}
		else{
			MessageHelper.formErrorHandleClient(document.getElementById("singleShipmentAddress").id, MessageHelper.messages["SHIPPING_INVALID_ADDRESS"]);
			return;
		}
		
		//Update shipModeId for all items
		formAction = formAction + "shipModeId=" + document.getElementById("singleShipmentShippingMode").value;
		
		var shipInstructions = "";
		// if instructions == null, then the flex flow option is not enabled, do not pass the parameter to the service
		if(instructions != null){
			shipInstructions = "shipInstructions%3D" + instructions + "%26orderItemId_1%3D" + document.getElementById("orderItem_1").value;
		}
		
		// if t == null, then the flex flow option is not enabled, do not pass the parameter to the service
		if(t != null){
			formAction = formAction + "&requestedShipDate=" + t;
		}
		
		//ShipAsComplete
		var checkBox = document.getElementById("shipAsComplete");
		if(checkBox.checked){
			formAction = formAction + "&ShipAsComplete=Y";
		}
		else{
			formAction = formAction + "&ShipAsComplete=N";
		}
              
		//Need to update shipModeId, addressId, shipInstructions in 3 separate calls to the same service.
		//Update the shipModeId first; shipModeId will not be updated for all items if addressId and orderItemId are present .
		form.action = formAction;
		
		//Update the addressId; addressId will not be updated for all items if shipModeId and orderItemId are present.
		//Then update shipInstructions; requires at least 1 orderItemId to be passed 
		form.URL.value = updateShippingURL+"&requestedShipDate*=&shipModeId*=&orderItemId*=&URL=OrderChangeServiceShipInfoUpdate%3F"+shipInstructions +"%26URL%3DOrderProcessServiceOrderPrepare%3FURL%3DOrderShippingBillingView";              
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}
		form.submit();
	},
	
	/************************************************************
	 * End Single Shipment page specific functions
	 ************************************************************/
	
	
	/****************************************************************
	 * The following methods are used on the Multiple Shipment page
	 ****************************************************************/
	
	/**
	 * This function is used to move all order items into a single shipment when a shopper changes the order from multiple shipment check-out to single shipment.
	 * The shipping information of the first item in the order will be used for all items after this update.
	 * It calls the <code>OrderItemAddressShipMethodUpdate1</code> service to update the order.
	 */
	moveAllItemsToSingleShipment:function(){
		//Get the first orderItem id..
		var orderItemId = document.getElementById("orderItem_1").value;
		//Now get the addressId and shipModeId of this orderItemId...
		var addressId = document.getElementById("MS_ShipmentAddress_"+orderItemId).value;
		//Update the shipModeId and addressId of all the items present in currentOrder...
		
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		
		this.updateParamObject(params,"addressId",addressId,false);
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}               
		cursor_wait();
		wc.service.invoke("OrderItemAddressShipMethodUpdate1", params);
	},
	
	
	/**
	 * Helper function for editing an address on the multiple shipment 'Shipping & Billing' page.
	 * @param (String) addressbox The ID of the select drop-down object that contains the addresses.
	 * @param (Integer) orderItemId The ID of the order item.
	 */
	updateAddressIdForThisItemHelper:function(addressBox, orderItemId){
		var dropdown = document.getElementById(addressBox);
		dropdown.value=-1;
		this.updateAddressIdForThisItem(dropdown,orderItemId);
	},
	
	
	/**
	 * Updates the address ID for an order item in a multipls shipment check-out scenario. It is used when the "AjaxCheckout" feature is enabled.
	 * It calls the <code>OrderItemAddressShipMethodUpdate</code> service to update.
	 * 
	 * @param {DOM Element} addressBox The select drop-down object that contains all available addresses.
	 * @param {Integer} orderItemId The order item ID.
	 */
	updateAddressIdForThisItem:function(addressBox,orderItemId){
		//Save it in local array..
		if(addressBox.value != -1){
			this.selectedAddressesArray[addressBox.name] =  addressBox.value;
		}
		if(addressBox.value == -1) return;
		if(!this.isAjaxCheckOut())return;
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		var addressId = addressBox.value;
		this.updateParamObject(params,"orderItemId",orderItemId,false,-1);
		this.updateParamObject(params,"addressId",addressId,false,-1);
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}            
		cursor_wait();			    
		wc.service.invoke("OrderItemAddressShipMethodUpdate", params);
	},
	
	
	/**
	 * Updates the shipping mode for an item in the order. It is used in a multiple shipment scenario and when the "AjaxCheckout" feature is enabled.
	 * It calls the <code>OrderItemAddressShipMethodUpdate</code> service.
	 *
	 * @param {DOM Element} shipModeBox The select drop-down object that contains all available shipping modes.
	 * @param {Integer} orderItemId The ID of the order item to update.
	 */
	updateShipModeForThisItem:function(shipModeBox,orderItemId){
		var shipModeId = shipModeBox.value;
		if(shipModeId == -1){
			return;
		}
		if(!this.isAjaxCheckOut())return;
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		this.updateParamObject(params,"orderItemId",orderItemId,false,-1);
		this.updateParamObject(params,"shipModeId",shipModeId,false,-1);
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}               
		cursor_wait();
		wc.service.invoke("OrderItemAddressShipMethodUpdate", params);
	},
	
	
	/**
	 * Updates the shipping instruction for an item. It is used in a multiple shipment scenario and when the "AjaxCheckout" feature is enabled.
	 * It calls the <code>OrderShippingInfoUpdate</code> service.
	 *
	 * @param {DOM Element} textArea The input text area for shipping instruction.
	 * @param {Integer} orderItemId The ID of the order item to update.
	 */
	updateShippingInstructionsForThisItem:function(textArea,orderItemId){
		if(!this.isAjaxCheckOut())return;
		
		var addressId = document.getElementById("MS_ShipmentAddress_"+orderItemId).value;
		var shipModeId = document.getElementById("MS_ShippingMode_"+orderItemId).value;
		var shipInstructions = textArea.value;
		
		reWhiteSpace = new RegExp(/^\s+$/);
		if(reWhiteSpace.test(shipInstructions)){
			shipInstructions = "";
		}
		
		//Validate the length of the shipping instructions
		if(!MessageHelper.isValidUTF8length(shipInstructions, 4000)){
			MessageHelper.formErrorHandleClient(textArea.id, MessageHelper.messages["ERROR_ShippingInstructions_TooLong"]); 
			return;						
		}			
		
		this.setShippingInstuctionsForAllOtherItems(addressId,shipModeId,shipInstructions);
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		
		this.updateParamObject(params,"addressId",addressId,false,-1);
		this.updateParamObject(params,"shipModeId",shipModeId,false,-1);
		this.updateParamObject(params,"shipInstructions",shipInstructions,false,-1);
		this.updateParamObject(params,"orderItemId",orderItemId,false,-1);

		//For handling multiple clicks
		if(!submitRequest()){
			return;
		} 		
		cursor_wait();		
		wc.service.invoke("OrderShippingInfoUpdate", params);
	},
	
	
	/**
	 * This function updates the requested shipping date for the current item in a multiple shipment check-out scenario and when the 'AjaxCheckout' feature is enabled.
	 * It invokes the <code>OrderItemAddressShipMethodUpdate</code> service.
	 *
	 * @param {dijit.form.DateTextBox} jsDate The dijit.form.DateTextBox object containing the requested shipping date specified by the user. 
	 * @param {Integer} orderItemId The ID of the order item to update.
	 */
	updateRequestedShipDateForThisItem:function(jsDate,orderItemId){
		if(jsDate == null || jsDate.getDisplayedValue() == null)
			return;
		
		var now = new Date();
				
		if(jsDate.compare(jsDate.getValue(), now) <= 0){
			// >0 --> jsDate is larger than now, i.e. a future date
			// <0 --> jsDate is smaller than now, i.e. a past date
			// ==0 --> both dates are exactly the same
			if(document.getElementById('MS_requestedShippingDate_' + orderItemId) != null){
				MessageHelper.formErrorHandleClient(document.getElementById('MS_requestedShippingDate_' + orderItemId).id, MessageHelper.messages["REQUESTED_SHIPPING_DATE_OUT_OF_RANGE_ERROR"]);
			}else{
				MessageHelper.displayErrorMessage(MessageHelper.messages["REQUESTED_SHIPPING_DATE_OUT_OF_RANGE_ERROR"]);
			}
			return;
		}
			
		if(!this.isAjaxCheckOut())
			return;
              
		var t = ""; 
		if(jsDate.getDisplayedValue() != ""){
			t = dojo.date.stamp.fromISOString(jsDate);
			//Set the time to 12pm to handle cases where daylight savings cause a date shift
			t.setHours(12);
			// set requested ship date in zulu time, from dojo: zulu - if true, UTC/GMT is used for a timezone
			t = dojo.date.stamp.toISOString(t, {selector: "%Y-%m-%dT%H:%m:%S.%SZ", zulu: true,milliseconds:true});
		}else if(jsDate.getDisplayedValue() == ""){
			t = this.resetRequestedShipDateValue;
		}
		
		//Close the calendar..
		jsDate._close();
		
		var addressId = document.getElementById("MS_ShipmentAddress_"+orderItemId).value;
		var shipModeId = document.getElementById("MS_ShippingMode_"+orderItemId).value;
		
		params = [];
		params["storeId"] = this.storeId;
		params["catalogId"] = this.catalogId;
		params["langId"] = this.langId;
		params.orderId = ".";
		this.updateParamObject(params,"orderItemId",orderItemId,false,-1);
		this.updateParamObject(params,"requestedShipDate",t,false,-1);

		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}   		
		cursor_wait();		
		CheckoutHelperJS.RequestShippingDateAction = true;
		wc.service.invoke("OrderItemAddressShipMethodUpdate", params);
	},
	
	
	/**
	 * This function is used to bring up the address entry form when a user wants to create a new address for an item in a multiple shipment scenario.
	 *
	 * @param {Integer} orderItemId The ID of the order item to update.
	 * @param {String} addressType The type of address to create.
	 *
	 * @private
	 */
	createAddressForMS:function(orderItemId,addressType){
		this.saveOrderItemsList(orderItemId,"-1");
		
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}               
		var checkForOpera = true; //require a check of whether the browser is opera or not
		cursor_wait(checkForOpera);
		wc.render.updateContext('editShippingAddressContext', {'shippingAddress':'-1','addressType':addressType});
		//Hide the mainContents (contains shipping/billing details, shop cart details, promotion details, orderDetails)
		this.showHideDivs('editAddressContents','mainContents');
	},
	
	
	/** 
	 * Helper function for adding a new address in a multiple shipment scenario.
	 *
	 * @param (String) addressSelectBox The ID of the select drop-down object that contains addresses.
	 * @param (Integer) orderItemId The ID of the item.
	 * @param (String) addressType The type of the selected address.
	 */
	displayAddressDetailsForMSHelper:function (addressSelectBox,orderItemId,addressType) {
		var dropdown = document.getElementById(addressSelectBox);
		dropdown.value=-1;
		this.displayAddressDetailsForMS(dropdown, orderItemId, addressType);
	},
	
	
	/**
	 * Displays the details of an address in a multiple shipment check-out scenario.
	 *
	 * @param {DOM Element} addressSelectBox The address select drop-down object.
	 * @param {Integer} orderItemId The order item ID.
	 * @param {String} addressType The type of the selected address.
	 */
	displayAddressDetailsForMS:function(addressSelectBox,orderItemId,addressType){
		if(this.isAjaxCheckOut()){
			if(addressSelectBox.value == -1){
				this.createAddressForMS(orderItemId,addressType);
			}
		}
		else{
			//For web1.0 also use the same function...
			if(addressSelectBox.value == -1){
				this.createAddressForMS(orderItemId,addressType);
			}
			else{
				//Display the address details in short...
				var selectedAddressId = addressSelectBox.value;
				dojo.byId("MS_shippingAddressDisplayArea_"+orderItemId).innerHTML = dojo.byId("addressDetails_"+selectedAddressId).innerHTML;
			}
		}
	},
	
	
	/**
	 * When the 'AjaxCheckout' feature is disabled, on page load, this function registers all item quantity fields and all shipping information related input fields on the multiple shipment Shipping & Billing page to the Dojo event listener. 
	 * If any of the fields has been changed by the user, the user will be asked to update the shopping cart before proceeding to the next page.
	 */
	initDojoEventListenerMultiShipmentPage:function(){                     
		var totalItems = document.getElementById("totalNumberOfItems").value;
		
		if(totalItems != null && totalItems > 0){
			var list_clickable = new dojox.collections.ArrayList([]);
			var list_editable = new dojox.collections.ArrayList([]);
			
			for(var i = 0; i < totalItems; i++){
				//Get the orderItemId
				var orderItemId = document.getElementById("orderItem_"+(i+1)).value;
				var object = "";
				
				if(orderItemId != null){
					// retrieve clickable objects, i.e. checboxes and buttons
					object = dojo.byId("MS_shippingInstructionsCheckbox_" + orderItemId);
					if(object != null){list_clickable.add(object);}
					object = dojo.byId("MS_requestShippingDateCheckbox_" + orderItemId);
					if(object != null){list_clickable.add(object);}
					object = dojo.byId("shipAsComplete");
					if(object != null){list_clickable.add(object);}
					object = dojo.byId("editAddressButton");
					if(object != null){list_clickable.add(object);}
					
					// retrieve selectable objects, i.e. drop-down menus, input fields
					object = dojo.byId("MS_ShipmentAddress_" + orderItemId);
					if(object != null){list_editable.add(object);}
					object = dojo.byId("MS_ShippingMode_" + orderItemId);
					if(object != null){list_editable.add(object);}
					object = dojo.byId("MS_shipInstructions_" + orderItemId);
					if(object != null){list_editable.add(object);}
					object = dojo.byId("qty_" + (i+1));
					if(object != null){list_editable.add(object);}
				}else{
					var j = i+1;
					console.debug("error: element 'orderItem_'" + j + " was expected but undefined.");
				}
			}
			for(var i=0; i<list_clickable.count; i++){
				var item = list_clickable.item(i);
				dojo.connect(item, 'onclick', setDirtyFlag);
			}
			
			for(var i=0; i<list_editable.count; i++){
				var item = list_editable.item(i);
				dojo.connect(item, 'onchange', setDirtyFlag);
			}
		}else{
			console.debug("error: element 'totalNumberOfItems' was expected but undefined.");
			return;
		}
	},
	
	
	/**
	 * Updates the shopping cart on the multiple shipment 'Shipping & Billing' page.
	 * This function is used when the 'AjaxCheckout' feature is disabled.
	 *
	 * @param {DOM Element} form The form object that contains the shopping cart.
	 */
	updateMultiShipmentShoppingCart:function(form){
		var updateShippingAction = 'OrderChangeServiceShipInfoUpdate';
		var updateShippingURL = 'OrderShippingBillingView?';
		
		var totalItems = document.getElementById("totalNumberOfItems").value;
		
		for(var i = 0; i < totalItems; i++){             
			//Get the orderItemId
			var orderItemId = document.getElementById("orderItem_"+(i+1)).value;
			if(document.getElementById("orderItemId_"+(i+1)) != null){
				document.getElementById("orderItemId_"+(i+1)).value = orderItemId;
			}
			
			//Update addressId
			var addressId = document.getElementById("MS_ShipmentAddress_" + orderItemId).value;
			if(addressId != -1){
				if(document.getElementById("addressId_" + (i+1)) != null) {
					document.getElementById("addressId_" + (i+1)).value = addressId;
				}
			}else{
				MessageHelper.formErrorHandleClient(document.getElementById("MS_ShipmentAddress_" + orderItemId).id, MessageHelper.messages["SHIPPING_INVALID_ADDRESS"]);
				return;
			}
			
			//Update shipModeId
			if(document.getElementById("shipModeId_" + (i+1)) != null) {
				document.getElementById("shipModeId_" + (i+1)).value = document.getElementById("MS_ShippingMode_"+orderItemId).value;
			}
			
			var instructions = null;
			var t = null;
			
			// Get the shipping instructions if the flex flow option is enabled
			var shippingInstructionsCheckbox = dojo.byId("MS_shippingInstructionsCheckbox_" + orderItemId);
			if(shippingInstructionsCheckbox != null){
				if(shippingInstructionsCheckbox.checked){
					if(document.getElementById("MS_shipInstructions_" + orderItemId) != null && document.getElementById("MS_shipInstructions_" + orderItemId).value != null){
						//Validate the length of the shipping instructions
						if(MessageHelper.isValidUTF8length(document.getElementById("MS_shipInstructions_" + orderItemId).value, 4000)){
							instructions = document.getElementById("MS_shipInstructions_" + orderItemId).value;
						} else {
							MessageHelper.formErrorHandleClient(document.getElementById("MS_shipInstructions_" + orderItemId).id,MessageHelper.messages["ERROR_ShippingInstructions_TooLong"]); 
							return;						
						}						
					}
				}else{
					if(document.getElementById("MS_shipInstructions_" + orderItemId) != null){
						instructions = "";
					}
				}
			}
			
			// Get the requested shipping date if the flex flow option is enabled
			var requestShippingDateCheckbox = dojo.byId("MS_requestShippingDateCheckbox_" + orderItemId);
			if(requestShippingDateCheckbox != null){
				t = this.resetRequestedShipDateValue;
				var jsDateObj = dijit.byId("MS_requestedShippingDate_" + orderItemId);
				if(requestShippingDateCheckbox.checked){
					if(jsDateObj != null && jsDateObj.getDisplayedValue() != null){
						var now = new Date();
						if(jsDateObj.compare(jsDateObj.getValue(), now) <= 0){
							// >0 --> jsDate is larger than now, i.e. a future date
							// <0 --> jsDate is smaller than now, i.e. a past date
							// ==0 --> both dates are exactly the same
							if(document.getElementById('MS_requestedShippingDate_' + orderItemId) != null){
								MessageHelper.formErrorHandleClient(document.getElementById('MS_requestedShippingDate_' + orderItemId).id, MessageHelper.messages["REQUESTED_SHIPPING_DATE_OUT_OF_RANGE_ERROR"]);
							}else{
								MessageHelper.displayErrorMessage(MessageHelper.messages["REQUESTED_SHIPPING_DATE_OUT_OF_RANGE_ERROR"]);
							}
							return;
						}
						var t = ""; 
						if(jsDateObj.getDisplayedValue() != ""){
							t = dojo.date.stamp.fromISOString(jsDateObj);
							//Set the time to 12pm to handle cases where daylight savings cause a date shift
							t.setHours(12);							
							// set requested ship date in zulu time, from dojo: zulu - if true, UTC/GMT is used for a timezone
							t = dojo.date.stamp.toISOString(t, {selector: "%Y-%m-%dT%H:%m:%S.%SZ", zulu: true,milliseconds:true});
						}else if(jsDateObj.getDisplayedValue() == ""){
							t = this.resetRequestedShipDateValue;
						}
					}
				}else{
					if(jsDateObj != null){
						t = this.resetRequestedShipDateValue;
					}
				}
			}
			// if instructions == null, then the shipping instruction flex flow option is not enabled, do not pass the parameter to the service
			if(instructions != null){
				if(document.getElementById("qty_"+(i+1)) != null && document.getElementById("qty_"+(i+1)).value != -1){
					if(document.getElementById("shipInstructions_"+(i+1)) != null){
						document.getElementById("shipInstructions_"+(i+1)).value = instructions;
					} 
				}
			}
			
			// if t == null, then the request shipping date flex flow option is not enabled, do not pass the parameter to the service
			if(t != null){
				if(document.getElementById("qty_"+(i+1)) != null && document.getElementById("qty_"+(i+1)).value != -1){
					if(document.getElementById("requestedShipDate_"+(i+1)) != null){
						document.getElementById("requestedShipDate_"+(i+1)).value = t;
					}
				}
			}
		}
		
		//ShipAsComplete 
		var checkBox = document.getElementById("shipAsComplete");
		if(document.getElementById("ShipAsComplete") != null) {
			if(checkBox.checked){
				document.getElementById("ShipAsComplete").value = "Y";
			}
			else{
				document.getElementById("ShipAsComplete").value = "N";
			}
		}
		
		// remove orderItemId array returned from response properties - it is an array and do not have _i information so next service call will lose track of orderItemIds
		updateShippingURL = updateShippingURL + "orderItemId*=";
		updateShippingURL = updateShippingURL + "&quantity*="; 
		updateShippingURL = updateShippingURL + "&addressId*=";
		updateShippingURL = updateShippingURL + "&shipModeId*=";
		updateShippingURL = updateShippingURL + "&shipInstructions*=";
		updateShippingURL = updateShippingURL + "&requestedShipDate*=";
		updateShippingURL = updateShippingURL + "&ShipAsComplete*=";
		
		updateShippingURL = updateShippingURL + "&orderItem*=";
		updateShippingURL = updateShippingURL + "&MS_ShipmentAddress*=";
		updateShippingURL = updateShippingURL + "&MS_ShippingMode*=";
		updateShippingURL = updateShippingURL + "&MS_shippingInstructionsCheckbox*=";  
		updateShippingURL = updateShippingURL + "&MS_shipInstructions*=";
		updateShippingURL = updateShippingURL + "&MS_requestShippingDateCheckbox*=";
		updateShippingURL = updateShippingURL + "&MS_requestedShippingDate*=";
		updateShippingURL = updateShippingURL + "&qty*=";
		updateShippingURL = updateShippingURL + "&shipAsComplete*=";                              
		
		form.action = updateShippingAction;
		form.URL.value = updateShippingURL;                                     
		//For handling multiple clicks
		if(!submitRequest()){
			return;
		}
		
		form.submit();
	}
	
	/************************************************************
	 * End Multiple Shipment page specific functions
	 ************************************************************/

}
