//********************************************************************
//*-------------------------------------------------------------------
//* Licensed Materials - Property of IBM
//*
//* WebSphere Commerce
//*
//* (c) Copyright IBM Corp. 2007
//*
//* US Government Users Restricted Rights - Use, duplication or
//* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//*
//*-------------------------------------------------------------------
		
	/************************************************************
	 *	WORK PENDING											*
	 *	1. JavaDoc for Compare Function							*
	 *	2. Dependency of HTML forms and element					*
	 *	3. Moving Global variable and Functions to Global.js	*
	 *	4. Fixing few defect in Compare Functions				*
	 *		i.e:Should not accept same item in compareZone		*
	 *			Should allow to frag items from compareZone		* 
	 ************************************************************/

	dojo.registerModulePath("wc", "wc");

	dojo.require("dojo.html.*");
	dojo.require("dojo.lang.*");
	dojo.require("dojo.event.*");
	dojo.require("dojo.widget.*");
	dojo.require("dojo.xml.Parse");
	dojo.require("dojo.json");
	dojo.require("dojo.widget.ContentPane");
	dojo.require("dojo.widget.ComboBox");
	
	dojo.require("wc.widget.RefreshArea");
	dojo.require("wc.render.RefreshController");
	dojo.require("wc.render.Context");

	dojo.require("wc.widget.WCAccordionContainer");
	dojo.require("wc.widget.WCHtmlDropTarget");
	dojo.require("wc.widget.TitlePaneTemplate");
	dojo.require("wc.widget.ContentPaneTemplate");
	dojo.require("wc.widget.ScrollablePane");
	dojo.require("wc.widget.ProductQuickView");
	dojo.require("wc.widget.ToolTipContent");

	dojo.require("dojo.dom");
	dojo.require("dojo.io.*");
	dojo.require("dojo.lfx.*");
	dojo.require("dojo.storage.*");
	
	/******************************************************************************************************************
	 *                                        GLOBAL VARIABLES & FUNCTIONS                                            *
	 *                                                    START                                                       *
	 ******************************************************************************************************************/

	function wishListUpdated(){
		// summary		: This function is called by 'WISH_LIST_UPDATED' event.
		// description	: This function is called by 'WISH_LIST_UPDATED' event. Only the wishlist is updated
		//				  Item is added or removed from WishList. it does not affect the QuickCart.
		// assumptions	: None.
		// dojo API		: None.
	}

	
	function orderUpdated(){
		// summary		: This function is called by 'ORDER_UPDATED' event.
		// description	: This function is called by 'ORDER_UPDATED' event. Only the order is updated
		//				  Item is added or removed from QuickCart. It does not affect the WishList.
		// assumptions	: None.
		// dojo API		: None.
	}

	function userChanged(){
		// summary		: This function is called by 'USER_CHANGED' event.
		// description	: This function is called by 'USER_CHANGED' event. Both Order and Wishlist is updated
		//				  User has logged off or logged in. This will update both Order and Wishlist for user
		// assumptions	: None.
		// dojo API		: None.
	}


	function queryToParamObject(queryString, object, toArray){
		// summary		: This function converts given Query String into JavaScript Object.
		// description	: This function converts given Query String into JavaScript Object.
		//				  It extracts the parameters and their respective values from given Query String
		//				  and then put them as a Key-Value pair in a JavaScript Object.
		//				  This function can be used when we have to pass JavaScript Object ( params ),
		//				  as a parameter for WebService. For example
		//						var params = [];
		//						var queryString = dojo.io.encodeForm(dojo.byId("FormId"));
		//						params = queryToParamObject(queryString, params)
		//						wc.service.invoke("AddToCart", params);
		// queryString	: String
		//				  Its an Query String. i.e. param1='value1'&param2='value2'&param3=3.
		// object		: JavaScript Object
		//				  It could be a JavaScript Object or JavaScript Array. JavaScript treats Array as Object only.
		// toArray		: Boolean
		//				  If true, creates an Array for duplicate entries
		//				  If false, does not creat an Array for duplicate entries. It overwrites the old value.
		// assumptions	: None.
		// dojo API		: None.
		// returns		: A JavaScript Object having Query string parameters as Key-Value pair.

		if(object == null)
			var object = [];

		var queryStringArray = queryString.split('&');
		for(var i = 0; i < queryStringArray.length; i++) {
			var tempString = queryStringArray[i];
			var tempArray = tempString.split('=');
			if(tempArray != null && tempArray.length > 1){
				var key = tempArray[0];
				var value = tempArray[1];
				object = updateParamObject(object, key, value, toArray);
			}
		}
		return object;
	}

	// summary		: This function updates the given params object with Key value pair.
	// description	: This function updates the given params object with Key value pair.
	//				  If the toArray value is true, It creates an Array for duplicate entries.
	//				  else, It overwrites the old value.
	//				  It is useful while making a service call which excepts few paramters of type array
	// params		: JavaScript Object
	//				  It could be a JavaScript Object or JavaScript Array. JavaScript treats Array as Object only.
	// key			: String
	// value		: String
	// toArray		: Boolean
	//				  If true, creates an Array for duplicate entries
	//				  If false, does not creat an Array for duplicate entries. It overwrites the old value.
	// assumptions	: None.
	// dojo API		: None.
	// returns		: A JavaScript Object having key - value pair.
	function updateParamObject(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;
	}
	
	/******************************************************************************************************************
	 *                                        GLOBAL VARIABLES & FUNCTIONS                                            *
	 *                                                    END                                                         *
	 ******************************************************************************************************************/
			



	/******************************************************************************************************************
	 *                                        STORE ACORDION FUNCTIONS                                                *
	 *                                                    START                                                       *
	 *                                                                                                                *
	 *                  storeAccordionJS have all the code necessary for storeAccordion to work                       *
	 *                   As the functions are used only by storeAccordion, We've put them under                       *
	 *                                         storeAccordionJS namespace.                                            *
	 ******************************************************************************************************************/

	storeAccordionJS={
		quickCartDrop : null,
		wishListDrop : null,
		compareDrop : null,
		compareCounter:0,
		compareRowCounter:0,
		compareItemCatEntry:new Object(),
		isComparePane:false,
		allSelectedFromCart:false,
		showStoreAccordionWaitTime:100,
		updateWaitTimeOut:1500,

		//ShopCart Shipping Info Parameters
		defaultShippingInfoParamObject:null,
		isDefaultShippingProvided:false,
		shipmentBlockObject:null,
		isShipmentBlockProvided:false,

		quickCartForm:[],
		wishListForm:[],

		isUpdateCartCalled:false,
		isShipmentPage:false,
		flexFlowOptions:new Object(),

		langId: "-1",
		storeId: "",
		catalogId: "",
		properties: new Object(),
		errorMessages: new Object(),
		
		
		setErrorMessage : function(key, value){
			this.errorMessages[key] = value;
		},
		
		getErrorMessage : function(key){
			var value = this.errorMessages[key];
			if(value == null)
				value = "Could not get the message value for specified key " + key;
			
			return value;
		},
		setProperty:function(name,value){
			// summary			: This function sets property value for given name in storeAccordionJS
			// description	: This function sets property value for given name in storeAccordionJS. 
			//								This property can be used in other functions.
			// name					: Name of the property
			// value 				: value of the property
			this.properties[name]=value;
			//alert("setProperty " + name + " : " + this.properties[name]);
		},
		
		getProperty:function(name){
			// summary			: This function returns property value.
			// description	: This function returns property value for given property name.
			// name					: Name of the property
			// return 			: value of the property
			return this.properties[name];
		},
		
		removeProperty:function(name){
			// summary			: This function removes property.
			// description	: This function removes property value for given property name.
			// name					: Name of the property
			delete this.properties[name];
		},
		
		setCommonParameters:function(langId,storeId,catalogId){
			// summary		: This function initializes common parameters used in all service calls
			// description	: This function initializes storeId, catalogId, and langId.
			// langId	: The language id to use.
			// storeId : The store id to use.
			// catalog : The catalog id to use.
			this.langId = langId;
			this.storeId = storeId;
			this.catalogId = catalogId;
		},
  
		onLoad:function(){
			// summary		: This function initializes Order, Wishlist and User events
			// description	: This function registers 'ORDER_UPDATED', 'WISH_LIST_UPDATED' and 'USER_CHANGED'
			//				  events. These events are used to notify change in order, wishlist and user
			//				  to interested parties, so that they can update their state accordingly. It also
			//				  loads the StoreAccordion.
			// assumptions	: None.
			// dojo API		: dojo.event.topic.registerPublisher() and dojo.event.topic.subscribe().
			
			/* 
			DELETE IT 
			// Makes sure all the interested party will be notified about order changes
			//dojo.event.topic.subscribe("/ORDER_UPDATED", this, "updateQuickCart");
			
			// Makes sure all the interested party will be notified about wishlist changes
			//dojo.event.topic.subscribe("/WISH_LIST_UPDATED", this, "updateWishList");
			
			// Makes sure all the interested party will be notified about wishlist changes
			//dojo.event.topic.subscribe("/USER_CHANGED", this, "updateCheckOutInfo");
			//dojo.event.topic.subscribe("/USER_CHANGED", this, "updateWishList");
			//dojo.event.topic.subscribe("/USER_CHANGED", this, "updateHeader");
			//dojo.event.topic.subscribe("/USER_CHANGED", this, "updateQuickCart");
			*/

			this.initStoreAccordionContainer();
			this.quickCartPostRefreshHandler();
			this.wishListPostRefreshHandler();
			
			this.initShippingInfo();
		},

		showStoreAccordion:function(waitTime) {
			// summary		: This function shows the StoreAccordion after waiting for 'waitTime' miliseconds.
			// description	: This function shows (make visible) the StoreAccordion after waiting for 'waitTime' miliseconds.
			//				  It waits for 'waitTime' miliseconds and then checks where browser is busy or not. 
			//				  And if browser has finished processing it will show the StoreAccordion. 
			//				  If Browser is still busy, it will wait for another 'waitTime' miliseconds.
			// waitTime		: Number
			//				  Number of miliseconds.
			// assumptions	: 'busyCount' variable is defined Globally. It should be available in this function.
			// dojo API		: dojo.lang.setTimeout() and dojo.html.show().

			if(busyCount > 0){
				dojo.lang.setTimeout(this,"showStoreAccordion",waitTime);	
			}else{
				var storeAccordian_div1 = document.getElementById("storeaccordion_div");
				var espot_div1 = document.getElementById("espot_div");
				
				storeAccordian_div1.style.visibility = "visible";
				espot_div1.style.visibility = "visible";
				dojo.html.show(storeAccordian_div1);
			}
		},

		initStoreAccordionContainer:function() {
			// summary		: This function initializes StoreAccordion.
			// description	: This function initializes StoreAccordion. It parses the dojo widgets for StoreAccordion
			// assumptions	: 'busyCount' variable is defined Globally. It should be available in this function.
			// dojo API		: dojo.xml.Parse() and dojo.widget.getParser().

			
			// ISSUE
			// Because of dojo widget's limitation we cannot put the content of 'Quick Cart' and 'Wish list' 
			// directly under  StoreAccordion. If we do so, the "ProductQuickView" widget under 'Quick Cart'
			// and 'Wish list' will not work. 
			
			// WORKAROUND
			// So initially we are puuting these content in temp div. This function copies the contents from 
			// temp div and put them back in StoreAccordion. and then it parses the dojo widgets in those contents.

			//busyCount ++;

			//this.showStoreAccordion(this.showStoreAccordionWaitTime);
			//busyCount --;


			//Connect the updateCartWait function with updateCart, so that whenever updateCartWait function
			//get called updateCart function will be called after updateWaitTimeOut miliseconds.
			dojo.event.kwConnect({
				srcObj:     this, 
				srcFunc:    "updateCartWait", 
				targetObj:  this, 
				targetFunc: "updateCart",
				delay:      this.updateWaitTimeOut,
				once:		true
			});
		},

		initShippingInfo:function() {
			// summary			: This function initializes the default shipping information.
			// description	: This is done so that all add to carts will be with shipping information so that we do not
			//								start creating unneccessary shipments.
			// assumptions	: 'globalShipModeId' and 'globalAddressId'variable is defined Globally. It should be available in this function.
			// dojo API			: none
			
			if (globalShipModeId != "" || globalAddressId != "") {
				var params = [];
				params.addressId = globalAddressId;
				params.shipModeId = globalShipModeId;
				this.updateShippingInfoParams(params);
			}
		},

		toggleCheckboxes:function(formName, checkAllNodeId){
			// summary		: This function checks/Unchecks all the items in given form
			// description	: This function checks/Unchecks all the items in given form
			// formName		: Name of the Form which all items will be checked/unchecked
			// checkAllNodeId: Id of the 'Check All' checkbox.
			// assumptions	: None.
			// dojo API		: dojo.html.getElementsByClass(), dojo.lang.isArrayLike() and dojo.lang.forEach().
			checkAllNode = dojo.byId(checkAllNodeId);
			checkItems = dojo.html.getElementsByClass(formName + '_checkboxItems');
			
			if(checkAllNode.checked){
				if(dojo.lang.isArrayLike(checkItems)){
					dojo.lang.forEach(checkItems, function(node){
						node.checked = true;
					});
				}else{
					checkItems.checked = true;
				}
			}else{
				if(dojo.lang.isArrayLike(checkItems)){
					var counter = 0;
					dojo.lang.forEach(checkItems, function(node){
						node.checked = false;
					});
				}else{
					checkItems.checked = false;
				}
			}
		},

		updateShippingInfoParams:function(shippingInfoParamObject){
			if(this.defaultShippingInfoParamObject == null)
				this.defaultShippingInfoParamObject = new Object();

			for(shippingInfoParamName in shippingInfoParamObject){
				this.defaultShippingInfoParamObject[shippingInfoParamName] = shippingInfoParamObject[shippingInfoParamName];
				//alert("StoreAccordionJS.updateShippingInfoParams : " + shippingInfoParamName + ":" + this.defaultShippingInfoParamObject[shippingInfoParamName]);
				this.isDefaultShippingProvided = true;
			}
		},

		resetShippingInfoParams:function(){
			this.defaultShippingInfoParamObject = null;
			this.isDefaultShippingProvided = false;
		},
		

		updateShipmentBlockObject:function(shipmentBlockObject){
			this.shipmentBlockObject = shipmentBlockObject;
			this.isShipmentBlockProvided = true;
		},

		resetShipmentBlockObject:function(){
			this.shipmentBlockObject = null;
			this.isShipmentBlockProvided = false;
		},

		addItemWithShipingInfo:function(params){

			for(shippingInfoParamName in this.defaultShippingInfoParamObject){
				params[shippingInfoParamName] = this.defaultShippingInfoParamObject[shippingInfoParamName];
			}
			
			var service = wc.service.declare({
				id: "AjaxAddOrderItemOnlyService",
				actionId: "AjaxAddOrderItemOnlyService",
				url: "AjaxOrderChangeServiceItemAdd",
				
				successHandler: function(serviceResponse) {
					params["orderItemId"] = serviceResponse.orderItemId;
					wc.service.invoke("AjaxAddOrderItemWithShipingInfo", params);
				},
				failureHandler: function(serviceResponse) {
					if(serviceResponse !=null && serviceResponse.errorMessage!=null) {
						alertDialog(serviceResponse.errorMessage,this.storeId,this.catalogId,this.langId);
					} else if (serviceResponse !=null && serviceResponse.errorMessageKey!=null) {
						alertDialog(serviceResponse.errorMessageKey,this.storeId,this.catalogId,this.langId);
					} else {
						alert("Error");
					}
				}
			});

			var updateShipInfoService = wc.service.declare({
				id: "AjaxAddOrderItemWithShipingInfo",
				actionId: "AjaxAddOrderItemWithShipingInfo",
				url: "AjaxOrderChangeServiceShipInfoUpdate",
				
				successHandler: function(serviceResponse) {
				},
				failureHandler: function(serviceResponse) {
					if(serviceResponse !=null && serviceResponse.errorMessage!=null) {
						alertDialog(serviceResponse.errorMessage,this.storeId,this.catalogId,this.langId);
					} else if (serviceResponse !=null && serviceResponse.errorMessageKey!=null) {
						alertDialog(serviceResponse.errorMessageKey,this.storeId,this.catalogId,this.langId);
					} else {
						alert("Error");
					}
				}
			});

			dojo.event.kwConnect({
				srcObj:     updateShipInfoService, 
				srcFunc:    "successHandler", 
				targetObj:  this, 
				targetFunc: "updateItemDefaultShipingInfo",
				once:		true
			});

			wc.service.invoke("AjaxAddOrderItemOnlyService", params);
			cursor_wait();
		},

		updateItemDefaultShipingInfo:function(params){
			//alert("updateItemShipingInfo");
			//for(i in params)
				//alert(i + ":" + params[i]);

						
			for(paramName in this.defaultShippingInfoParamObject){
				for(items in params['orderItemId']){
					params = updateParamObject(params, paramName, this.defaultShippingInfoParamObject[paramName], false, -1);
					//alert(paramName + ":" + params[paramName]);
				}
			}
			for(items in params['orderItemId']){
				params = updateParamObject(params, 'orderItemId', params['orderItemId'][items], false, -1);
			}
			
			 
			for(;params['orderItemId'].length>0;){
				params['orderItemId'].pop();
			}

			this.alertParams(params);
			wc.service.invoke("OrderItemShipmentBlockUpdate", params);
			cursor_wait();
		},

		quickCartDropEventHandler:function(event){
			// summary		: This function adds item to Order when user drops an item in 'Quick Cart'
			// description	: This function adds item to Order when user drops an item in 'Quick Cart'
			//				  It calls add2ShopCartAjaxForDroppedItems function which actually adds
			//				  droppped item to Order.
			// event		: dojo.dnd.DropEvent object.
			//				  An event object class for passing state information between participants in a 
			//				  drag-and-drop operation cycle.
			// assumptions	: None.
			// dojo API		: None.
			// returns		: true.
			this.add2ShopCartAjaxForDroppedItems(event.dragSource.dragObject);
			return true;
		},

		add2ShopCartAjaxForDroppedItems:function(dragObject)
		{
			// summary		: This function adds item to Order
			// description	: This function adds item to Order. It is called by 'quickCartDropEventHandler'.
			//				  Calling this function leads to change in current Order.
			// dragObject	: dojo.dnd.DragObject object.
			// assumptions	: 'dragObject' should have 'catentryId' property attached to it.
			// dojo API		: None.
			
			var params = [];
			params.storeId = this.storeId;
			params.catalogId = this.catalogId;
			params.langId = this.langId;
			params.orderId		= ".";
			params.catEntryId	= dragObject.catentryId;
			params.quantity		= "1";
			
			if(!this.isDefaultShippingProvided){
				this.alertParams(params);
				wc.service.invoke("AjaxAddOrderItem", params);
			}
			else{
				this.addItemWithShipingInfo(params);
			}
			cursor_wait();
		},

		deleteFromCart:function(){
			// summary		: This function removes item(s) from Order.
			// description	: This function removes selected item(s) from current Order.
			//				  Calling this function leads to change in current Order.
			// assumptions	: Form id for 'Quick Cart' should be 'QuickCartForm' and CSS class for the checkbox 
			//				  associated with each orderItem in 'QuickCartForm' shold be 'QuickCartForm_checkboxItems'.
			// dojo API		: dojo.html.getElementsByClass(), dojo.lang.isArrayLike() and dojo.lang.forEach().
			
			var params = [];
			params.storeId = this.storeId;
			params.catalogId = this.catalogId;
			params.langId = this.langId;
			var needToCall = false;

			checkItems = dojo.html.getElementsByClass('QuickCartForm_checkboxItems');

			if(dojo.lang.isArrayLike(checkItems)){
				dojo.lang.forEach(checkItems, function(node){
					if(node.checked){
						var nodeValue = node.value;
						nodeValue = eval('(' + nodeValue + ')');
						
						for(key in nodeValue){
							params = updateParamObject(params, key, nodeValue[key], false, -1);
						}

						needToCall=true;
					}
				});
			}else{
				if(checkItems.checked == true){
					var nodeValue = checkItems.value;
					nodeValue = eval('(' + nodeValue + ')');
					for(key in nodeValue){
						params = updateParamObject(params, key, nodeValue[key], false);
					}

					needToCall=true;
				}
			}

			if(needToCall){
				params.orderId	= ".";
				this.alertParams(params);
				wc.service.invoke("AjaxDeleteOrderItem", params);
				cursor_wait();
			}
			
			var checkAllNode = dojo.byId("checkAllCartItem");
			checkAllNode.checked = false;
		},


		moveFromCart:function(){
			// summary		: This function moves item(s) from Order to 'WishList'.
			// description	: This function removes selected item(s) from current Order. and add same item(s) 
			//				  to user's 'WishList'. Calling this function leads to change in current Order as well as 
			//				  change in user's 'WishList'.
			// assumptions	: Form id for 'Quick Cart' should be 'QuickCartForm' and CSS class for the checkbox 
			//				  associated with each orderItem in 'QuickCartForm' shold be 'QuickCartForm_checkboxItems'.
			// dojo API		: dojo.html.getElementsByClass(), dojo.lang.isArrayLike() and dojo.lang.forEach().
			
			var needToCall = false;
			var params1 = [];
			params1.storeId = this.storeId;
			params1.catalogId = this.catalogId;
			params1.langId = this.langId;
			var params2 = [];
			params2.storeId = this.storeId;
			params2.catalogId = this.catalogId;
			params2.langId = this.langId;

			checkItems = dojo.html.getElementsByClass('QuickCartForm_checkboxItems');

			if(dojo.lang.isArrayLike(checkItems)){
				dojo.lang.forEach(checkItems, function(node){
					if(node.checked){
						var nodeValue = node.value;
						nodeValue = eval('(' + nodeValue + ')');
						
						for(key in nodeValue){
							var value = nodeValue[key];
							params1 = updateParamObject(params1, key, value, false, -1);
							params2  = updateParamObject(params2, key, value, false, -1);
						}

						needToCall=true;
					}
				});
			}else{
				if(checkItems.checked == true){
					var nodeValue = checkItems.value;
					nodeValue = eval('(' + nodeValue + ')');
					
					for(key in nodeValue){
						params1 = updateParamObject(params1, key, nodeValue[key], false);
						params2 = updateParamObject(params2, key, nodeValue[key], false);
					}

					needToCall=true;
				}
			}
			
			if(needToCall){
				params1.orderId	= ".";
				this.alertParams(params1);
				wc.service.invoke("AjaxDeleteOrderItem", params1);
				cursor_wait();

				params2.URL = "SuccessfulAJAXRequest";
				this.alertParams(params2);
				wc.service.invoke("AjaxInterestItemAdd", params2);
				cursor_wait();
			}
			
			var checkAllNode = dojo.byId("checkAllCartItem");
			checkAllNode.checked = false;
		},

		updateCartWait:function(quantityBox, orderItemId) {
			// summary		: This function updates the Order after waiting for 'updateWaitTimeOut' miliseconds.
			// description	: This function updates the Order after waiting for 'updateWaitTimeOut' miliseconds.
			//				  with new quantity specified by user for particular order item.
			// quantityBox	: DOM Node 
			//				  DOM node representing the quantity testbox.
			// orderItemId	: Number
			//				  OrderItemId for the Item being updated.
			// assumptions	: None.
			// dojo API		: None.
		},

		updateCart:function(quantityBox, orderItemId){
			// summary		: This function updates the Order
			// description	: This function updates the Order with new quantity specified by user for
			//				  particular order item.
			// quantityBox	: DOM Node 
			//				  DOM node representing the quantity testbox.
			// orderItemId	: Number
			//				  OrderItemId for the Item being updated.
			// assumptions	: None.
			// dojo API		: None.

			var quantity = parseInt(quantityBox.value);
			if(!isNaN(quantity)){
				var params = [];
				params.storeId = this.storeId;
				params.catalogId = this.catalogId;
				params.langId = this.langId;
				params.orderId		= ".";
				params.quantity		= quantity;
				params.orderItemId	= orderItemId;
				this.alertParams(params);
				wc.service.invoke("AjaxUpdateOrderItem",params);
				cursor_wait();
			}else{
				//Quantity is not number
				//Do you want me to alert user for this?
			}
		},

		
		wishListDropEventHandler:function(event){
			// summary		: This function adds item to WishList when user drops an item in 'Wish List'
			// description	: This function adds item to WishList when user drops an item in 'Wish List'
			//				  It calls add2WishListAjaxForDroppedItems function which actually adds
			//				  droppped item to WishList.
			// event		: dojo.dnd.DropEvent object.
			//				  An event object class for passing state information between participants in a 
			//				  drag-and-drop operation cycle.
			// assumptions	: None.
			// dojo API		: None.
			// returns		: true.
			this.add2WishListAjaxForDroppedItems(event.dragSource.dragObject);
			return true;
		},

		add2WishListAjaxForDroppedItems:function(dragObject)
		{
			// summary		: This function adds/moves item to WishList
			// description	: This function have two diffrent behaviours.
			//				  If Item is dragged from 'Quick Cart' it will Move the item from Order to 'WishList'
			//				  If item is not dragged from 'Quick Cart' it will add it to 'WishList'.
			//				  Calling this function leads to change in WishList and/or Order.
			// dragObject	: dojo.dnd.DragObject object.
			// assumptions	: 'dragObject' should have 'catentryId' property attached to it.
			//				  If item is dragged from 'Quick Cart', it should also have 'orderId' and 'orderItemId'.
			// dojo API		: None.

			var params = [];
			params.storeId = this.storeId;
			params.catalogId = this.catalogId;
			params.langId = this.langId;

			if(dragObject.catentryId == null)
				return;

			if(typeof dragObject.orderId != "undefined" && typeof dragObject.orderItemId != "undefined"){
				//Move to WishList
				params.orderId	= ".";
				params.orderItemId	= dragObject.orderItemId;
				this.alertParams(params);
				wc.service.invoke("AjaxDeleteOrderItem", params);
				cursor_wait();
			}

			//Add to WishList
			params.URL = "SuccessfulAJAXRequest";
			params.catEntryId = dragObject.catentryId;
			this.alertParams(params);
			wc.service.invoke("AjaxInterestItemAdd", params);
			cursor_wait();
		},
		
		deleteFromWishList:function(){
			// summary		: This function removes item(s) from 'WishList'.
			// description	: This function removes selected item(s) from current 'WishList'.
			//				  Calling this function leads to change in 'WishList'.
			// assumptions	: Form id for 'Wish List' should be 'WishListForm' and CSS class for the checkbox 
			//				  associated with each orderItem in 'WishListForm' shold be 'WishListForm_checkboxItems'.
			// dojo API		: dojo.html.getElementsByClass(), dojo.lang.isArrayLike() and dojo.lang.forEach().
			
			var params = [];
			params.storeId = this.storeId;
			params.catalogId = this.catalogId;
			params.langId = this.langId;
			var needToCall = false;
			
			checkItems = dojo.html.getElementsByClass('WishListForm_checkboxItems');

			if(dojo.lang.isArrayLike(checkItems)){
				dojo.lang.forEach(checkItems, function(node){
					if(node.checked){
						var nodeValue = node.value;
						nodeValue = eval('(' + nodeValue + ')');
						for(key in nodeValue){
							params = updateParamObject(params, key, nodeValue[key], true);
						}

						needToCall=true;
					}
				});
			}else{
				if(checkItems.checked == true){
					var nodeValue = checkItems.value;
					nodeValue = eval('(' + nodeValue + ')');
					for(key in nodeValue){
						params = updateParamObject(params, key, nodeValue[key], false);
					}

					needToCall=true;
				}
			}

			if(needToCall){
				params.URL = "SuccessfulAJAXRequest";
				this.alertParams(params);
				wc.service.invoke("AjaxInterestItemDelete", params);
				cursor_wait();
			}
			
			var checkAllNode = dojo.byId("checkAllWishListItem");
			checkAllNode.checked = false;
		},
		
		moveFromWishList:function(){
			// summary		: This function adds item(s) to Order from 'WishList'.
			// description	: This function adds selected item(s) to current Order from user 'WishList'.
			//				  Calling this function leads to change in current Order.
			// assumptions	: Form id for 'Quick Cart' should be 'WishListForm' and CSS class for the checkbox 
			//				  associated with each orderItem in 'WishListForm' shold be 'WishListForm_checkboxItems'.
			// dojo API		: dojo.html.getElementsByClass(), dojo.lang.isArrayLike() and dojo.lang.forEach().
			
			var params = [];
			params.storeId = this.storeId;
			params.catalogId = this.catalogId;
			params.langId = this.langId;
			var needToCall = false;

			checkItems = dojo.html.getElementsByClass('WishListForm_checkboxItems');

			if(dojo.lang.isArrayLike(checkItems)){
				dojo.lang.forEach(checkItems, function(node){
					if(node.checked){
						var nodeValue = node.value;
						nodeValue = eval('(' + nodeValue + ')');
						
						for(key in nodeValue){
							params = updateParamObject(params, key, nodeValue[key], false, -1);
						}
						
						needToCall=true;
					}
				});
			}else{
				if(checkItems.checked == true){
					var nodeValue = checkItems.value;
					nodeValue = eval('(' + nodeValue + ')');
					
					for(key in nodeValue){
						params = updateParamObject(params, key, nodeValue[key], false);
					}
					
					needToCall=true;
				}
			}

			if(needToCall){
				params.orderId	= ".";
				//wc.service.invoke("AjaxAddOrderItem", params);
				if(!this.isDefaultShippingProvided){
					this.alertParams(params);
					wc.service.invoke("AjaxAddOrderItem", params);
				}
				else{
					this.addItemWithShipingInfo(params);
				}
				cursor_wait();
			}
			var checkAllNode = dojo.byId("checkAllWishListItem");
			checkAllNode.checked = false;
		},

		fastCheckout:function(formNodeId){
			// summary		: This function performs 'fast check out'.
			// description	: This function performs 'fast check out' by submitting the order, with user's
			//				  'fast check out profile'.
			// formNode		: DOM node
			//				  A DOM node representing form to be submitted.
			//				  drag-and-drop operation cycle.
			// assumptions	: None.
			// dojo API		: dojo.io.bind().

			//AjaxOrderCopy
			//wc.service.invoke("AjaxPrepareOrder");
			//wc.service.invoke("AjaxSubmitOrder");
			
			wc.service.declare({
				id: "FastCheckOutPrepareOrder",
				actionId: "FastCheckOutPrepareOrder",
				url: "AjaxOrderProcessServiceOrderPrepare",
				formId: formNodeId,
				successHandler: function(serviceResponse) {
					cursor_clear();
					wc.service.invoke("AjaxSubmitOrder");
				},
				failureHandler: function(serviceResponse) {
					if(serviceResponse !=null && serviceResponse.errorMessage!=null)
						alertDialog(serviceResponse.errorMessage,this.storeId,this.catalogId,this.langId);
					else	alert("Error");
				}
			});

			wc.service.declare({
				id: "FastCheckOutOrderCopy",
				actionId: "FastCheckOutOrderCopy",
				url: "AjaxOrderCopy",
				formId: formNodeId,
				successHandler: function(serviceResponse) {
					cursor_clear();
					wc.service.invoke("FastCheckOutPrepareOrder");
					cursor_wait();
				},
				failureHandler: function(serviceResponse) {
					if(serviceResponse !=null && serviceResponse.errorMessage!=null)
						alertDialog(serviceResponse.errorMessage,this.storeId,this.catalogId,this.langId);
					else	alert("Error");
				}
			});

			wc.service.invoke("FastCheckOutOrderCopy");
			cursor_wait();
		},

		showCompare:function(show){
			this.isComparePane = show;
		},

		getStorageKey:function(){
			var storageKey = "CompareItems";
			var sessionId = this.getProperty("sessionId");
			var sessionCode = 0;
			for(i=0; i < sessionId.length; i++){
				sessionCode = sessionCode + sessionId.charCodeAt(i);
			}
			storageKey = storageKey + sessionCode;
			return storageKey;
		},

		initializeCompare:function(){
			var storageKey = this.getStorageKey();
			
			if(this.isComparePane){
				this.compareCounter=0;
				this.compareRowCounter=0;
				this.compareItemCatEntry=new Object();

				//Load the compare items from dojo.storage using 'CompareItems' key.
				var result = StorageJS.load(storageKey);
				if(result != null){
					this.compareItemCatEntry = result;
				}
					
				var compare = document.getElementById("compareZone");
				var childNodes = compare.childNodes;
				for (i=0; i<childNodes.length; i++) {
					if (childNodes[i].id != "compareDropZoneImg") {
						compare.removeChild(childNodes[i]);
					}
				}

				var firstItem = true;
				for(catEntryIdentifier in this.compareItemCatEntry){

					this.compareCounter++;

					if (this.compareCounter <= 6) {
						var catentryAddedToCompare = document.CompareForm.catentryId[this.compareCounter-1].value = catEntryIdentifier;
				
						for (i=0; i<childNodes.length; i++) {
							if (childNodes[i].id == "compareDropZoneImg") {
								compare.removeChild(childNodes[i]);
							}
						}
					
						var td1 = document.createElement("td");
						td1.setAttribute("id", "compareCatentry"+catentryAddedToCompare);

						var div1 = document.createElement("div");
						div1.setAttribute("id", "compareCatentryCheckBoxContainer"+catentryAddedToCompare);
						var checkBox = document.createElement("input");
						checkBox.setAttribute("id", "compareCatentryCheckBox"+catentryAddedToCompare);
						checkBox.setAttribute("type", "checkbox");
						checkBox.setAttribute("class", "CompareForm_checkboxItems");
						checkBox.setAttribute("value", catEntryIdentifier);
						div1.appendChild(checkBox);

						var div2 = document.createElement("div");
						div2.setAttribute("id", "compareCatentryContainer"+catentryAddedToCompare);
						
						td1.appendChild(div1);
						td1.appendChild(div2);

						
						//Get the content of the TD from this.compareItemCatEntry variabale which was populated with
						//values stored into dojo.storage under 'CompareItems' key.
						div2.innerHTML = this.compareItemCatEntry[catEntryIdentifier];
						var node = dojo.dom.getFirstChildElement(div2);

						//Enable drag-drop for compare item
						var compareItemDragSource = new dojo.dnd.HtmlDragSource(node, "compare_item");
						compareItemDragSource.dragObject["catentryId"] = catEntryIdentifier;
		
						if (((this.compareCounter-1) % 3) == 0 ) {
							this.compareRowCounter++;
							
							var tr1 = document.createElement("tr");
							tr1.setAttribute("id", "compareRow"+this.compareRowCounter);
						} else {
							var tr1 = document.getElementById("compareRow"+this.compareRowCounter);
						}
						tr1.appendChild(td1);
						
						if (firstItem) {
							var table1 = document.createElement("table");
							
							var tbody1 = document.createElement("tbody");
							tbody1.setAttribute("id", "compareItemsTable");
							table1.appendChild(tbody1);
							
							tbody1.appendChild(tr1);
							compare.appendChild(table1);
						} else {
							var tbody1 = document.getElementById("compareItemsTable");
							tbody1.appendChild(tr1);
						}

						firstItem = false;
					}

				}
			}
		},

		Add2CompareAjax:function(catEntryIdentifier, node){
			var storageKey = this.getStorageKey();
			
			if(catEntryIdentifier in this.compareItemCatEntry || catEntryIdentifier == null){
				alert(this.getErrorMessage("compareItemExist"));
				return false;
			}else{
				this.compareCounter++;

				if (this.compareCounter <= 6) {
					document.CompareForm.catentryId[this.compareCounter-1].value = catEntryIdentifier;
	
					//Save the compare items into dojo.storage under 'CompareItems' key, so that we can later retrive it

					var html = node.innerHTML.replace(/^\s+/, "").replace(/\s+$/, "");
					html = html.replace(/\"/g, "'").replace(/\r|\n|\r\n|\n\r/g, "");
					this.compareItemCatEntry[catEntryIdentifier] = html;
					StorageJS.save(storageKey, this.compareItemCatEntry, -1);
					
					//initialize the compare pane with all the items
					this.initializeCompare();

					//return true;
				} else {
					alert(this.getErrorMessage("compareMaxItems"));
					//return false;
				}
			}
		},

		Add2CompareAjaxWith:function(catEntryIdentifier, dragImagePath , url){
			var storageKey = this.getStorageKey();
			
			if(catEntryIdentifier in this.compareItemCatEntry || catEntryIdentifier == null){
				alert(this.getErrorMessage("compareItemExist"));
				//return false;
			}else{
				this.compareCounter++;

				if (this.compareCounter <= 6) {
					document.CompareForm.catentryId[this.compareCounter-1].value = catEntryIdentifier;
					var _id = "Compare_Item_"+catEntryIdentifier;
					var itemHTML = ""	
							+"	<a id='imgcatBrowse"+ _id + "' href='"+ url +"' >\n"
							+"		<img src='"+ dragImagePath +"' alt='"+ dragImagePath +"' border='0' />\n"
							+"	</a>\n"

					//Save the compare items into dojo.storage under 'CompareItems' key, so that we can later retrive it
					itemHTML = itemHTML.replace(/\"/g,"'").replace(/\r|\n|\r\n|\n\r/g, "");
					this.compareItemCatEntry[catEntryIdentifier] = itemHTML;
					StorageJS.save(storageKey, this.compareItemCatEntry, -1);
					//initialize the compare pane with all the items
					this.initializeCompare();

					//return true;
				} else {
					alert(this.getErrorMessage("compareMaxItems"));
					//return false;
				}
			}
		},

		/**********************************************************
		* Function to add a catEntry to the shopping cart. Used in conjunction
		* with CatalogEntryThumbnailDisplay.jspf. 
		*
		*	Parameters:
		*	catEntryIdentifier - the identifier of the catalog entry element
		* 
		* Assumptions that there are DOM elements called "formParamsStoreId_<catEntryIdentifier>",
		* "formParamsCatalogId_<catEntryIdentifier>", "formParamsCatEntryId_<catEntryIdentifier>",
		* "attributeValuesClass_<catEntryIdentifier>", "attrNameClass_<catEntryIdentifier>".
		**********************************************************/
		compareDropEventHandler:function (event) {
			event.dragSource.type="compare_item";
			var node = event.dragObject.domNode;
			var catEntryIdentifier = event.dragSource.dragObject.catentryId;
			
			var dragNode = event.dragObject.domNode;
			var node = dragNode.cloneNode(true);

			this.Add2CompareAjax(catEntryIdentifier, node);
		},

		/**********************************************************
		* Function to add a catEntry to the shopping cart. Used in conjunction
		* with CatalogEntryThumbnailDisplay.jspf. 
		*
		*	Parameters:
		*	catEntryIdentifier - the identifier of the catalog entry element
		* 
		* Assumptions that there are DOM elements called "formParamsStoreId_<catEntryIdentifier>",
		* "formParamsCatalogId_<catEntryIdentifier>", "formParamsCatEntryId_<catEntryIdentifier>",
		* "attributeValuesClass_<catEntryIdentifier>", "attrNameClass_<catEntryIdentifier>".
		**********************************************************/
		increaseCompareCounter:function() {
			this.compareCounter++;
		},

		//drop event handler for the delete from compare zone
		deleteFromCompareZone:function(){
			var storageKey = this.getStorageKey();
			
			checkItems = dojo.html.getElementsByClass('CompareForm_checkboxItems');
			var items = [];
			if(dojo.lang.isArrayLike(checkItems)){
				dojo.lang.forEach(checkItems, function(node){
					if(node.checked){
						var catEntryIdentifier = parseInt(node.value);
						items.push(catEntryIdentifier);
						//delete this.compareItemCatEntry[node.value];
						this.compareCounter--;
					}
				});
			}else{
				if(checkItems.checked == true){
					var catEntryIdentifier = parseInt(checkItems.value);
					items.push(catEntryIdentifier);
					//delete this.compareItemCatEntry[checkItems.value];
					this.compareCounter--;
				}
			}
			

			for(index in items){
				delete this.compareItemCatEntry[items[index]];
			}

			StorageJS.save(storageKey, this.compareItemCatEntry, -1);
			
			//initialize the compare pane with all remaining items if any.
			this.initializeCompare();

			var checkAllNode = dojo.byId("checkAllCompareItem");
			checkAllNode.checked = false;

			//return true;
		},

		compareProducts:function(){
			var storageKey = this.getStorageKey();

			//Load the compare items from dojo.storage using 'CompareItems' key.
			var result = StorageJS.load(storageKey);
			if(result != null){
				this.compareItemCatEntry = result;
			}

			var url = document.CompareForm.action + "?storeId=" + document.CompareForm.storeId.value + "&catalogId=" + document.CompareForm.catalogId.value +
				"&langId=" + document.CompareForm.langId.value + "&categoryId=" + document.CompareForm.categoryId.value;
			
//			if (document.CompareForm.catentryId[0].value != "") {
//				url = url + "&catentryId=" + document.CompareForm.catentryId[0].value;
//			}
//			if (document.CompareForm.catentryId[1].value != "") {
//				url = url + "&catentryId=" + document.CompareForm.catentryId[1].value;
//			}
//			if (document.CompareForm.catentryId[2].value != "") {
//				url = url + "&catentryId=" + document.CompareForm.catentryId[2].value;
//			}
//			if (document.CompareForm.catentryId[3].value != "") {
//				url = url + "&catentryId=" + document.CompareForm.catentryId[3].value;
//			}
//			if (document.CompareForm.catentryId[4].value != "") {
//				url = url + "&catentryId=" + document.CompareForm.catentryId[4].value;
//			}
//			if (document.CompareForm.catentryId[5].value != "") {
//				url = url + "&catentryId=" + document.CompareForm.catentryId[5].value;
//			}
//			if (document.CompareForm.catentryId[6].value != "") {
//				url = url + "&catentryId=" + document.CompareForm.catentryId[6].value;
//			}
//			if (document.CompareForm.catentryId[7].value != "") {
//				url = url + "&catentryId=" + document.CompareForm.catentryId[7].value;
//			}

			for(catEntryIdentifier in this.compareItemCatEntry){
				url = url + "&catentryId=" + catEntryIdentifier;
			}

			document.location.href = url;
		},

		quickCartPostRefreshHandler:function(){
			if( !("quickCart" in this.flexFlowOptions) || ("quickCart" in this.flexFlowOptions && this.flexFlowOptions["quickCart"] == true)){
				var quickCartFormName = "QuickCartForm";
				var miniQuickCartTextName = "miniQuickCartText";
				if(document.getElementById(miniQuickCartTextName)){
					document.getElementById("QuickCartTilePaneString").innerHTML = document.getElementById(miniQuickCartTextName).value;
				}
				this.updateShipmentSelectBoxes();
			}
		},
			
		wishListPostRefreshHandler:function(){
			if( !("wishList" in this.flexFlowOptions) || ("wishList" in this.flexFlowOptions && this.flexFlowOptions["wishList"] == true)){
				var wishListFormName = "WishListForm";
				var miniWishListTextName = "miniWishListText";
				//alert(document.getElementById(wishListFormName)[miniWishListTextName].value);
				if(document.getElementById(miniWishListTextName)){
					document.getElementById("WishListTilePaneString").innerHTML = document.getElementById(miniWishListTextName).value;
				}
			}
		},

		updateShipmentSelectBoxes:function(){
			if(this.isShipmentPage){
				this.shipmentBlockObject = shipmentPageJS.getQuickCartHelperObjects();
				if(this.shipmentBlockObject != null){
					var selectedValue = "";
					var widgets = dojo.widget.manager.getWidgetsByFilter(this.quickCartProductQuickViewFilter, false);
					//We've got the widgets now lets find the shipmentSelectBox and update them
					//We've added the shipmentSelectBoxId and quantityInputBoxId into additionalProperties of the widget
					//Hopefully we can get the SelectBox node using shipmentSelectBoxId.
					for(widget in widgets){
						//var selectedIndex = 0;
						var productQuickViewWidget = widgets[widget];
			
						if(productQuickViewWidget != null && productQuickViewWidget.shipmentSelectBoxId != null){
							//var hiddenShipmentSelectBoxNode =  dojo.byId(productQuickViewWidget.shipmentSelectBoxId);
							
							//var hiddenShipmentSelectBoxId = productQuickViewWidget.shipmentSelectBoxId;
							var i = productQuickViewWidget.orderItemId;

							
							var selectBoxSelectedValueNode = document.getElementById("SelectBoxSelectedValue_" + i);
//							var shipmentSelectBoxOptionContainerNode = document.getElementById("ShipmentSelectBoxOptionContainer_" + i);
//							shipmentSelectBoxOptionContainerNode.innerHTML = "";

//							for(option in hiddenShipmentSelectBoxNode.options)
//								hiddenShipmentSelectBoxNode.options[option] = null;

							//hiddenShipmentSelectBoxNode.options.length = 0;

							for(shipDetailKey in this.shipmentBlockObject ){
//								var valueObject = eval("("+this.shipmentBlockObject[shipDetailKey]+")");
								var valueObject = this.shipmentBlockObject[shipDetailKey];
								var shipDetailKey = parseInt(shipDetailKey);

								if(productQuickViewWidget.addressId == valueObject.addressId && productQuickViewWidget.shipModeId == valueObject.shipModeId){
									//selectedIndex = shipDetailKey;
									selectedValue = shipDetailKey + 1;
									break;
								}

								//hiddenShipmentSelectBoxNode.options[shipDetailKey] = new Option(shipDetailKey,this.shipmentBlockObject[shipDetailKey]);
								//hiddenShipmentSelectBoxNode.options[shipDetailKey] = new Option(shipDetailKey,(shipDetailKey+1));

//								var scriptString = "JavaScript:"
//												+		"if(document.getElementById('SelectBoxSelectedValue_"+ i +"').innerHTML != '"+(shipDetailKey+1)+"')"
//												+		"{"
//												+			"if(shipmentPageJS.isValidBlock("+(shipDetailKey+1)+")){"
//												+				"document.getElementById('SelectBoxSelectedValue_"+ i +"').innerHTML = '"+ (shipDetailKey+1) +"';"
//												+				"document.getElementById('"+ hiddenShipmentSelectBoxId +"').selectedIndex = "+shipDetailKey+";"
//												+				"document.getElementById('"+ hiddenShipmentSelectBoxId +"').onchange.call();"
//												+			"}else{"
//												+				"alert('Please select a valid address and shipping method in Shipment " + (shipDetailKey+1)+"');"
//												+			"}"
//												+		"}";
								

								//var tempOption = document.createElement("a");
//								tempOption.setAttribute("href", scriptString);
								//tempOption.setAttribute("class", "shipmentSelectOption");
								//tempOption.appendChild(document.createTextNode(parseInt(shipDetailKey)+1));

								//shipmentSelectBoxOptionContainerNode.appendChild(tempOption);
								//shipmentSelectBoxOptionContainerNode.appendChild(document.createElement("br"));
							}
							//hiddenShipmentSelectBoxNode.selectedIndex = selectedIndex;
							selectBoxSelectedValueNode.innerHTML = selectedValue;

						}else{
							alert("shipmentSelectBoxId property is not set under additionalProperties for ProductQuickViewWidget");
						}
					}
				}
			}
		},


		quickCartProductQuickViewFilter:function(widget){
			var widgetType = "productquickview";
			if(widget.widgetType.toLowerCase() == widgetType){
				tempStr = widget.identifier;
				tempStr = tempStr.substring(0,17);
				if (tempStr == "quickCartCatEntry") {
					return true;
				}
			}
			return false;
		},

		shipmentChanged: function(params, selectBoxId){
			params = eval("( " + params + " )");
			var selectedShipment = dojo.byId(selectBoxId).options[dojo.byId(selectBoxId).selectedIndex].value;
			
			if(shipmentPageJS.isValidBlock(selectedShipment)){
				var newShipmentParams = eval("("+ shipmentPageJS.getQuickCartHelperObjects()[selectedShipment-1] +")");
					
				for(newParam in newShipmentParams){
					params = updateParamObject(params, newParam, newShipmentParams[newParam], false);
				}
				this.updateItemShipingInfo(params);
			}else{
				alert("Please select a valid address and shipping method in Shipment "+selectedShipment);
			}
		},

		updateItemShipingInfo:function(params){
			wc.service.invoke("OrderItemShipmentBlockUpdate", params);
			cursor_wait();
		},

		showShipment:function(show){
			this.isShipmentPage = show;
		},

		setFlexFlowOptions:function(key, value){
			this.flexFlowOptions = updateParamObject(this.flexFlowOptions, key, value, false);
		},

		alertParams:function(params){
			var str = "";
			for(x in params)
				str = str + "\n" + x + ":" + params[x];
			
			//alert(str);
		}
	}	
	

	/******************************************************************************************************************
	 *                                        STORE ACORDION FUNCTIONS                                                *
	 *                                                    END                                                         *
	 ******************************************************************************************************************/



