// This is a file to hold helper functions for the calendar
//
// Just a bunch of wrapper functions, maybe it will be inheritance one day

//Global Variables
var saved_requests = new Array;  //this is an array to store each ajax request 
//to retrieve the dates based on zipcode and product id.  This way we can reuse 
//requests and not have to hit the server everytime.

//this is our array with all our open calendars
//this way if the user quickly clicks on the submit button we won't open 2 at
//once.  We store an object with a reference to the open calendar and the zipcode
//used for that calendar.  This way if the zipcode changes we can close down 
//the open calendar.
// Comments for QA test, 20100715T1040
var calendars_open = new Object();


/*
	Calendar.setup(
	{
		datestatusfunc: ourdatestatusfunc,
		onupdate: datechanged,
		position: position,
		show_legend: show_legend,
		weeknumbers: false,
		inputfield: inputfield,
		hiddenlayer: hiddenlayername,
		startyear: startyear,
		startmonth: startmonth,
		endyear: endyear,
		endmonth: endmonth,
		footer: footer,
		nofootermessages: nofootermessages,
		heading: heading,
		mouseoffclose: mouseoffclose, 
		button: triggername,
		date: document.getelementbyid(inputfield).value,
		flat: flatid,    //this is if we want the calendar to be inside a parent
        specialflat: specialflat || false,  //this is if we want a special flat calendar
										   //this is basically a mix of the
										   //flat calendar and the popup
										   //calendar
		loading_calendar: loading_cal					
	}
	);
*/

/*
	This is a wrapper function for Calendar.setup
	- it's really trying to rewrite buildCalendar() to make it easier to override, and set defaults
*/
Calendar.wrapperSetup = function (params) {
    function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	// default postion should be the x and y coords, can i find it at this location?
	param_default("position", new Array(0,0));

	//default for onClose
	var _onClose = function (cal)
    {//we want to set the let everyone know that 
	//our calendar is closed by calling this function
	 setCalendarClosed(cal); //this should be called in all
	 cal.hide();  //we have to hide as well
	 cal.destroy();
	 //onClose handlers.  So if you override this
	 //then add setCalendarClosed(cal)
	 //unless you don't care about multiple calendars open at once
	}
													   
	// dateChanged

	param_default("show_legend", 0);
	param_default("mouseOffClose", false);
	param_default("noFooterMessages", false);
	param_default("onClose", _onClose);
	//param_default("wrapperSetup_TEST", "Hi World");


	// default, just gives an alert, so you can see what it does
	var _onUpdate = function (calendar) {
		if (calendar.dateClicked) {
			// get new form data dates (pretty one for display and one for submission 
			var formattedDate = calendar.date.print("%a %m/%d/%y");
			var deldate = calendar.date.print("%Y/%m/%d");
			if((deldate === calendar.params.today_date) && calendar.params.sdu_applied )
				formattedDate = calendar.date.print("Today %m/%d/%y");

		}
	}
	param_default("onUpdate", _onUpdate);



	// What is the ourExtraDateStatusFunc
	// Well this is sort of another call back that is called
	// so ourDateStatusFunc calls

	return Calendar.setup( params );
}




/* 
	Now things get complicated
*/


/*
	This is a loading calendar 
	This will display a loading calendar that will stay open
	while the ajax request is running.  Once the ajax call returns
	and the new calendar opens, the new calendar will take care of closing
	the loading calendar down.  However, you must set params.loading_calendar
	to the return value of this function. We will create a new params
	object for the loading calendar.  This way we can inherit all our params
	from the regular calendar but also modify some values just for the loading 
	calendar and not worry about messing with the params for the real calendar. 
*/
Calendar.loadingSetup = function (params) {
	var load_params = {}; //define our own loading params

	function param_default(pname, def) { if (typeof load_params[pname] == "undefined") { load_params[pname] = def; } };

	for (var i in params)
	{//take everything off our params object
	 load_params[i] = params[i];
	}

	//now we set anything that is specific to our loading 
	//calendar here.
	var empty = function () {return;};  //select function so nothing happens if they click on a day
	param_default("position", new Array(0,0));
	load_params.onSelect =empty ;
	param_default('date',document.getElementById(params.inputFieldID).value);
	load_params.loading = "Loading Calendar Dates";  //let calendar-setup know that this is a loading call
	load_params.loading_calendar = false;  //there can be no loading calendar for a loading calendar

	return Calendar.setup( load_params );
}

/*
    Displays an error message if a product is not available for a given zipcode.
	Functionality is based on the Calendar.loadingSetup function.
*/
Calendar.unavailableSetup = function (params) {
	var load_params = {}; //define our own loading params

	function param_default(pname, def) { if (typeof load_params[pname] == "undefined") { load_params[pname] = def; } };

	for (var i in params)
	{//take everything off our params object
	 load_params[i] = params[i];
	}

	//now we set anything that is specific to our loading 
	//calendar here.
	var empty = function () {return;};  //select function so nothing happens if they click on a day
	param_default("position", new Array(0,0));
	load_params.onSelect =empty ;
	param_default('date',document.getElementById(params.inputFieldID).value);
	param_default('hide_calendar_grid',false);

	// This function is only intended to spit out errors with the zip code.
	if(params.zip_error_message){
	    load_params.loading = params.zip_error_message;
		load_params.hide_calendar_grid = true;
	}else{
	    load_params.loading = "This product is not available for the entered zipcode. ";
	}
	
	return Calendar.setup( load_params );
}


/*
	This one is used during in the Shopping Cart for a Regular (Non-International Product)
	- flat (used in the zipcode input field dhtml layer)
	- update zipcode wording on shopping cart page after selecting date
	- update delivery date test on shopping cart page after selecting date
	- hide the zipcode input field dhtml layer after selecting date
*/
Calendar.scartRegularSetup = function (params) {
    function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	var dateChanged = function (calendar) {
	var inputFieldID = params.inputFieldID;
	var zipField = params.zipField;
	var addToCart = params.addToCart;
	var query_string = params.query_string;
	var delDateRange = params.delDateRange;
	var displayDelDateRange = params.displayDelDateRange;
	var entry_num = params.cart_entry_num;
	var shippingCallBack;
	if (params.shippingCallBack) {
		shippingCallBack = params.shippingCallBack;
	}

	if (calendar.dateClicked) {
		//get new form data dates (pretty one for display and one for submission
		var formattedDate = calendar.date.print("%a. %B %d, %Y");
		var deldate = calendar.date.print("%Y/%m/%d");
		if((deldate === calendar.params.today_date) && calendar.params.sdu_applied)
			formattedDate = calendar.date.print("Today, %B %d, %Y");

		//get the date fields 
		var dateField = document.getElementById(inputFieldID);
		var displayField = document.getElementById("item" + entry_num + "_display_deldate");

		var displayText = getObject("item" + entry_num + "_display_area_deldate");
		var zipdisplayText = getObject("item" + entry_num + "zip_area_deldate");
		var dmdisplayText = getObject("item" + entry_num + "delivery_method_area_deldate");

		// update the delivery method, or just the sameday flag => means it's using florist delivery
		var sameday = document.getElementById(params.samedayField);
		if (sameday) {
			if (calendar.shipping_methods_by_date[deldate] == undefined || 
			    calendar.shipping_methods_by_date[deldate].match(/Florist/i) )
				sameday.value = "1";
			else 
				sameday.value = "0";
			    //alert("sameday : "+sameday.value);
		}
	
		if (document.forms['zipform'] && document.forms['zipform'].radio_delivery_date && document.forms['zipform'].radio_delivery_date.length > 0) { 
			var radioFormLength = document.forms['zipform'].radio_delivery_date.length;
			document.forms['zipform'].radio_delivery_date[radioFormLength-1].checked = true;
		}
		
		// fill in the zipcode field in the Delivery Information Section, (if we didn't already
		if (document.getElementById(params.zipField) && document.getElementById(params.deliveryZipField)) {
			document.getElementById(params.deliveryZipField).value = document.getElementById(params.zipField).value;
		}

		if (delDateRange[deldate]) {
			dateField.value = delDateRange[deldate];
			displayField.value = displayDelDateRange[deldate];
				if (displayText)
					displayText.innerHTML = displayDelDateRange[deldate];
				if (zipdisplayText)
					zipdisplayText.innerHTML = document.getElementById(zipField).value;
				if (dmdisplayText && ( calendar.shipping_methods_by_date[deldate] != undefined))
				{
					if(calendar.shipping_methods_by_date[deldate].match(/Florist/i)){
						dmdisplayText.innerHTML = calendar.shipping_methods_by_date[deldate];
					}else{
						dmdisplayText.innerHTML = ''; 
                    } 
				}

				hideElement("item" + entry_num + "_shipping_option_deldate", 0);
				if (addToCart)
					popuplateAddField(addToCart, document.getElementById(zipField).value, delDateRange[deldate], query_string);
		} else {
			dateField.value = deldate;
			displayField.value = formattedDate;
			if (displayText) 
				displayText.innerHTML = formattedDate;
			if (zipdisplayText) 
				zipdisplayText.innerHTML = document.getElementById(zipField).value;
			if (dmdisplayText && ( calendar.shipping_methods_by_date[deldate] != undefined))
			{
                if(calendar.shipping_methods_by_date[deldate].match(/Florist/i)){
			        dmdisplayText.innerHTML = calendar.shipping_methods_by_date[deldate];
			    }else{
			        dmdisplayText.innerHTML = '';
                }
			}

			hideElement("item" + entry_num + "_shipping_option_deldate", 0);
			if (addToCart)
				popuplateAddField(addToCart, document.getElementById(zipField).value, deldate, query_string);
			}
			if (theIOTWDateArray[params.cart_entry_num]) updateDeliveryPagePrices(params.cart_entry_num);
		}
		if (typeof shippingCallBack == 'function') {
			shippingCallBack();
		}
	}

	//we don't want to use t he default onclose handler
	//because we want to clsoe down the 
	//enter zip box as well
    var _onClose = function (cal)
    {//we want to set the let everyone know that
    //our calendar is closed by calling this function

		Ftd.shipping.hide_zip_error(params);
		setCalendarClosed(cal); //this should be called in all on close handlers
		//now we want to close the open Edit zip field box.
		//should this id be in params??
		hideElement("shipping_option_" + cal.params.inputFieldID, 0);
		cal.hide();  //we have to hide as well
		cal.destroy();
    }

	params.onClose = _onClose;	
	params.onUpdate = dateChanged;
	params.hidden_layer_name = 'calendar_background_layer_'+params.cart_entry_id;
    params.button = "calendar_trigger_"+params.inputFieldID;
    params.mouseOffClose = 0;
    //params.date = document.getElementById(inputField).value

 return Calendar.wrapperSetup( params );
}




/*
	This one is used in the Shopping Cart for a Internal Product 
	- popup layer
*/
Calendar.scartInternationalSetup = function (params) {
    function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

//alert("inside Calendar.scartInternationalSetup");
	// Set some defaults
	param_default("scartInernationalSetup_TEST", "Hi there");

	/*	
		define a new calendar onSelect function
		var _onUpdate = function () { .. }	
		calendar_params.onUpdate = _onUpdate();
	*/
	var _onUpdate = function (calendar) {
		var shippingCallBack;
		
		if (params.shippingCallBack) {
			shippingCallBack = params.shippingCallBack;
		}
		if (calendar.dateClicked) {

			// get new form data dates (pretty one for display and one for submission 
			var formattedDate = calendar.date.print("%a %m/%d/%y");
			var deldate = calendar.date.print("%Y/%m/%d");
			if((deldate === calendar.params.today_date) && calendar.params.sdu_applied)
				formattedDate = calendar.date.print("Today %m/%d/%y");

			// get the date fields 
			var dateField = calendar.params.inputField;  // Calendar.setup translates to object
			var displayField = document.getElementById(calendar.params.displayField);
			var displayText = document.getElementById(calendar.params.displayText);

			// the date ranges were saved into the calendar params via buildCalendarParamsFromAjax
			var delDateRange = calendar.params.delDateRange;
			var displayDelDateRange = calendar.params.displayDelDateRange;

			if (delDateRange[deldate]) {
				dateField.value = delDateRange[deldate];
				if (displayField) displayField.value = displayDelDateRange[deldate];
				if (displayText) displayText.innerHTML = displayDelDateRange[deldate];
			} else {
				dateField.value = deldate;
				if (displayField) displayField.value = formattedDate;
				if (displayText) displayText.innerHTML = calendar.date.print("%a. %B %d, %Y");	
			}


			// if it's a "Add Anther to Cart", run function, populateAddField
			if (calendar.params.addToCartURL) {
				var addToCartURL = calendar.params.addToCartURL;	
				
				// For an intl prod, just add the delivery date
				addToCartURL += "&delivery_date="+dateField.value;	
				
				//alert("about to add another: "+addToCartURL);
				window.location = addToCartURL;
			}
			if (theIOTWDateArray[params.cart_entry_num]) updateDeliveryPagePrices(params.cart_entry_num);
		}
		if (typeof shippingCallBack == 'function') {
			shippingCallBack();
		}
	}
	params.onUpdate = _onUpdate;


	return Calendar.wrapperSetup( params );
}




/*
	This one is used in the My Account area
*/
Calendar.myaccountSetup = function (params) {
    function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	// Set some defaults
	param_default("myaccountSetup_TEST", "Hi there");


	/*	
		define a new calendar onSelect function
		var _onUpdate = function () { .. }	
		calendar_params.onUpdate = _onUpdate();
	*/
	var _onUpdate = function (calendar) {
		if (calendar.dateClicked) {

			// get new form data dates (pretty one for display and one for submission 
			var formattedDate = calendar.date.print("%b. %d, %Y");
			var deldate = calendar.date.print("%Y/%m/%d");
			var chosenMonth = calendar.date.print("%m");
			var chosenDay = calendar.date.print("%d");

			// get the date fields 
			var dateField = calendar.params.inputField;  // Calendar.setup translates to object
			var displayField = document.getElementById(calendar.params.displayField);
			var hiddenMonth = document.getElementById(calendar.params.myaccount_month);
			var hiddenDay = document.getElementById(calendar.params.myaccount_day);


			dateField.value = deldate;
			displayField.value = formattedDate;
			hiddenMonth.value = chosenMonth;
			hiddenDay.value = chosenDay;



			// if it's a "Add Anther to Cart", run function, populateAddField
		}
	}
	params.onUpdate = _onUpdate;


	return Calendar.wrapperSetup( params );
}

/* This one is used in the Homepage and Category page for Zip finder */

Calendar.homepageSetup = function (params) {
	    function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };
  
  	   // Set some defaults
            param_default("homepageSetup_TEST", "Hi there");
            
	    var _onUpdate = function (calendar) {
		if (calendar.dateClicked) {
			// write code to add the selected date in the dropdown.
			var displayDateVal = calendar.date.print("%Y/%m/%d"),
			    displayDateTxt = calendar.date.print("%b %e - %A"),
			    displayField = document.getElementById(calendar.params.displayField);
			
			for(var i = 0, len = displayField.children.length; i < len; i++) {
		    	    if (displayField.children[i].value == displayDateVal) {
		    	        displayField.selectedIndex = i;
		                return;
			    }
		    	}
			displayField.options[0] = new Option(displayDateTxt, displayDateVal);
			displayField.selectedIndex = 0;
		}
            }
            params.onUpdate = _onUpdate;
            
	    return Calendar.wrapperSetup( params );

}
										

/* This is for setting up the calendar on the product page
	currently this is called by both the international and 
	regular products.
	takes in our params object and returns a ref to our calendar
	object
*/
Calendar.productPageSetup = function (params) {

function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	//function to be called when they select a date
	var _dateSelected = function (calendar) {
		if (calendar.dateClicked) {
			var formattedDate = calendar.date.print("%a %m/%d/%y");
			var deldate = calendar.date.print("%Y/%m/%d");
			var dateField = document.getElementById(calendar.params.inputFieldID);
			var displayField = document.getElementById("display_" + calendar.params.inputFieldID);
			var shippingDisplayField = document.getElementById(calendar.params.shippingDisplayField);
			var delDateRange = calendar.params.delDateRange;
			var displayDelDateRange = calendar.params.displayDelDateRange;
			
			if((deldate === calendar.params.today_date) && calendar.params.sdu_applied)
				formattedDate = calendar.date.print("Today %m/%d/%y");

			if (delDateRange[deldate]) {
				dateField.value = delDateRange[deldate];
				displayField.value = displayDelDateRange[deldate];
			} else {
				dateField.value = deldate;
				displayField.value = formattedDate;
			}
			shippingDisplayField.value = 'Shipping - ' + calendar.params.shipping_methods_by_date[deldate];
			
		 //right now the calendar is shown on focus of the display field.
		 //so this means that when they click on the field again to choose another
		 //date then it already has focus so this even is not fired therefore
		 //the calendar is not shown.  This way when they click on the field
		 //again we will show the calendar.
			if (document.forms['zipform'] && document.forms['zipform'].radio_delivery_date && document.forms['zipform'].radio_delivery_date.length > 0) {
				var radioFormLength = document.forms['zipform'].radio_delivery_date.length;
				document.forms['zipform'].radio_delivery_date[radioFormLength-1].checked = true;
			}
			if (theIOTWDateArray) updateProductPagePrices(deldate);

		    document.getElementById("display_" + calendar.params.inputFieldID).blur();
			
		}
	}

		var _onclose = function (cal)
		{
		 setCalendarClosed(cal); //this should be called in all
        //onClose handlers.  So if you override this
       //then add setCalendarClosed(cal)
        //unless you don't care about multiple calendars open at once
         cal.hide();
         cal.destroy();  //no longer call destroy Must call it in IE!
		 //right now the calendar is shown on focus of the display field.
         //so this means that when they click on the field again to choose another
         //date then it already has focus so this even is not fired therefore
         //the calendar is not shown.  This way when they click on the field
         //again we will show the calendar.
         document.getElementById("display_" + calendar.params.inputFieldID).blur();
		}

param_default("onUpdate", _dateSelected);  //setting our on update if not set yet
param_default("onClose", _onclose);  //setting our onclose handler

return Calendar.wrapperSetup( params );

}


/* 
	This one is for the old path, shopping cart
*/
Calendar.oldPathSetup = function (params) {
    function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	return Calendar.wrapperSetup( params );
}


/*
	A rather descriptive name of something does what it says it does
	- really just buildCalendar() with some tweaks

	Sets:
		1) dateStatusFunc
		2) onUpdate
		3) footer
		4) startYear
		5) startMonth
		6) endYear
		7) endMonth
*/
function buildCalendarParamsFromAjax( responseText ) {
	// Stores everything into the param data structure that you can pass directly
	// into a Calendar.XXXsetup function
	var params = {};
	var json = eval('(' + responseText + ')');

	var startDay				= json.calendar_start_day;
	var startMonth				= json.calendar_start_month;
	var startYear				= json.calendar_start_year;
	var endDay					= json.calendar_end_day;
	var endMonth				= json.calendar_end_month;
	var endYear					= json.calendar_end_year;
	// one day, remove the need for the extra evals
	var undeliverable			= eval('(' + json.unavailable_dates + ')');
	var saturday				= eval('(' + json.saturday_dates + ')');
	var twoday					= eval('(' + json.twoday_dates + ')');
	var nextday					= eval('(' + json.nextday_dates + ')');
	var delDateRange			= eval('(' + json.del_date_range + ')');
	var displayDelDateRange		= eval('(' + json.display_del_date_range + ')');
	var footer					= eval('(' + json.footer_messages + ')'); 
	var shipping_methods_by_date = eval('(' + json.shipping_methods_by_date + ')');
	var zip_availability         = json.zip_availability;
	var zip_error_message        = json.zip_error_message;

	/*
		dateStatusFunc:  returns false for any unavailable day, use to grey out the date
	
		dateIsSpecial allows us to mark specific dates as being *special*
		so this function is dynamic and actually changes with each callback
		it's used by ourDateStatusFunc  
	*/
	var _dateIsSpecial = function (year, month, day) {
		if ( (year < startYear) || (year == startYear && month < startMonth) || (year == startYear && month == startMonth && day < startDay) ||
			year > endYear || (year == endYear && month > endMonth) || (year == endYear && month == endMonth && day > endDay)
		) return "date_unavailable";

		for (var i in undeliverable[month]) {
			if (undeliverable[month][i] == day) return "date_unavailable";
		}
		for (var i in saturday[month]) {
			if (saturday[month][i] == day)  return "saturday_delivery";
		}
		for (var i in twoday[month]) {
			if (twoday[month][i] == day) return "twoday_delivery";
		}
		for (var i in nextday[month]) {
			if (nextday[month][i] == day) return "nextday_delivery";
		}
		return false;
	}

	var _ourDateStatusFunc = function (date, y, m, d) {
		m = m+1;
		var isSpecial = _dateIsSpecial(y, m, d);
		if (isSpecial) 
			return isSpecial;
		else
			return false; // other dates are enabled
	}
	
	params.dateStatusFunc = _ourDateStatusFunc;

	/* and now just values, not more dynamic function references */
	params.startYear = startYear;
	params.startMonth = startMonth;
	params.endYear = endYear;
	params.endMonth = endMonth;
	params.footer = footer;
	params.shipping_methods_by_date = shipping_methods_by_date;
	
	
	/* store the date ranges, needed for the onUpdate function */
	params.delDateRange = delDateRange;
	params.displayDelDateRange = displayDelDateRange;

    /* store zip errors */
	params.zip_availability = zip_availability;
	params.zip_error_message = zip_error_message;

	/* Added for design2007. Parsing fees out of footer, but we need to know what to parse out */
	/* Also get date from server not untrusty client */
	params.today_date = json.today_date;
	/* SameDay Upcharge Params */
	params.sameday_upcharge = json.sameday_upcharge;
	params.sdu_applied = json.sdu_applied;
	params.dropdown_dates = eval('(' + json.dropdown_dates + ')');

	return params; 
}

/* this will save our request object into a global array
   so that when a user wants to search on dates for a 
	zipcode and product that they have already searched on
	then we don't have to hit the server again
*/
function saveRequest(req,params) {
	var zipFieldElem = document.getElementById(params.zipField);
	var product_id = params.product_id || document.getElementById(params.productField).value;
	var zip_code = params.zip_code || ( zipFieldElem ? zipFieldElem.value : new String () );

	if (zip_code.length > 5) {
		zip_code = zip_code.substring(0,3);
	}
	
	var key = zip_code+"_"+product_id;
	if(isfsenabled && (ShoppingCartCookie.fsm_in_cart() || PA.get_painfo_cookie().fs_m === 'mem')){
	        key += "_fs";
	}
	saved_requests[key] = req;
}

/* This will return a saved request for a given
   zipcode and product id if it exists.  If not
   we just return false.

*/
function getSavedRequest(params) {
	var zipFieldElem = document.getElementById(params.zipField);
	var product_id = params.product_id || document.getElementById(params.productField).value;
	var zip_code = params.zip_code || ( zipFieldElem ? zipFieldElem.value : new String () );

	if (zip_code.length > 5) {
		zip_code = zip_code.substr(0,3);
	}
	
	var key = zip_code+"_"+product_id;
	if(isfsenabled && (ShoppingCartCookie.fsm_in_cart() || PA.get_painfo_cookie().fs_m === 'mem')){
		key += "_fs"; 
	}
	var req = saved_requests[key];

	//should we test for a timestamp value here??? Just to make sure
	//the request is not too old??.
	if(req //first are we defined
	   && req.readyState == 4 //now check our ready state and status 
	   && req.status == 200)
	{
		return req;
	}

	return false;
}

/* This is for showing the calendar on the product page
for regular products.  International products have their own
function
*/
function showProductCalendar(params)
{
	/* if we have a zip error than we don't want to show the 
	calendar
	onload our calendar params has zip error set to true
	only by entering a valid zip code in the zip field
	will the zip error be set to false.  This is all handled
	by the js functions called zipSuccess and zipFailure
	which are currently defined in product.epl
	*/
	if(params.invalidZip) {
		//if the ajax call is still running for validating zip
		//then we will display the zip error even if there isn't one!
	 	if(document.getElementById(params.zipField).value == '') {
			//this is for the case when they don't enter a zip
			//and therefore the ajax call in not called.
			hideElement(params.zipErrorID,true);
			return;
		}

		if(params.validating_zip) {
			//we are going to the server to validate
			//so comeback later
			var _func = function () { showProductCalendar(params);};

			window.setTimeout(_func,50);
		}
		return;
	}
	
	/* incase you click on the link twice before it popups */
    if (isCalendarOpen(params)) {
        return;
    }
    //we don't have an actual reference to our calendar so just
    //send in 1 for the second param.  This way if the user
    //quickly clicks the button then we won't open 2 calendars at once
	//alert('Hello');
	setCalendarOpen(params,1);

	//call the loadCalendar setup.  Which will return a reference to
	//our loading calendar object which we will add to params
	//so we can close it within calendar.js
	var loadingCal = Calendar.loadingSetup(params);
    params.loading_calendar = loadingCal;

	//if the calendar pops up over the input field while they have focus
	//on the field then the cursor peeks through into the calendar.
	//so we will shift focus off the input field
	document.getElementById("display_" + params.inputFieldID).blur();

	//build our ajax call back to get all our dates
	var ajaxCallBack = function (req) {
		if (req.readyState == 4 && req.status == 200) {
			// process the parameters	
			var calendar_params = buildCalendarParamsFromAjax(req.responseText);	
			   /* only copy values into the calendar object
               that has not been set by the ajax call back */
               for (i in params)
                if (typeof calendar_params[i] == "undefined")
                    calendar_params[i] = params[i];
			/* setup the other params form the input 
			 */
			calendar_params.inputField = params.inputField;
			calendar_params.hiddenLayer = params.hiddenLayer;
			calendar_params.button = params.button || params.triggerName; 
			calendar_params.displayField = params.displayField; // for showing the resulting date

			// make a calendar
			if(calendar_params.zip_availability > 0){
		 	    var new_cal = Calendar.productPageSetup(calendar_params);
			}else{
			    calendar_params.loading_className = "loading_msg_zipError";
			    var new_cal = Calendar.unavailableSetup(calendar_params);
			}
			//now that we have our actual reference to our calendar object
			//then we will properly set the calendar to open.
			setCalendarOpen(params,new_cal);
	
			//save our request for later use
			saveRequest(req,params); //should we see if it is already saved??
		}
	}

 /* get the vars */
	var product_id;
    var master_product_id = "";
	    if (document.getElementById("master").value == 1)
		{
          product_id = get_subcode_value("");  //document.zipform.subcode.value;
          master_product_id = document.getElementById(params.productField).value;
        } else {
           product_id = document.getElementById(params.productField).value;
        }
	params.product_id=product_id;
    var zip_code = document.getElementById(params.zipField).value;
		
    var product_price = document.getElementById(params.priceField).value;
	var saved_req = getSavedRequest(params);
	if(saved_req)
	{//if we have a saved request then just do
		 //that will be the same as if we went to the 
		 //server e.g. same zip and product id
		 //our ajax callback and don't bother going to the server
		 ajaxCallBack(saved_req);
	} else {
		// do AJAX call
		request = "/" + markcode + "/json/delivery_data.epl?&zip_code="+zip_code+"&product_id="+product_id+"&product_price="+product_price+"&master_product_id="+master_product_id+"&rand="+Math.round((Math.random()*999999)+1);
		request += FS.add_fs_params();
		/*
		var _doIt = function (){
		 ajaxLoader(request, ajaxCallBack);
		};
		//Just trying to slow things down
		//window.setTimeout(_doIt,5000);
		*/
		ajaxLoader(request, ajaxCallBack);
   }
}

/*  This is called on the product page to show the calendar for
international products.  There isn't that much difference from the
regular products but we don't have a zip code 
and we do have a country id
*/
function showInternationalProductCalendar(params)
{

/* incase you click on the link twice before it popups */
     if (isCalendarOpen(params)) {
        return;
    }
    //we don't have an actual reference to our calendar so just
    //send in 1 for the second param.  This way if the user
    //quickly clicks the button then we won't open 2 calendars at once
//setCalendarOpen(params,1);
//call the loadCalendar setup.  Which will return a reference to
//our loading calendar object which we will add to params
//so we can close it within calendar.js
var loadingCal = Calendar.loadingSetup(params);
    params.loading_calendar = loadingCal;
//if the calendar pops up over the input field while they have focus
//on the field then the cursor peeks through into the calendar.
//so we will shift focus off the input field
document.getElementById("display_" + params.inputFieldID).blur();

//build our ajax call back to get all our dates
	var ajaxCallBack = function (req) {
		if (req.readyState == 4 && req.status == 200) {
			// process the parameters	
			var calendar_params = buildCalendarParamsFromAjax(req.responseText);	
			   /* only copy values into the calendar object
               that has not been set by the ajax call back */
               for (i in params)
                if (typeof calendar_params[i] == "undefined")
                    calendar_params[i] = params[i];
			/* setup the other params form the input 
			 */
			calendar_params.inputField = params.inputField;
			calendar_params.hiddenLayer = params.hiddenLayer;
			calendar_params.button = params.button || params.triggerName; 
			calendar_params.displayField = params.displayField; // for showing the resulting date

			// make a calendar
		 	var new_cal = Calendar.productPageSetup(calendar_params);
			//now that we have our actual reference to our calendar object
			//then we will properly set the calendar to open.
			setCalendarOpen(params,new_cal);
			//save our request for later use
			saveRequest(req,params); //should we see if it is already saved??
		}
	}

 /* get the vars */
	var product_id;
    var master_product_id = "";
	    if (document.getElementById("master").value == 1)
		{
          product_id = get_subcode_value("");  //document.zipform.subcode.value;
          master_product_id = document.getElementById(params.productField).value;
        } else {
           product_id = document.getElementById(params.productField).value;
        }

    var country_id = params.country_id;
    var product_price = document.getElementById(params.priceField).value;
	var saved_req = getSavedRequest(params);
	if(saved_req)
	{//if we have a saved request then just do
		 //that will be the same as if we went to the 
		 //server e.g. same zip and product id
		 //our ajax callback and don't bother going to the server
		 ajaxCallBack(saved_req);
	} else {
		// do AJAX call
		request = "/" + markcode + "/json/delivery_data.epl?&country_id="+country_id+"&product_id="+product_id+"&product_price="+product_price+"&master_product_id="+master_product_id+"&rand="+Math.round((Math.random()*999999)+1)+"&pp=1";
		request += FS.add_fs_params();
		ajaxLoader(request, ajaxCallBack);
   }
}

/* This is for the onclick of the Edit Selection in the Shopping cart for
regular Products.  params is an object of all our calendar
switches and callback functions.  This will be passed around to all the
functions.  You can update it as you go along.
*/
function showScartRegularCalendar(params)
{
    /* incase you click on the link twice before it popups */
     if (isCalendarOpen(params)) {
        return;
    }
	//we don't have an actual reference to our calendar so just
	//send in 1 for the second param.  This way if the user
	//quickly clicks the button then we won't open 2 calendars at once
	setCalendarOpen(params,1);


	//call the loadCalendar setup.  Which will return a reference to 
	//our loading calendar object which we will add to params
	//so we can close it within calendar.js
	var loadingCal = Calendar.loadingSetup(params);
	params.loading_calendar = loadingCal;


	//build our ajax call back to get all our dates
	var ajaxCallBack = function (req) {
		if (!req) return false;
		if (req.readyState == 4 && req.status == 200) {
			// process the parameters	
			var calendar_params = buildCalendarParamsFromAjax(req.responseText);	
			   /* only copy values into the calendar object
               that has not been set by the ajax call back */
               for (i in params)
                if (typeof calendar_params[i] == "undefined")
                    calendar_params[i] = params[i];

			/* setup the other params form the input 
			 */
			calendar_params.inputField = params.inputField;
			calendar_params.hiddenLayer = params.hiddenLayer;
			calendar_params.button = params.button || params.triggerName; 
			calendar_params.flat = params.flat || params.flatID;  // odd
			calendar_params.position = new Array(0,0);
			calendar_params.displayField = params.displayField; // for showing the resulting date

			// make a calendar
			if(calendar_params.zip_availability > 0){
		 	    var new_cal = Calendar.scartRegularSetup(calendar_params);
			}else{
			    calendar_params.loading_className = "loading_msg_zipError";
			    var new_cal = Calendar.unavailableSetup(calendar_params);
			}
			//now that we have our actual reference to our calendar object
			//then we will properly set the calendar to open.
			setCalendarOpen(params,new_cal);
			//save our request for later use
			saveRequest(req,params); //should we see if it is already saved??
			
		}
	}

	/* get the vars */
	var product_id;
    var master_product_id = "";

	if (document.getElementById("item"+params.cart_entry_num+"_master").value == 1) {
		product_id = get_subcode_value("_"+params.cart_entry_id);  //document.zipform.subcode.value;
		master_product_id = document.getElementById(params.productField).value;
	} else {
	    product_id = document.getElementById(params.productField).value;
	}

	var zip_code = document.getElementById(params.zipField).value;
    var product_price = document.getElementById(params.priceField).value;

	var saved_req = getSavedRequest(params);
	if(saved_req) {
		//If we have a saved request then just do
		//that will be the same as if we went to the 
		//server e.g. same zip and product id
		//our ajax callback and don't bother going to the server
		ajaxCallBack(saved_req);

	} else {
		// do AJAX call
		request = "/" + markcode + "/json/delivery_data.epl?zip_code="+zip_code+"&product_id="+product_id+"&product_price="+product_price+"&long_form_date_range=1&master_product_id="+master_product_id+"&rand="+Math.round((Math.random()*999999)+1);
		request += FS.add_fs_params();
		ajaxLoader(request, ajaxCallBack);
   }
}




/* 
	This is the onClick action for the Shopping Cart International Product 
*/

function showScartInternationalCalendar(params) {

	/* get the vars */
	var product_id = document.getElementById(params.productField).value;
	var product_price = document.getElementById(params.priceField).value;
	var country_id = params.country_id;

	/* incase you click on the link twice before it popups */
	if (isCalendarOpen(params)) {
		return;
	}

//we don't have an actual reference to our calendar so just
//send in 1 for the second param.  This way if the user
//quickly clicks the button then we won't open 2 calendars at once
setCalendarOpen(params,1);

	/* 
		call the loadCalendar setup.  Which will return a reference to
		our loading calendar object which we will add to params
		so we can close it within calendar.js
	*/
	var loadingCal = Calendar.loadingSetup(params);
    params.loading_calendar = loadingCal;


	/* this is the ajax call back that creates the calendar */
	var ajaxCallBack = function (req) {
		if (req.readyState == 4 && req.status == 200) {
			//alert("ajaxCallBack got a result");
			// process the parameters	
			var calendar_params = buildCalendarParamsFromAjax(req.responseText);	

			/* only copy values into the calendar object
			   that has not been set by the ajax call back */
			for (i in params) 
				if (typeof calendar_params[i] == "undefined") 
					calendar_params[i] = params[i];

			/* setup the other params form the input */
			calendar_params.button = params.button || params.triggerName; 
			calendar_params.flat = params.flat || params.flatID;  // odd

			// make a calendar
			var new_cal = Calendar.scartInternationalSetup(calendar_params);
			//now that we have our actual reference to our calendar object
            //then we will properly set the calendar to open.
			setCalendarOpen(calendar_params,new_cal);
			//save our request for later use
			saveRequest(req,params); //should we see if it is already saved??
		}
	}

	/*
		if we have a saved request then just do
		our ajax callback and don't bother going to the server
	*/
	var saved_req = getSavedRequest(params);
	if (saved_req) 
		ajaxCallBack(saved_req);
    else {
		// do AJAX call
		var request = "/" + markcode + "/json/delivery_data.epl?long_form_date_range=1&country_id="+country_id+"&product_id="+product_id+"&product_price="+product_price;
		request += FS.add_fs_params();
		ajaxLoader(request, ajaxCallBack);
	}
}




function showMyaccountCalendar(params) {

	/* incase you click on the link twice before it popups */
	if (isCalendarOpen(params)) {
		return;
	}

	//we don't have an actual reference to our calendar so just
	//send in 1 for the second param.  This way if the user
	//quickly clicks the button then we won't open 2 calendars at once
	setCalendarOpen(params,1);

	/* 
		call the loadCalendar setup.  Which will return a reference to
		our loading calendar object which we will add to params
		so we can close it within calendar.js
	*/
	var loadingCal = Calendar.loadingSetup(params);
    params.loading_calendar = loadingCal;


	// make a calendar
	var new_cal = Calendar.myaccountSetup(params);
	//now that we have our actual reference to our calendar object
	//then we will properly set the calendar to open.
	setCalendarOpen(params,new_cal);
}

function showHomepageCalendar(params) {
        /* incase you click on the link twice before it popups */
        if (isCalendarOpen(params)) {
                return;
        }
        //we don't have an actual reference to our calendar so just send in 1 for the second param.  This way if the user quickly clicks the button then we won't open 2 calendars at once.

	setCalendarOpen(params,1);
        
	/* call the loadCalendar setup.  Which will return a reference to our loading calendar object which we will add to params. so we can close it within calendar.js */
	
	var loadingCal = Calendar.loadingSetup(params);
	params.loading_calendar = loadingCal;
	
	/*
	dateStatusFunc:  returns false for any unavailable day, use to grey out the date

	dateIsSpecial allows us to mark specific dates as being *special*
	so this function is dynamic and actually changes with each callback
	it's used by ourDateStatusFunc
	*/
	var _dateIsSpecial = function (year, month, day) {
		if ( (year < params.startYear) || (year == params.startYear && month < params.startMonth) || (year == params.startYear && month == params.startMonth && day < params.startDay) ||
year > params.endYear || (year == params.endYear && month > params.endMonth) || (year == params.endYear && month == params.endMonth && day > params.endDay)
){
			return "date_unavailable";
		}
	
		return false;
	}
	
	var _ourDateStatusFunc = function (date, y, m, d) {
		m = m+1;
		var isSpecial = _dateIsSpecial(y, m, d);
		if (isSpecial){
			 return isSpecial;
		 }else{
			 return false; // other dates are enabled
		 }
 	}
	
	params.dateStatusFunc = _ourDateStatusFunc;
												            // make a calendar
        var new_cal = Calendar.homepageSetup(params);
        //now that we have our actual reference to our calendar object then we will properly set the calendar to open.
	setCalendarOpen(params,new_cal);
 }

/* this will validate the zip code before calling the show calendar
functions.  you pass in your calendar_params object same as all the 
other functions in this file.  You have to set the onValidZip param 
whatever function you want to be called after the zip is validated. 
Usually something like showScartRegularCalendar(params);

*/
function validateCalendarZip(zip_params) {
	var ieErrorTmp;
	var entry_id = zip_params.cart_entry_id;
	var entry_num = zip_params.cart_entry_num;
	var zipFormat = true;

	/* this DISABLES DEBUG alerts for the scope of this function */
	if (document.all && !window.opera) {
		ieErrorTmp = window.onerror;
		window.onerror = function () { return true }
	} /* debug alerts are re-enabled at the bottom of this function */

	var zip_code_submit = document.getElementById(zip_params.zipField).value;
    var product_id = document.getElementById(zip_params.productField).value;
	var deldate = document.getElementById(zip_params.inputField).value;
	
	// Should we do some basic checking here 
	// before we go to the server???
	if(!zip_code_submit) {
		closeOpenCalendar(zip_params);
		hideElement(zip_params.zipErrorID, 1);
		return;
	}
		
	// Check zip formatting
	var zipFormat = validateZip(zip_params.zipField);

	ajaxLoader(
		'/' + markcode + '/xml/zipdata.epl?zip='+zip_code_submit+'&product_id='+product_id+'&deldate='+deldate,
		function (req) {
			if (!req) return false;
			if (req.readyState != 4 || req.status != 200) return false;
			var city; var state; var zipcode; var country;
			var zip_availability = 1;

			if (req.responseXML && req.responseXML.documentElement) {
				city    = req.responseXML.documentElement.getAttribute('city');
				state   = req.responseXML.documentElement.getAttribute('state');
				zipcode = req.responseXML.documentElement.getAttribute('zipcode');

				// If no zipcode is returned, doesn't mean it's invalid.
				// We just might not have it in our database.
				if(zipFormat){
					zipcode = zip_code_submit;
				}
				
				// Only get zip_availability if product_id is set
				// Without product_id it will not be returned
				if(product_id){
					zip_availability = parseInt(req.responseXML.documentElement.getAttribute('zip_availability'));

					// Store zip error messages in zip params that way when passed to onValid function
					// we won't call ajax since we know an error exists
					zip_params.zip_availability = zip_availability;
					zip_params.zip_error_message = req.responseXML.documentElement.getAttribute('zip_error_message');
				}

				if ( (city && state && zipcode) || zipFormat ) {
					 
					// If zipcode is invalid for selected product, then do not change field values
					if(zip_availability){
						// Set country based on zipcode structure - kind of hacky but it'll do for now
						if ( zipcode && /\D/.test(zipcode) && zipcode.length < 6 ) {
							zipcode = zip_code_submit.toUpperCase();
							zip_code_submit = zipcode;
						}

						// Set country based on zipcode structure - kind of hacky but it'll do for now
						if (/\d/.test(zipcode) && zipcode.length < 6 ) {
							country = "US";
						} else {
							country = "CA";
						}
						
						if ( document.getElementById("item"+entry_num+"_STCITY") ) {
							// City now set to blank as requested by Ticket #74727
							// Only for US addresses where the state changes
							if(document.getElementById("item"+entry_num+"_STSTATE") && document.getElementById("item"+entry_num+"_STSTATE").value != state) {
								document.getElementById("item"+entry_num+"_STCITY").value = '';
							}
							
							if(document.getElementById("item"+entry_num+"_STCITY").innerHTML) {
							  document.getElementById("item"+entry_num+"_STCITY").innerHTML = city;
							}
						
						}
						selectOptionByValue("item"+entry_num+'_STSTATE', state);
			
						selectOptionByValue("item"+entry_num+'_STCNTRY', country);

						if ( document.getElementById("item"+entry_num+"_STZIP") )
							document.getElementById("item"+entry_num+"_STZIP").value = zipcode;
						if ( document.getElementById("item"+entry_num+"_state_area_deldate") )
							document.getElementById("item"+entry_num+"_state_area_deldate").innerHTML = state;
						if ( document.getElementById("item"+entry_num+"_zip_area_deldate") )
							document.getElementById("item"+entry_num+"_zip_area_deldate").innerHTML = zipcode + ' ';

					}

					hideElement(zip_params.zipErrorID, 0);

					if(typeof zip_params.onValidZip != "function")
					{// Just to make sure a onValidZip is passed in
						alert('You have to send in a function to call on a valid zip!');
					} else {
						zip_params.onValidZip(zip_params);
					}
				} //
				else { 
					closeOpenCalendar(zip_params);
					hideElement(zip_params.zipErrorID, 1);
				 
				}
						
			}//end if if responseXML
		}
	);
if (document.all && !window.opera) window.onerror = ieErrorTmp;
}


/* ****************************************************************************** */
//  Ftd contains the main functions:
//  Ftd.shipping
//  Ftd.product
var Ftd  = new Function ();
/* ****************************************************************************** */


/* ****************************************************************************** */
    Ftd.shipping  = new Function ();
/* ****************************************************************************** */
  
	Ftd.shipping.hide_zip_error	= function (calendar_params) {
		var cart_entry_id = calendar_params.cart_entry_id;
		var cart_entry_num = calendar_params.cart_entry_num;
		var zipField      = "item" + cart_entry_num + "_STZIP";
        
        // Do not do for international orders
        if(!calendar_params.country_id) {
		    document.getElementById(zipField).className = document.getElementById(zipField).className.replace("error_field","");
            document.getElementById("item" + cart_entry_num + "_STZIP_label").className = document.getElementById("item" + cart_entry_num + "_STZIP_label").className.replace("error_msg","");
        }
		

		hideElement("item" + cart_entry_num + "_zip_block_error",0);
		
	}

  
    // Checks zip availability on delivery form.
	// Regarless of availability, zipcode and state will be changed on all areas of delivery form.
	Ftd.shipping.updateSelectedZip = function (calendar_params) {
     
        // Do not update any zip for international orders
        if(calendar_params.country_id) {
            return 0;
        }

		var cart_entry_id = calendar_params.cart_entry_id;
		var cart_entry_num = calendar_params.cart_entry_num;
	    var productField  = calendar_params.productField;
		var deldate       = document.getElementById(calendar_params.inputField).value;
		var zipField      = "item" + cart_entry_num + "_STZIP";
		var zipcode       = document.getElementById(zipField).value;

		// Initially hide all existing zip errors
        Ftd.shipping.hide_zip_error(calendar_params);

		// Check zip formatting
		var zipFormat = validateZip(zipField);
		if(!zipFormat) { 
			display_zip_error("There is a problem with your zip code.");
			return;
		}
		

		// Change zip code fields in other areas of the form
		document.getElementById("item" + cart_entry_num + "_edit_STZIP").value = zipcode; 	
		document.getElementById("item" + cart_entry_num + "_zip_area_deldate").innerHTML = zipcode + ' ';

		var product_id;
		var master_product_id = "";
		if (document.getElementById("item" + cart_entry_num + "_master").value == 1) {
			product_id = get_subcode_value("");  //document.zipform.subcode.value;
			master_product_id = document.getElementById(productField).value;
		} else {
			product_id = document.getElementById(productField).value;
		}
	
        // Function to display zip error messages
		function display_zip_error(error_msg) {

			document.getElementById(zipField).className += " error_field";

			document.getElementById("item" + cart_entry_num + "_STZIP_label").className += " error_msg";
			
			// Display zip code error message
			var zip_block_error_msg = document.getElementById("item" + cart_entry_num + "_zip_block_error_msg");
			zip_block_error_msg.innerHTML = error_msg;
			hideElement("item" + cart_entry_num + "_zip_block_error",1);
		}

		// Function to hide zip error messages
        function hide_zip_error(){
			document.getElementById(zipField).className = document.getElementById(zipField).className.replace("error_field","");
			document.getElementById("item" + cart_entry_num + "_STZIP_label").className = document.getElementById("item" + cart_entry_num + "_STZIP_label").className.replace("error_msg","");
			hideElement("item" + cart_entry_num + "_zip_block_error",0);
		}

		//AJAX callback function, which will reset the defined parameters above with new calendar attributes
		function ajaxCallBack (req) {
			if (!req) return false;
			if (req.readyState != 4 || req.status != 200) return false;

			var city; var state; var zipcode; 
			
			var zip_availability  = 0; 
			var zip_error_message = "";

			if (req.responseXML && req.responseXML.documentElement) {
				city    = req.responseXML.documentElement.getAttribute('city');
				state   = req.responseXML.documentElement.getAttribute('state');
				zip = req.responseXML.documentElement.getAttribute('zipcode');
				
				// Change the state in other areas of the form
				document.getElementById("item" + cart_entry_num + "_state_area_deldate").innerHTML = state;
				//document.getElementById("item" + cart_entry_num + "_STSTATE_").value = state;
				document.getElementById("item"+cart_entry_num+"_STSTATE").value = state;
				
				// Only get zip_availability if product_id is set
				// Without product_id it will not be returned
				if(product_id){
					zip_availability  = parseInt(req.responseXML.documentElement.getAttribute('zip_availability'));
					zip_error_message = req.responseXML.documentElement.getAttribute('zip_error_message');
				}

				//Product not available for given zipcode.
				if(zip_availability == 0){
		            display_zip_error(zip_error_message);
				}
			}
		}


		// Do AJAX call
		request_state = '/' + markcode + '/xml/zipdata.epl?zip='+zipcode+'&product_id='+product_id+'&deldate='+deldate+'&rand='+Math.round((Math.random()*999999)+1);
		ajaxLoader(request_state, ajaxCallBack);

		// AJAX will return to function to set the above variables
    }



/* ****************************************************************************** */
    Ftd.product  = new Function ();
/* ****************************************************************************** */
	
/* ******************************************************************************* */
/*           73266 - Change request for Purchase Path phase 1 (68790)              */
/* ******************************************************************************* */
    Ftd.product.cfg = {}; // href for storing configuration key/value pairs
    Ftd.product.getValidClientZip = function (id) {
        if (!this.cfg) this.cfg = {};
        if (!this.cfg.local) this.cfg.local = {};
        if (!this.cfg.local.zip_elem) this.cfg.local.zip_elem = document.getElementById(id);
        return this.validateClientZipLocally(this.cfg.local.zip_elem.value);
    };
/* ****************************************************************************** */
    Ftd.product.zipFieldOnChangeHandler = function (zipElem, successFuncRef, errorFuncRef) {
        /* these are strictly here for developers and can be safely removed/replaced for production use */
        if (!zipElem)
            alert('You must supply Ftd.product.zipFieldOnChangeHandler() with'+"\n"
                +'an HTML INPUT element containing the client supplied zipcode.');
        if (!successFuncRef)
            alert('You must supply Ftd.product.zipFieldOnChangeHandler() with a successFuncRef');
        /* ******************************************************************************************** */
		//let the calendar know we are currently validing the zip
		calendar_params_product.validating_zip = true;
		var zip = this.getValidClientZip(zipElem.id);

        if (!zip || /[^A-Za-z\d\-\s]/.test(zip) ) {
            hideElement('zip_error', true);
            errorFuncRef(this.cfg);
            return false; // contains invalid chars
        }

        // ********************************************************
        // this is mostly superfluous until an action is defined
        // ********************************************************
        zip = zip.toUpperCase();
        zip = zip.replace(/[\W\_]/g, ''); // scrub non-alpha-num chars
        if (
            ( /^\d+$/.test(zip) && zip.length < 5 )
            || ( /[A-Za-z]/.test(zip) && zip.length < 6 )
        ) {
            errorFuncRef(this.cfg);
            return true; // correct format, but incomplete
        }
        // ********************************************************

        if ( this.validateClientZipLocally(zipElem.value) ) {
            //this.validateClientZipRemotely(zipElem.id, successFuncRef, errorFuncRef);
			this.cfg.local.valid_zip = zip;
			successFuncRef(this.cfg);
        } else {
            hideElement('zip_error', true);
            errorFuncRef(this.cfg);
            return false;
        }
    };
    Ftd.product.validateClientZipLocally = function (zip) {
        if (!zip || /[^A-Za-z\d\-\s]/.test(zip) ) // allows NNNNN-NNNN format
            return false; // contains invalid chars
        zip = zip.replace(/[\W\_]/g, ''); // scrub non-alpha-num chars
        if (zip.length < 5) return false; // maybe good, but too short
        zip = zip.toUpperCase();
        if ( /* validation spec */
            /^\d{5}$/.test( zip ) /* zip code */ // NNNNN-NNNN ?
            || /^[A-Z\d]{6}$/.test( zip ) /* postal code */
        ) return zip;
        else return false;
    };

    Ftd.product.validateClientZipRemotely = function (zipFieldId, successFuncRef, errorFuncRef) {
        /* these are strictly here for developers and can be safely removed/replaced for production use */
        if (!zipFieldId)
            alert('You must supply Ftd.product.validateClientZipRemotely() with a zipFieldId');
        if (!successFuncRef)
            alert('You must supply Ftd.product.validateClientZipRemotely() with a successFuncRef');
        /* ******************************************************************************************** */
        var zipCode = this.getValidClientZip(zipFieldId);
        var stored = new String ();
        if (this.cfg && this.cfg.local) {
            if (this.cfg.local.valid_zip)
                this.cfg.local.stored_zip = this.cfg.local.valid_zip;
            this.cfg.local.valid_zip = zipCode;
            if (this.cfg.local.stored_zip == zipCode) {
                hideElement('zip_error', false);
                successFuncRef(this.cfg);
                return false;
            }
        }
        ajaxLoader(
            '/xml/zipdata.epl?zip='+zipCode,
            function (req, cfg) {
                if (!req) return false;
                if (req.readyState != 4 || req.status != 200) return false;
                if (!cfg) cgf = {};
                if (!cfg.xml) cfg.xml = {}; /* href for remote data */
                if (!cfg.local) cgf.local = {};
                var city; var state; var zipcode;
                if (req.responseXML && req.responseXML.documentElement) {
                    city    = req.responseXML.documentElement.getAttribute('city');
                    state   = req.responseXML.documentElement.getAttribute('state');
                    zip = req.responseXML.documentElement.getAttribute('zipcode');
                    if (city && state && zip) {
                        cfg.xml.city = city;
                        cfg.xml.state = state;
                        cfg.xml.zip = zip;
                        hideElement('zip_error', false);
                        successFuncRef(cfg); /* gets prepopulated cfg array */
                    } else {
                        cfg.local.error = '! city && state && zip';
                        hideElement('zip_error', true);
                        if (errorFuncRef) errorFuncRef(cfg); /* no server data for valid client zip */
                    }
                } else { // this else{} block can be commented/removed for production use
                    cfg.local.error = '! (req.responseXML && req.responseXML.documentElement)';
                    if (errorFuncRef) errorFuncRef(cfg); /* client/server problems? */
                }
            },
            this.cfg // this get's passed as second arg to above function
        );
    };

    Ftd.product.getDeliveryDataRemotely = function (productId, zipCode, masterID, product_price, date, show_abbreviated_date_ranges, successFuncRef, errorFuncRef) {
        /* these are strictly here for developers and can be safely removed/replaced for production use */
        if (!productId)
            alert('You must supply Ftd.product.getDeliveryDataRemotely() with a productId');
        if (!zipCode)
            alert('You must supply Ftd.product.getDeliveryDataRemotely() with a zipCode');
        if (!successFuncRef)
            alert('You must supply Ftd.product.getDeliveryDataRemotely() with a successFuncRef');
        /* ******************************************************************************************** */
        if (!this.cfg) this.cfg = {};
        if (!this.cfg.local) this.cfg.local = {};
        if (
            this.cfg.local.product_id
            && this.cfg.local.product_id == productId
            && this.cfg.local.stored_zip
            && this.cfg.local.stored_zip == this.validateClientZipLocally(zipCode)
        ) {
            successFuncRef(this.cfg);
            return true;
        }
        this.cfg.local.product_id = productId;
		var res = getSavedRequest( {'product_id': productId, 'zip_code': zipCode } ) 
	
		var getDateDefaults =  function (req, cfg) {
			if (!req) return false;
			if (req.readyState != 4 || req.status != 200) return false;
			if (!cfg) cgf = {};
			if (!cfg.xml) cgf.xml = {};
			if (req.responseText) var jsonStr = req.responseText;
			if (jsonStr) {
				cfg.xml.delivery_data = eval( '('+ jsonStr +')' );
				saveRequest(req, {'product_id': productId, 'zip_code': zipCode});     
				Ftd.product.updateSelectedDate('product_id', 'product_price', 'STZIP', 'deldate_product', '', null, {'updateDeliveryDropdown': '1'}); 
				successFuncRef(cfg);
			} else {
				cfg.local.error = '! req.responseText (jsonStr)';
				if (errorFuncRef) errorFuncRef(cfg);
			}
		} 

		if (res) {
			//alert('debugging ticket #76046 - no AJAX call made'); 
			getDateDefaults(res,this.cfg); 	
		} else {
			//alert('debugging ticket #76046 - /json/delivery_data.epl?product_id='+productId+'&zip_code='+zipCode+'&master_product_id='+masterID+'&product_price='+product_price+'&date='+date+'&show_abbreviated_date_ranges='+show_abbreviated_date_ranges);
			ajaxLoader(
				'/' + markcode + '/json/delivery_data.epl?product_id='+productId+'&zip_code='+zipCode+'&master_product_id='+masterID+'&product_price='+product_price+'&date='+date+'&show_abbreviated_date_ranges='+show_abbreviated_date_ranges+'&rand='+Math.round((Math.random()*999999)+1)+'&counterror=1'+FS.add_fs_params(), getDateDefaults, this.cfg);
		}
	};



	Ftd.product.updateSelectedDate = function (productField, priceField, zipField, inputField, country_id , countError, extra_params) {
		if(extra_params == null) { extra_params = {}; }

        // Since serveral items on the product page call this function, lets keep track if it's called.
		if(Ftd.product.cfg.updateSelectedDateCalled) return;
        Ftd.product.cfg.updateSelectedDateCalled = 1;
		setTimeout("Ftd.product.cfg.updateSelectedDateCalled = 0",6000);

		calendar_params_product.validating_zip = true;

		if(zipField) { 
			if (!validateZip(zipField)) {
				hideElement("sameday_delivery_available", 0);
				hideElement("zip_error",1);
				//we don't want the calendar to be able to open
				//so set invalid zip to true;
				calendar_params_product.invalidZip = true;
				calendar_params_product.validating_zip = false;
				Ftd.product.cfg.updateSelectedDateCalled = 0;
				return;
			} 
		}
		
		// Hide error divs for user messaging, such as calendar loading and zip error 
		hideElement("zip_error",0);
		hideElement("zip_block_error",0);

		var product_id;
		var master_product_id = "";
		if (document.getElementById("master").value == 1) {
			product_id = get_subcode_value("");  //document.zipform.subcode.value;
			master_product_id = document.getElementById(productField).value;
		} else {
			product_id = document.getElementById(productField).value;
		}
		
		var dateField = document.getElementById(inputField);
		var displayField = document.getElementById("display_"+inputField);

		var res = getSavedRequest( {'product_id': product_id, 'zipField': zipField } )


		//AJAX callback function, which will reset the defined parameters above with new calendar attributes
		function showParameters (req) {
			if (req.readyState == 4 && req.status == 200) {
				var json = eval('(' + req.responseText + ')');

				var next_available_date     = json.next_available_date;
				var next_available_date_display = json.next_available_date_display;

				var dateField = document.getElementById(inputField);
				var displayField = document.getElementById("display_"+inputField);


				// Changing date field value according to AJAX call
				// If zip is invalid then don't change the values
				if(json.zip_availability > 0){
					// Reset the delivery date for old design
					// We do this in case the user chooses a new zip code.
					if(!document.getElementById("dropdown_"+inputField)){
						if (document.getElementsByName('radio_delivery_date')) { 
							var tmp = getCheckedValue(document.getElementsByName('radio_delivery_date'));
							if (!getCheckedValue(document.getElementsByName('radio_delivery_date'))) {
								dateField.value = next_available_date;
								displayField.value = next_available_date_display;
							}
						} else {
							dateField.value = next_available_date;
							displayField.value = next_available_date_display;
						}
					}

					if(Ftd.product.cfg.dropdown_count>0 && extra_params.updateDeliveryDropdown){
						var dropdown = Ftd.product.updateDeliveryDropdown(req, {'dropdown_field': "dropdown_"+inputField, 
							'display_fee':Ftd.product.cfg.display_dropdown_fee});
						// Set index to first available date
						if(dropdown){ 
						    if( dropdown.selectedIndex == 0 ){ dropdown.selectedIndex = 1; }
							dateField.value = dropdown.options[dropdown.selectedIndex].value;
							// Take care of date range, if the first date is part of one
						    var dropdownFirstDate = dropdown.options[dropdown.selectedIndex].value.split(":");	
							displayField.value = new Date(dropdownFirstDate[0]).print("%a %m/%d/%y");
							if((dropdownFirstDate[0] === json.today_date) && json.sdu_applied  && (dropdownFirstDate.length <=1))
								displayField.value = new Date(dropdownFirstDate[0]).print("Today %m/%d/%y");
						}
					}

					// Clear error_field class from zip field
					document.getElementById("STZIP").className = document.getElementById("STZIP").className.replace("error_field", "");

					if (document.getElementById("sameday_delivery_available")) {
						if(json.available_today) {
							hideElement('sameday_delivery_available', 1);
						} else {
							hideElement('sameday_delivery_available', 0);
						}
					}

					if (document.getElementById("display_deldate_product")) {
						if (json.has_date_ranges && document.getElementById("display_deldate_product")) {
							document.getElementById("display_deldate_product").style.width = "14em";
						} else {
							document.getElementById("display_deldate_product").style.width = "110px";
						}
					}

                    // Show the When Should It Arrive section and disable the STZIP section
					if(extra_params.zipFirst){
                        // Hide
						hideElement('prod_select_delivery_date', 0);
                        hideElement('prod_opts_usps_link', 0);

						// Show
				        hideElement('when_should_it_arrive', 1);
                                        var quickview_div = document.getElementById("quick_view");
                                        if( quickview_div && quickview_div.style.display == 'block'){
                                            document.getElementById('dropdown_deldate_product').removeAttribute('disabled');
                                        }
                        hideElement('prod_opts_edit_STZIP', 1);

			// Call to update the addons based on zipcode.
			var prodId = Addons.getSelectedProdId();
			var prodObj = vase_addon_cached.products[prodId];
			prodObj.sameday = json.sameday;
			prodObj.vendor = json.vendor;
			Addons.updateAddonsOnZipChange(prodObj.sameday);
			// end: update addons based on zipcode.
			
						// Disable the zip field
						if(zipField && document.getElementById(zipField)){
						    document.getElementById(zipField).className='STZIP_disabled';
							document.getElementById(zipField).readOnly=true;
						}
						buildBottomBar();
					}
					product_page_submit = 0;

				//Product not available for given zipcode.
				}else{
					// Display zip code error message
					var zip_block_error_msg = document.getElementById("zip_block_error_msg");
					zip_block_error_msg.innerHTML = json.zip_error_message;
					hideElement("zip_block_error",1);
					document.getElementById("STZIP").className += " error_field";

					if(Ftd.product.cfg.dropdown_count>0 && extra_params.updateDeliveryDropdown){
						Ftd.product.updateDeliveryDropdown(req, {'dropdown_field': "dropdown_"+inputField, 
							'zip_error':1});
					}

					// Clear date field value
					displayField.value = "";

					product_page_submit = 1;
				}

                     
				 saveRequest(req, {'product_id': product_id, 'zipField': zipField } );
				
				 //we want the calendar to be able to open
				 //so we will set our zip error to false for the calendar
				 //params.  Since we are on the product page we know that we only have
				 //one calendar_params object.
				 calendar_params_product.invalidZip = false;
				 calendar_params_product.validating_zip = false;
			}
			Ftd.product.cfg.updateSelectedDateCalled = 0;
		} // end showParameters


		if (res) {
			showParameters(res);
		} else {
			// do AJAX call
			Stamp = new Date();
			var timestamp = (Stamp.getYear()+1900)+"."+(Stamp.getMonth() + 1)+ "."+Stamp.getDate()+"."+Stamp.getHours() ;
			request = "/" + markcode + "/json/delivery_data.epl?country_id="+country_id +"&zip_code="+document.getElementById(zipField).value+"&product_id="+product_id+"&master_product_id="+master_product_id+"&product_price="+document.getElementById(priceField).value+"&date="+dateField.value+"&show_abbreviated_date_ranges=1&rand="+Math.round((Math.random()*999999)+1)+"&counterror="+countError+"&pp=1";
			request += FS.add_fs_params();
			ajaxLoader(request, showParameters);
			// AJAX will return to function to set the above variables
		}

        } // end Ftd.product.updateSelectedDate



    /* 
	  Builds the design2007 date drop down
	  Input: req from ajax call, dropParams
	  dropParams: dropdown_field, display_fee, zip_error 

	  Notes: Keep generic so it can be used on any page, not just the product page. Currently there is nothing that ties this function to the product page, it is only associated with the product namespace since this is where it is first used.

	*/
    Ftd.product.updateDeliveryDropdown = function(req, dropParams) {
    var dropdown = document.getElementById(dropParams.dropdown_field);
		    
	if(dropdown && req.responseText){
		// Remove all options
		for(var i=dropdown.length-1 ; i>=0 ; i--){
		    dropdown.remove(i);
		}

		// Add first drop down element
		var dropdown_option=document.createElement('option');
		if(dropParams.zip_error) dropdown_option.text = 'Invalid Zip Code';
		else dropdown_option.text='Select Date';
		try{ dropdown.add(dropdown_option,null); }
        // IE only
		catch(ex){ dropdown.add(dropdown_option); }	

		if(dropParams.zip_error) return;
		
		params = buildCalendarParamsFromAjax(req.responseText);
		if(params.dropdown_dates && params.today_date){
			var date = new Date(params.today_date);

			var success_count = 0;
			var fail_count = 0;
			var day_counter = date.getDate();
			var month_counter = date.getMonth()+1;
			var year_counter = date.getFullYear();
				
				
			// Go through params.footer one day at a time
			// Stop if we hit desired available dates or a certain number of unavailable dates
			while(success_count<Ftd.product.cfg.dropdown_count && fail_count<150){

            if(day_counter>31){
				day_counter = 1;
				month_counter++; 
			}
			if(month_counter>12){
				month_counter = 1;
				year_counter++;
			}
			
			// Setup the footer key
			var curr_day = day_counter;
			var curr_month = month_counter;
			if(curr_day<10) curr_day = '0'+ curr_day;
			if(curr_month<10) curr_month = '0'+ curr_month;
			var curr_date = year_counter + '/' + curr_month + '/' + curr_day;
				
			// Is the date available
			if(params.dropdown_dates[curr_date] != null){
				var fee = params.dropdown_dates[curr_date];	
				// Create the pretty date
				var pretty_date = new Date(curr_date);
			    
				// Create the option element
	            // Check for a date range
							var dropdown_value = curr_date;
							var dropdown_text = pretty_date.print("%b %e - %A");

							if((curr_date === params.today_date) && params.sdu_applied ){
								dropdown_text = pretty_date.print("%b %e - Today");
								if(!dropParams.display_fee)
									dropdown_text =  dropdown_text + " ($" + params.sameday_upcharge.toFixed(2) + " add'l)" ;
							}

							if(params.delDateRange[curr_date]){
							    var begin_date = params.delDateRange[curr_date].split(":")[0];
							    var end_date = params.delDateRange[curr_date].split(":")[1];

								// Last date in a range
								if(end_date == curr_date){
								    var pretty_begin_date = new Date(begin_date);
								    var pretty_end_date = new Date(end_date);
								    dropdown_text = pretty_begin_date.print("%b %e %a.")+" to "+pretty_end_date.print("%b %e %a."); 
								    dropdown_value = params.delDateRange[curr_date];
							    // First or middle date in a range
								}else{
								    dropdown_text = "";
								}
							}

							if(dropdown_text){
								// Add fee 
								if(dropParams.display_fee) dropdown_text =  dropdown_text + " - $" + fee;
								
								dropdown_option=document.createElement('option');
								dropdown_option.value= dropdown_value;
								dropdown_option.text= dropdown_text;
								try{ dropdown.add(dropdown_option,null); }
								// IE only
								catch(ex){ dropdown.add(dropdown_option); }	
							
							    success_count++;
							}

						}else{
						    fail_count++;
						}

						day_counter++;
					}
					
				} // end if params.footer


				// Add last drop down element
				var dropdown_option=document.createElement('option');
				dropdown_option.text='view more delivery dates';
				dropdown_option.value='showCal';
				try{ dropdown.add(dropdown_option,null); }
                // IE only
				catch(ex){ dropdown.add(dropdown_option); }	

				// Set the selected date to default
				dropdown.selectedIndex=0;
				if( getBrowserTypeNew() == "Opera") {
				    dropdown.size = success_count + 2;
				    dropdown.length = success_count + 2;
				}

				/* Changes for the defect #10010. Prefill the delivery date selected from Zip Finder. */
				var quickview_div = document.getElementById("quick_view");
				if( quickview_div && quickview_div.style.display == 'block'){
					var ck = QV.getCkData();
					if( ck ){
					if(params.delDateRange[ck.deliverydate]){
                                                QV.prefill_qv_date(dropdown, params.delDateRange[ck.deliverydate], 

params.dropdown_dates[dropdown_value], dropParams.display_fee);
                                        }else{
                                                QV.prefill_qv_date(dropdown, ck.deliverydate, params.dropdown_dates

[dropdown_value], dropParams.display_fee);
                                        }	
					}
				}
				/* end: changes for the defect #10010. */

				return dropdown;
	} // end if responseText
	} // end Ftd.product.updateDeliveryDropdown




        /* 
		  Builds the design2007 international date drop down
		  Input: dropParams
		  dropParams:  

		  Notes: Wrapper for updateDeliveryDropdown

		*/
		// params productField, priceField, zipField, inputField, country_id , countError, extra_params
        Ftd.product.updateInternationalDeliveryDropdown = function(productField, priceField, inputField, country_id, extra_params) {
            var product_price = document.getElementById(priceField).value;
			var master_product_id = "";
			if (document.getElementById("master").value == 1)
			{
			  product_id = get_subcode_value("");  //document.zipform.subcode.value;
			  master_product_id = document.getElementById(productField).value;
			} else {
			   product_id = document.getElementById(productField).value;
			}

			// Build our ajax call back to get all our dates
			var ajaxCallBack = function (req) {
				if (req.readyState == 4 && req.status == 200) {
					Ftd.product.updateDeliveryDropdown(req, {'dropdown_field': inputField, 
					'display_fee':Ftd.product.cfg.display_dropdown_fee});
				
				    // Show the dropdown
				    hideElement('delivery_date_dropdown',1);

					// Save our request for later use
					//saveRequest(req,params); //should we see if it is already saved??
				}
			}
			
			// Do AJAX call
			request = "/" + markcode + "/json/delivery_data.epl?&country_id="+country_id+"&product_id="+product_id+"&product_price="+product_price+"&master_product_id="+master_product_id+"&rand="+Math.round((Math.random()*999999)+1);
			request += FS.add_fs_params();
			ajaxLoader(request, ajaxCallBack);
		}





        /* 
		  Function to be called when the design2007 drop down is changed.

		*/
		Ftd.product.onchangeDeliveryDropdown = function(inputField,calendarDiv,extraParams) {
		    if(!extraParams) extraParams = {};
			var dropdown = document.getElementById("dropdown_"+inputField);
           
		    // Opting to use the calendar widget
			if(dropdown.options[dropdown.selectedIndex].value == "showCal" && calendarDiv){
				// Show calendar here
				hideElement(calendarDiv, 1);
				// Hide dropdown error
                hideElement('delivery_date_dropdown_error', 0);

                if(extraParams.international){
				    showInternationalProductCalendar(calendar_params_product);
				}else{
                    showProductCalendar(calendar_params_product);
				}
			}else if(dropdown.selectedIndex != 0){
			// Selecting a valid date using the drop down
				var dateField = document.getElementById(inputField);
				var displayField = document.getElementById("display_"+inputField);
				var selectedDate = dropdown.options[dropdown.selectedIndex].value;

				// Hide calendar here
				hideElement(calendarDiv, 0);
				// Hide dropdown error
				hideElement('delivery_date_dropdown_error', 0);

				if(selectedDate){
					dateField.value = selectedDate;
					// in case the date is actually a date range let's split it.
				        var dropdownFirstDate = dateField.value.split(":");	
					displayField.value = new Date(dropdownFirstDate[0]).print("%a %m/%d/%y");
					// depending on client's date as we do not have the response obj in this onchange event
					if( (dropdownFirstDate[0] ===  new Date().print("%Y/%m/%d")) && (dropdownFirstDate.length <=1))
						displayField.value = new Date(dropdownFirstDate[0]).print("Today %m/%d/%y");
				}
			}
		}
	

        /*
		  Called when user changes STZIP field 
		  Input: params.countryID, params.zipFirst 

		  Notes: 
		*/
		Ftd.product.onchangeSTZIP = function(e, params) {
		    Ftd.product.updateSelectedDate('product_id', 'product_price', 'STZIP', 'deldate_product', params.countryID, null, {'updateDeliveryDropdown':1, 'zipFirst':params.zipFirst});

            // Blur the field so this doesn't run twice
			var zip_field = document.getElementById('STZIP');
			zip_field.blur();

		}

        /*
		  Called when user presses key in STZIP field 
		  Input: 

		  Notes: 
		*/
		Ftd.product.keypressSTZIP = function(e, params) {
		    e = window.event ? window.event : e;
			
		    if(e.keyCode == 13){
		    	    /* Changes for the ticket #161865 */
			    if(e.preventDefault){
			         e.preventDefault();
			    }else{
			         e.returnValue=false;
			    }
			    /*end: changes for the ticket #161865 */
			    Ftd.product.onchangeSTZIP(e, params);
			}
		}


        /*
		  Allows user to edit the STZIP after being greyed out 
		  Input: 

		  Notes: 

		*/
        Ftd.product.editSTZIP = function() {
		    // Hide
                   var quickview_div = document.getElementById("quick_view");
                   if(!(quickview_div && quickview_div.style.display == 'block')){
		       hideElement('when_should_it_arrive',0);
                   }else{
                      document.getElementById('dropdown_deldate_product').setAttribute('disabled','disabled');
                      document.getElementById("dropdown_deldate_product").selectedIndex=0;
                   }
            hideElement('prod_opts_edit_STZIP', 0);
			hideElement('productPage_calendarWidget_and_radioButtons', 0);
			hideElement('delivery_date_dropdown_error', 0);

		    // Show
			hideElement('prod_select_delivery_date', 1);
            hideElement('prod_opts_usps_link', 1);

			// Enable the zip field
            var zip = document.getElementById('STZIP');
            if(zip){
			  zip.className='';
			  zip.readOnly=false;
            }
		}



        /*
		  Invoked when user clicks the Select Delivery Date button 
		  Input: 

		  Notes: 

		*/
		Ftd.product.selectDeliveryDate = function() {
		    if(!validateZip('STZIP')){ 
			    hideElement('zip_error',1); 
			    return false;
			}

			if(!Ftd.product.cfg.updateSelectedDateCalled){
				/* they buddy, you don't have $country_id here, not an embperl file */
			    Ftd.product.updateSelectedDate('product_id', 'product_price', 'STZIP', 'deldate_product', '$country_id', null, {'updateDeliveryDropdown':1, 'zipFirst':1});
			}
		}

        /*
		  Invoked when user clicks the Add to Cart button 
		  Input: 

		  Notes: 

		*/
		Ftd.product.addToCart = function(params) {
		    // Make sure dropdown has selected a date if calendar widget is not showing
		    if(params.calendarDiv && params.dropdown) {
			  var cal  = document.getElementById(params.calendarDiv);
			  var drop = document.getElementById(params.dropdown);
			  if(cal && drop && cal.style.display == 'none' && drop.selectedIndex == 0){
			      hideElement('delivery_date_dropdown_error', 1);
			      return false;
			  }
			}
			
		    window.document.zipform.AID.value = 'shopcart';
			return true;
		}




/* If you only want 1 calendar open at a time then this should be called
	before you show any loading calendars or do any ajax calls. 
	Send in your calendar_params object.
	It will return true if a calendar is already open.
	However, if a calendar is open for the inputField you are submitting
	for, then we will check to see if our zip codes match.  If the zip
	code for the currently open calendar is different than the 
	new calendar we are trying to open then we will close down
	the currently open calendar and return false to let you know
	that the calendar is no longer open so you can open the new 
	calendar
*/
function isCalendarOpen(params)
{

	if(typeof(calendars_open[params.inputFieldID]) == "undefined")
	{//we don't exist so open right away
	 return false;
	}
	
var new_zip = "";
	if(typeof(params.zipField) !="undefined")
	{
	 new_zip = document.getElementById(params.zipField).value;  //getting the zip value
	}
	//calendars_open contains a zipCode value
	if(new_zip == calendars_open[params.inputFieldID].zipCode)
	{//same zipcode so stay open
	 return true;
	}
//we are submitting a new zipcode so we should close down the 
//open cal and return false
closeOpenCalendar(params);

return false;
}

/* This is for closing down whatever calendar is currently open
   for the corresponding inputFieldID sent in via params object.
   we test to make sure anything is open and that we have a valid
   calendar object before we do anything so you don't have to 
   worry about calling this with the calendar already closed

*/
function closeOpenCalendar(params)
{
	if(typeof(calendars_open[params.inputFieldID]) != "undefined"  //make sure we have somthing 
	   && typeof(calendars_open[params.inputFieldID].calendar) == "object") 
	{//make sure we have a calendar object
	 //NOTE: should we call the calendar.callCloseHandler here??
	 //that way if any cleaning up needs to be done it can be done 
	 //in onClose of the calendar.
	 calendars_open[params.inputFieldID].calendar.hide();
	 calendars_open[params.inputFieldID].calendar.destroy();
	 //calendars_open[params.inputFieldID].calendar.callCloseHandler();

	 // Hide the background layer, also called in callCloseHandler
	 var background_layer = document.getElementById(calendars_open[params.inputFieldID].calendar.hiddenLayer);
	 background_layer.style.display = "none";
	}
calendars_open[params.inputFieldID] = undefined; //clearing out our array for this inputField
}

/* this will set our calendars_open array to let us know
	that our calendar is open for the corresponding inputFieldID
	sent in through our params object.  This should be called
	right away even before you have a valid calendar object
	open, just send in a 1 for the cal object.  We do this because
	we want to quickly set the calendar to open before any ajax calls.
	then once our ajax calls our complete we should call this function again
	but this time with a proper calendar object so we can properly
	close down later
	
*/
function setCalendarOpen(params,cal)
{
calendars_open[params.inputFieldID] = 1;  //quickly set to true in case we have a race condition
var open_cal = new Object;
open_cal.calendar = cal;

	if(typeof (params) != "undefined"  && typeof (params.zipField) != "undefined")
	{
		var zipFieldElem = document.getElementById(params.zipField);
	 if (zipFieldElem) open_cal.zipCode = zipFieldElem.value;	 
	}
	else if(typeof (params) != "undefined" && typeof (params.zipCode) != "undefined")
	{//we may not have a zipFied but we might have a zipCode
	 open_cal.zipCode = params.zipCode;
	}
	
calendars_open[params.inputFieldID] = open_cal;  //setting our calendar to open

}

//simple function to set our calendar closed.
//just in case in the future we want to do more when we close
function setCalendarClosed(cal)
{
calendars_open[cal.params.inputFieldID] = undefined;
}



