var Checkout = new Class({
	Extends: UltraCart,
	Implements: [Options,Events],
	options: {
		screenBrandingTheme: 'default',
		returnOnErrorUrl: 'http://www.flirtyaprons.com/error.html',
		secureHostName: null,
		items: [],
		allowedCountries: null,
		allowedStateProvinces: null,
		defaultCountry: null,
		defaultStateProvince: null,
		checkout: true
	},
	initialize: function(els, mid, options) {

		this.parent(mid,options);
		this.setOptions(options);
		
		// create an instance of modal for dialog boxes
		this.modal = new Modal();
		
		// if items from the catalog have been requested, get them
		this.items = (this.options.items.length > 0)?this.getItems(items):[];
		
		if(this.options.checkout) {
			
			// store user interface elements for later use
			this.ui = els;
			
			// if items from the catalog have been requested, get them
			this.items = (this.options.items.length > 0)?this.getItems(items):[];
			
			// print cart and customer data to the page
			this.printAddress();
			this.printShippingMethods();
			this.updateSession(); //Necessary to calculate shipping cost
			this.updateCart(); //Calculates the totals after the session's been updated
			this.printCart();
			this.printCreditCardTypes();
			this.printAdvertisingSources();
	
			// get the countries where shipping is allowed
			this.allowedCountries = (this.options.allowedCountries)?this.options.allowedCountries:this.getAllowedCountries();
			
			// print allowed countries
			if ($defined(this.ui.billToCountry)) this.printCountries(this.ui.billToCountry,this.session.billToCountry);
			if ($defined(this.ui.shipToCountry)) this.printCountries(this.ui.shipToCountry,this.session.shipToCountry);
			
			// Set the default country
			if (!this.session.billToCountry) this.session.billToCountry = this.options.defaultCountry;
			if (!this.session.shipToCountry) this.session.shipToCountry = this.options.defaultCountry;
			this.printAddress();
	
			// print allowed states
			if ($defined(this.ui.billToState)) this.ui.billToState = this.printStateProvinces(this.ui.billToState,this.session.billToCountry,this.session.billToState);
			if ($defined(this.ui.shipToState)) this.ui.shipToState = this.printStateProvinces(this.ui.shipToState,this.session.shipToCountry,this.session.shipToState);
			
			// when a customer changes the billTo country, update the billToState select box
			if (this.ui.billToCountry && this.ui.billToState) {
				this.ui.billToCountry.addEvent('change',function(e) {
					this.ui.billToState = this.printStateProvinces(this.ui.billToState,e.target.value,this.session.billToState);
				}.bind(this));
			}
	
			// when a customer changes the shipTo country, update the shipToState select box
			if (this.ui.shipToCountry && this.ui.shipToState) {
				this.ui.shipToCountry.addEvent('change',function(e) {
					this.ui.shipToState = this.printStateProvinces(this.ui.shipToState,e.target.value,this.session.shipToState);
				}.bind(this));
			}
		}
	},
	
	// return the Item object
	getLocalItem: function(itemId) {
		var item = null;
		for (i=0;i<this.items.length;i++) {
			if (this.items[i].itemId == itemId) {
				item = this.items[i];
				break;
			}
		}
		
		// item not found, try to retrieve the item from UltraCart
		if (!item) {
			var result = this.getItems([itemId]);
			if (result.length > 0) {
				item = result[0];
				this.items.push(item);
			}
		}

		// if we found the item, return the Item object
		if (item) {
			item.buyButton = this.getBuyButton(item);
			item.msrp = parseFloat(item.manufacturerSuggestedRetailPrice).toFixed(2);
			item.cost = parseFloat(item.cost).toFixed(2);
			return item;
		}
		
		// despite our best efforts, the item was not found
		// return an empty Item object
		return {
			'itemOid':0,
			'itemId':itemId,
			'description':'Not Available',
			'extendedDescription':'Not Available',
			'cost':'NA',
			'weight':{
				'uom':this.constant.measure.weight.imperial,
				'value':0
			},
			'length':{
				'uom':this.constant.measure.length.imperial,
				'value':0
			},
			'width':{
				'uom':this.constant.measure.length.imperial,
				'value':0
			},
			'height':{
				'uom':this.constant.measure.length.imperial,
				'value':0
			},
			'attributes':[],
			'multimedias':[],
			'options':[],
			'allowBackorder':false,
			'availableQuantity':0,
			'inStock':false,
			'inventoryTracked':false,
			'preorder':false,
			'minimumQuantity':0,
			'maximumQuantity':0
		}
	},
	
	//Return the cost of the item
	printItemCost: function(el,item) {
		var cost = item.cost;
		var msrp = item.msrp;
		var onSale = null; //declare the onSale variable
		if (msrp > cost) {onSale = true;} //is the item on sale?
		msrp += '';
		cost += '';
		if (!cost) {
			el.set('html','NA');
			return false;
		}
		cost = cost.split('.');
		cost = '<sup>$<\/sup>' + cost[0] + '<sup>'+ cost[1] + '<\/sup>';
		
		if (onSale) {
			msrp = msrp.split('.');
			msrp = '<span class=\'originalCost\'><sup>$<\/sup>' + msrp[0] + '<sup>'+ msrp[1] + '<\/sup><\/span>';
			cost = msrp + ' ' + cost;
		}
		
		el.set('html', cost);
	},

	// returns a buy button or "out of stock" message
	getBuyButton: function(item,qty) {
		
		// if it's not in stock and backorder isn't allowed, no buy button is needed
		if (!item.inStock && !item.allowBackorder) return new Element('span',{'text':'Out of Stock'});

		// create our "add to cart" button
		var addToCart = new Element('span',{
			'text':(item.inStock)?'Add to Cart':'Backorder',
			'class':(item.inStock)?'addToCart':'backorder',
			'events':{
				'click':function(e) {
					e.stop();

					// update the button to indicate processing
					var btn = e.target;
					btn.set('text','Please wait...').addClass('disabled');
						
					// post to UltraCart
					var errors = this.addItems([{
						'itemId':item.itemId,
						'quantity':(isNaN(qty))?1:qty,
						'options':($defined(item.options))?item.options:[]
					}]);
					
					// if there are errors, tell customers the item isn't available for purchase
					if(errors != null && errors.length > 0) {
						btn.set('text','Not Available');
						// display an error dialog box
						var el = new Element('div',{
							'class':'editItemDialog',
							'styles': {
									'display': 'block',
									'width': '420px'
							},
							'html': '<h2>' + item.description + "</h2><p>There's a problem with your selection:</p>"
						});
						el.adopt(new Element('div', {
							'class': 'Info',
							'html': errors
						}));
						el.adopt(new Element('a',{
							'text':'Continue Shopping',
							'class':'button',
							'href':'#',
							'events':{
								'click':function(e) {
									e.stop();
									this.modal.hide();
									return;
								}.bind(this)
							}
						}));
						this.modal.show(el);						
						return false;
					}
					
					// otherwise, allow people to continue shopping or checkout
					else {
						btn.set('text',(item.inStock)?'Sign Up':'Add to Waiting List');

						// display a confirmation dialog box
						var el = new Element('div',{
							'class':'editItemDialog',
							'styles': {
									'display': 'block',
									'width': '420px'
							},
							'html': '<h2>' + item.description + '</h2><p>Your selection has been added to the shopping cart. What would you like to do next?'
						});
						var ul = new Element('ul');
						var li = new Element('li');
						li.adopt(new Element('a',{
							'text':'Continue Shopping',
							'class':'button',
							'href':'#',
							'events':{
								'click':function(e) {
									e.stop();
									this.modal.hide();
									return;
								}.bind(this)
							}
						}));
						
						var lii = new Element('li');
						lii.adopt(new Element('a',{
							'text':'Checkout',
							'class':'button',
							'href':'/checkout.html'
						}));
						ul.adopt(li,lii);						
						el.adopt(ul);
						this.modal.show(el);
					}
					
					//Update the "items in cart"
					this.printCartItemsCount($('Checkout'));
					this.printCartItemsCount($$('.cartStatus'));
					
					// revert back to normal status
					btn.set('text','Add Another').removeClass('disabled');
					
					// if a modal window is open for options, close it
					//this.modal.hide();
				}.bind(this)
			}
		},this);

		// if there aren't any options, simply return the "add to cart" button
		if (item.options.length <= 0) return addToCart;

		// we're still here, so there must be options. create a button to open the options dialog
		var openDialog = new Element('span',{
			'text':(item.inStock)?'Add to Cart':'Backorder',
			'class':(item.inStock)?'addToCart':'backorder',
			'events':{
				'click':function(e) {
					e.stop();
					
					// create a dialog box
					var el = new Element('div',{'class':'editItemDialog'});
					var h1 = new Element('h1',{'text':item.description});
					
					var div = new Element('div',{'class':'LabelInput'});
					var label = new Element('label',{'for':'quantity','text':'Quantity'});
					var select = this.getQtyElement(item);
					
					select.addEvent('change', function(e) {
						// make sure the user entered a number
						qty = e.target.value;
					});
					
					div.adopt(label,select);
					
					// get form inputs for all the item options
					var options = this.getItemOptions(item);
					
					// add all our elements to the dialog box
					el.adopt(h1,div,options,addToCart);

					// display the item options in a modal dialog box
					this.modal.show(el);
					
					// after showing the dialog, reset the button text
					e.target.set('text','Add to Cart');
				}.bind(this)
			}
		},this);
		return openDialog;
	},
	
	//Turns any anchor tag in to an "add to cart" link
	createBuyLink: function(el,item,qty) {
		
		//attach the proper events to our link
		el.addEvent('click',function(e){
			e.preventDefault();
			
			// create a dialog box
			var dialog = new Element('div',{
					'class':'editItemDialog',
					'styles': {
							'display': 'block',
							'width': '420px'
					}
				});
			
			// post to UltraCart
			var errors = this.addItems([{
				'itemId':item.itemId,
				'quantity':(isNaN(qty))?1:qty,
				'options':($defined(item.options))?item.options:[]
			}]);
			
			// if there are errors, tell customers the item isn't available for purchase
			if(errors != null && errors.length > 0) {
				var description = new Element('h2',{'text':item.description});
				var content = new Element('p',{'text':"There's a problem with your selection:"});
				
				var errorDisplay = new Element('div', {
					'class': 'Info',
					'html': errors
				});			
				
				var continueShopping = new Element('a',{
					'text':'Continue Shopping',
					'href':'#',
					'events':{
						'click':function(e) {
							e.stop();
							this.modal.hide();
							return;
						}.bind(this)
					}
				});
				
				dialog.adopt(description,content,errorDisplay,continueShopping);
				
				this.modal.show(dialog);						
				return false;
			}
			
			// otherwise, allow people to continue shopping or checkout
			else {
				var confirmation = new Element ('div');
				var description = new Element('h2',{'text':item.description});
				var content = new Element('p',{'text':"Your selection has been added to the shopping cart. What would you like to do next?"});
				var ul = new Element('ul');
				var li = new Element('li');
				li.adopt(new Element('a',{
					'text':'Continue Shopping',
					'href':'#',
					'events':{
						'click':function(e) {
							e.stop();
							this.modal.hide();
							return;
						}.bind(this)
					}
				}));
				
				var lii = new Element('li');
				lii.adopt(new Element('a',{
					'text':'Checkout',
					'href':'/checkout.html'
				}));
				ul.adopt(li,lii);
				
				var confirmation = dialog.clone().adopt(confirmation,description,content,ul);
				console.log(confirmation);				
										
				
				this.modal.show(el);
			}
			
			
		});
	},
	
	//Return a select box for item quantity
	getQtyElement: function(item) {
		
		//Create a select box
		var select = new Element('select',{
			'id':'quantity',
			'styles': {
				'width':50
			},
			'events':{
			'change':function(e) {
				qty = e.target.value;
				}		
			}
		});		
		
		//Get the minim and maximum quantity
		var min = (item.minimumQuantity > 0)?item.minimumQuantity:1;
		if (!$defined(item.maximumQuantity) || isNaN(item.maximumQuantity) || item.maximumQuantity == '') {
			var max = 50;
		} else if (item.maximumQuantity < min) {
			var max = min;
		} else {
			var max = item.maximumQuantity;
		}
				
		for (i=min;i<=max;i++) {
			select.adopt(new Element('option',{'value':i,'text':i}));
		}
		
		return select;
				
	},
		
	// short cut to refresh the entire cart - does NOT refresh billing, shipping and payment
	printCart: function() {
		this.printItems();
		this.printTotals();
		this.printCoupons();
	},

	// display all the items in the cart
	printItems: function() {
		try {
			if(!$defined(this.session)) this.getCartInstance();
			if(!$defined(this.ui.items)) return false;
			
			this.ui.items.set('html','');
			this.ui.editItem = null; // in case the user clicks edit too quickly
			
			// if there aren't any items in the cart, display 'Your cart is empty'
			if (this.session.items.length <= 0) {
				var td = new Element('td',{
					'class':'emptyCart',
					'colspan':4,
					'text':'Your cart is empty'
				});
				var tr = new Element('tr');
				tr.adopt(td);
				this.ui.items.adopt(tr);
				return false;
			}
					
			// print the item list
			this.session.items.each(function(item,index) {
				var tr = new Element('tr',{'class':'item'});
				
				// "remove" and "edit" butons will appear in the "Actions" column
				var actions = new Element('td',{'class':'actions'});
				
				// when a user clicks remove, update ultracart and remove the table row from the UI
				var remove = new Element('span',{
					'class':'remove',
					'text':'remove',
					'events':{
						'click':function(e) {
							try {
								// remove the item from ultracart
								var errors = this.removeItem(item.itemId);
								if(errors != null && errors.length > 0) {
									this.logError(errors);
									return false;
								}
								
								// remove the item element from the page
								tr.set('tween', {
									'onComplete': function() {
										tr.destroy();
									}.bind(this)
								});
								tr.fade('out');

								this.printTotals();
							}
							catch(error) {
								this.logError(error);
							}
							
							// update ui.shoppingCart
							this.refreshCart();
							
						}.bind(this)
					}
				});
				actions.adopt(remove);

				if (item.options.length > 0) {
					// only display the "edit" link if we have editable options
					var ok = false;
					item.options.each(function(option,index) {
						switch (option.type) {
							case this.constant.inputType.single:
							case this.constant.inputType.multiline:
							case this.constant.inputType.dropDown:
							case this.constant.inputType.radio:
								ok = true;
								break;
							default:
								break;
						}
					}.bind(this));
					if (ok) {
						var edit = new Element('span',{
							'class':'edit',
							'text':'edit',
							'events':{
								'click': function(e) {
									var el = new Element('div',{'class':'editItemDialog'});
									var desc = new Element('h1',{'text':item.description});
	
									// create a button to save the option values and close the dialog box
									var save = new Element('span',{
										'class':'save',
										'text':'Update Item',
										'events': {
											'click':function(e) {
												var btn = e.target;
												btn.set('text','Saving...');
												btn.addClass('disabled');
												this.updateItems(this.session.items);
												this.printCart();
												this.modal.hide();
											}.bind(this)
										}
									},this);
									el.adopt(desc,this.getItemOptions(item),save);
	
									this.modal.show(el);
								}.bind(this)
							}
						},this);
						actions.adopt(edit);
					}
				}

				// description equates to the product name
				var description = new Element('td',{
					'class':'description',
					'html':'<p>'+item.description+'</p>'
				});
				
				//get the image thumbnail from UltraCart
				if (item.multimedias.length > 0) {
					var imgSrc = null;
					
					// if a thumbnail exists, get its source. Otherwise, request a thumbnail be created and grab the source.
					if (item.multimedias[0].thumbnails.length > 0) {
						imgSrc = item.multimedias[0].thumbnails[0].httpUrl;
					} else {
						imgSrc = this.getItemMultimediaThumbnail(item,item.multimedias[0],80,80);
						imgSrc = imgSrc.httpUrl;
					}
					
					if (imgSrc) {
						//lets make sure the image source is https://
						imgSrc = imgSrc.replace('http:','https:');
						
						var img = new Element('img',{
							'src' : imgSrc,
							'height' : '80',
							'width' : '80',
							'class' : 'thumbnail',
							'alt' : item.description
						});
						
						img.inject(description,'top');
					}
					
				}

				// display item options below product name 
				var dl = new Element('dl');
				item.options.each(function(option,index) {
					if (option.type == this.constant.inputType.hidden) return false;
					var dt = new Element('dt',{'text':option.label});
					var dd = new Element('dd');
					if ($chk(option.selectedValue)){
						dd.set('text',option.selectedValue);
					} else if (option.required) {
						dd.set({
							'class':'customerChoice required',
							'text':'click \'edit\' to select (required)'
						});
					} else {
						dd.set({
							'class':'customerChoice',
							'text':'click \'edit\' to select'
						});
					}
					
					dl.adopt(dt,dd);
				}.bind(this));
				description.adopt(dl);
				
				// update the cart when the user changes item quantities
				var qty = new Element('td',{
					'class':'quantity'
				});
				
				var input = this.getQtyElement(item);
				
				input.setSelected(item.quantity);
				
				input.addEvent('change', function(e) {
					// make sure the user entered a number
					var qty = parseInt(e.target.value);
					if (isNaN(qty)) {
						qty = (item.quantity > 0)?item.quantity:1;
					}
					e.target.value = qty;					
					this.session.items[index].quantity = qty;
					
					// update ui.shoppingCart
					this.refreshCart();
					
				}.bind(this));
				
				qty.adopt(input);
				
				// Figure out the Item Cost
				if (item.unitCost > item.unitCostWithDiscount) {
					var itemCost = '<span class="originalCost">' + (item.quantity * item.unitCost).toFixed(2) + '</span><br /><span>' + (item.quantity * item.unitCostWithDiscount).toFixed(2) + '</span>';
				}				
				else {
					var itemCost = '<span>' + (item.quantity * item.unitCost).toFixed(2) + '</span>';
				}
							
				// line item totals go in the "cost" column
				var cost = new Element('td',{
					'class':'cost',
					'html': itemCost
				});
				
				tr.adopt(actions,description,qty,cost);
				this.ui.items.adopt(tr);
			}.bind(this));
		} catch (error) {
			this.logError(error);
			return false;
		}
	},
	
	// when a user clicks on the "edit" button, display a dialog box immediately below the cart item with editable item attributes 
	getItemOptions: function(item) {
		var el = new Element('div',{'class':'itemOptions'});
		
		item.options.each(function(option) {
			el.adopt(this.getItemOption(option));
		},this);
		
		return el;
	},
	
	printCartItemsCount: function(el) {
		if (!$defined(this.session)) this.getCartInstance();
		var itemCount = 0;
		for (i=0;i<this.session.items.length;i++) {
			itemCount += this.session.items[i].quantity;
		};
		if (!el) return itemCount;

		var text = (itemCount > 0)?itemCount + ' items in cart':'Your cart is empty';
		el.set('text',text);
		return text;
	},
	
	refreshCart: function() {
		if (!$defined(this.session)) this.getCartInstance();

		(function() {						
			this.updateItems(this.session.items); // Update our items in Ultracart
			this.updateSession(); // Updating session to get the most current shipping costs
			this.printShippingMethods();
			this.updateCart(); //Calculates the totals after the session's been updated
			this.printCart();
			this.ui.shoppingCart.unspin();
		}.bind(this)).delay(500);
	},
	
	// print the appropriate input type for a single item option
	getItemOption: function(option) {
		var el;
		option.selectedValue = ($defined(option.selectedValue))?option.selectedValue:'';
		switch (option.type) {
			// create short text input for the item option
			case this.constant.inputType.single:
				el = new Element('div',{'class':'LabelInput'});
				var label = new Element('label',{'text':option.label});
				var input = new Element('input',{
					'type':'text',
					'value':option.selectedValue,
					'class':(option.required)?'required':'',
					'events': {
						'blur': function(e) {
							option.selectedValue = e.target.value;
						}.bind(this)
					}
				});
				el.adopt(label,input);
				break;
				
			// create textarea input for the item option
			case this.constant.inputType.multiline:
				el = new Element('div',{'class':'LabelInput'});
				var label = new Element('label',{'text':option.label});
				var input = new Element('textarea',{
					'text':(option.values.length > 0)?option.values[0].value:'',
					'value':option.selectedValue,
					'class':(option.required)?'required':'',
					'events': {
						'blur': function(e) {
							option.selectedValue = e.target.value;
						}
					}
				});
				el.adopt(label,input);
				break;
			
			// create select box input for the item option
			case this.constant.inputType.dropDown:
				el = new Element('div',{'class':'LabelInput'});
				var label = new Element('label',{'text':option.label});
				var input = new Element('select',{
					'class':(option.required)?'required':'',
					'events': {
						'blur': function(e) {
							option.selectedValue = e.target.value;
						}.bind(this)
					}
				});
				var html = '<option value="">Select One<\/option>';
				option.values.each(function(op,index){
					html += '<option value="'+op.value+'">'+op.value+'<\/option>';
				});
				
				input.set('html',html);
				input.setSelected(option.selectedValue);
				el.adopt(label,input);
				break;

			// create hidden input for the item option
			case this.constant.inputType.hidden:
				el = new Element('input',{type:'hidden',value:option.values[0].value});
				break;

			// create radio input for the item option
			case this.constant.inputType.radio:
				el = new Element('div',{'class':'radio'});
				
				// create a radio button for each allowed value
				option.values.each(function(radio,index){
					var div = new Element('div',{'class':'LabelInput'});
					var label = new Element('label',{'text':radio.value});
					var input = new Element('input',{
						'type':'radio',
						'name':'radio'+option.optionOid,
						'value':radio.value,
						'checked':(radio.value == option.selectedValue)?true:false,
						'events': {
							'change': function(e) {
								option.selectedValue = e.target.value;
							}.bind(this)
						}
					});
					input.inject(label,'top');
					div.adopt(label);
					el.adopt(div);
				}.bind(this));
				break;

			// create paragraph for the fixed item option
			case this.constant.inputType.fixed:
				el = new Element('p',{'text':option.selectedValue});
				break;

			// throw an error when we don't recognize the item option
			default:
				break;
		}
		return el;
	},
	
	// useful method for indicating that item options and quanities have changed, but we haven't posted the latest changes to UltraCart yet
	zeroTotals: function() {
		this.session.subtotal = 0;
		this.session.subtotalDiscount = 0;
		this.session.subtotalWithDiscount = 0;
		this.session.taxRate = 0;
		this.session.tax = 0;
		this.session.taxableSubtotal = 0;
		this.session.taxableSubtotalDiscount = 0;
		this.session.taxableSubtotalWithDiscount = 0;
		this.session.shippingHandling = 0;
		this.session.shippingHandlingDiscount = 0;
		this.session.shippingHandlingWithDicount = 0;
		this.session.giftCharge = 0;
		this.session.giftCartCertificateAmount = 0;
		this.session.giftWrapCost = 0;
		this.session.surcharge = 0;
		this.session.total = 0;
	},
	
	// print subtotal, tax, shipping/handling, etc. from session data
	printTotals: function(updateRequired) {
		if(!$defined(this.session)) this.session = this.getCartInstance();

		if (this.ui.subtotal) this.ui.subtotal.set('text',this.session.subtotal.toFixed(2));
		if (this.ui.subtotalDiscount) {
			if (this.session.subtotalDiscount > 0) {
				this.ui.subtotalDiscount.set('text',(-this.session.subtotalDiscount).toFixed(2));
			} else {
				this.ui.subtotalDiscount.set('text','0.00');
			}
		}
		if (this.ui.subtotalWithDiscount) this.ui.subtotalWithDiscount.set('text',this.session.subtotalWithDiscount.toFixed(2));
		if (this.ui.taxRate) this.ui.taxRate.set('text',this.session.taxRate);
		if (this.ui.tax) this.ui.tax.set('text',this.session.tax.toFixed(2));
		if (this.ui.taxableSubtotal) this.ui.taxableSubtotal.set('text',this.session.taxableSubtotal.toFixed(2));
		if (this.ui.taxableSubtotalDiscount) this.ui.taxableSubtotalDiscount.set('text',(-this.session.taxableSubtotalDiscount).toFixed(2));
		if (this.ui.taxableSubtotalWithDiscount) this.ui.taxableSubtotalWithDiscount.set('text',this.session.taxableSubtotalWithDiscount.toFixed(2));
		if (this.ui.shippingHandling) {
			if (!this.session.shippingMethod) {
				this.ui.shippingHandling.set('text','Pending');
			} else {
				this.ui.shippingHandling.set('text',this.session.shippingHandling.toFixed(2));
			}
		}	
		if (this.ui.shippingHandlingDiscount) this.ui.shippingHandlingDiscount.set('text',(-this.session.shippingHandlingDiscount).toFixed(2));
		if (this.ui.shippingHandlingWithDiscount) this.ui.shippingHandlingWithDiscount.set('text',this.session.shippingHandlingWithDiscount.toFixed(2));
		if (this.ui.giftCharge) this.ui.giftCharge.set('text',this.session.giftCharge.toFixed(2));
		if (this.ui.giftCertificateAmount) this.ui.giftCertificateAmount.set('text',(-this.session.giftCertificateAmount).toFixed(2));
		if (this.ui.giftWrapCost) this.ui.giftWrapCost.set('text',this.session.giftWrapCost.toFixed(2));
		if (this.ui.surcharge) this.ui.surcharge.set('text',this.session.surcharge.toFixed(2));
		if (this.ui.total) this.ui.total.set('text',(this.session.total).toFixed(2));
	},
	
	// print coupons
	printCoupons: function() {
		if (!$defined(this.ui.couponCodes)) return false;

		try {
			if(!$defined(this.session)) this.session = this.getCartInstance();
			this.ui.couponCodes.set('html','');
			if (this.session.coupons.length > 0) {
				var span;
				this.session.coupons.each(function(coupon,index) {
					span = new Element('span',{
						'class':'coupon',
						'text':coupon.couponCode,
						'title':'Click to remove from your order',
						'events':{
							'click':function(e) {
								this.removeCoupon(coupon.couponCode);
								this.updateSession();
								this.printCart();
							}.bind(this)
						}
					});
					this.ui.couponCodes.adopt(span);
				}.bind(this));
			}
		} catch (error) {
			this.logError(error);
		}
	},
	
	// apply a coupon to the cart or display an error
	validateCoupon: function(coupon) {
		if (!$defined(this.ui.couponMessage)) return false;

		var errors = this.applyCoupon(coupon);
		this.ui.couponMessage.empty();
		if(errors && errors.length > 0) {
			this.ui.couponMessage.set('class','error');
			errors.each(function(error,index) {
				this.ui.couponMessage.appendText(error);
			}.bind(this));
		} else {
			this.ui.couponMessage.set({
				'class':'success',
				'text':'Coupon applied'
			});
			this.updateSession();
			this.printCart();
		}
	},

	
	// apply gift certificate and update cart
	// we do this a little differently than coupons because there can only be 1 GC applied to an order
	printGiftCertificate: function(gc) {
		if (!$defined(this.ui.giftCertificateMessage)) return false;
		try {
			if(!$defined(this.session)) this.getCartInstance();
			this.ui.giftCertificateMessage.empty();

			// start by validating the gift certificate
			var errors = this.validateGiftCertificate(gc);
			if(errors && errors.length > 0 && this.ui.giftCertificateError) {
				this.ui.giftCertificateMessage.set('class','error');
				errors.each(function(error,index) {
					this.ui.giftCertificateMessage.appendText('text',error);
				}.bind(this));
				return false;
			}
			this.applyGiftCertificate(gc);
			this.updateSession();
			this.updateCart();
			this.printTotals();
			this.ui.giftCertificateMessage.set({
				'class':'success',
				'text':'Gift Certificate applied'
			});
		} catch (error) {
			this.logError(error);
		}
	},
	
	// update the "country" select box with a list of allowed countries
	// if an option exists for the country store in the session, preselect it
	printCountries: function(el,value) {
		// populate allowed countries
		var options;
		if ($defined(this.allowedCountries) && this.allowedCountries.length > 0) {
			options = '<option value="">Select One<\/option>';
			this.allowedCountries.each(function(country,index) {
				options += '<option value="' + country + '">' + country + '<\/option>';
			});
		} else {
			options = '<option value="">None Available<\/option>';
		}
		el.set('html',options);
		if ($defined(value)) el.setSelected(value);
	},
	
	// update the "state" select box with a list of country-specific states and provinces
	printStateProvinces: function(el,country,stateProvince) {
		var input;
		var result = this.getStateProvinceCodes(country);
		
		// if we have a list of allowed states, show a drop-down menu. Otherwise, show plain text input.
		if($defined(result) && result.length > 0) {
			input = new Element('select',{'id':el.id,'name':el.name,'class':el.get('class'),'title':el.get('title'),'disabled':el.disabled});
			var options = '<option value="">Select One<\/option>';
			result.each(function(state,index) {
				options += '<option value="' + state + '">' + this.unabbreviateStateProvinceCode(country,state) + '<\/option>';
			}.bind(this));
			input.set('html',options);
		} else {
			input = new Element('input',{'type':'text','class':el.get('class'),'title':el.get('title'),'id':el.id,'name':el.name,'value':stateProvince,'disabled':el.disabled});
		}
		input.replaces(el);
		input.setSelected(stateProvince);
		return input;
	},
	
	// populate the "credit card type" select box with a list of allowed credit cards
	printCreditCardTypes: function() {
		if($defined(this.ui.creditCardType) && this.session.creditCardTypes.length > 0) {
			var options = '<option value="">Select One<\/option>';
			this.session.creditCardTypes.each(function(creditCard,index) {
				options += '<option value="' + creditCard + '">' + creditCard + '<\/option>';
			}.bind(this));
			this.ui.creditCardType.set('html',options);
		}
	},

	// print the session billing and shipping address in the checkout form
	printAddress: function() {
		try {
			if(!$defined(this.session)) this.session = this.getCartInstance();
			
			// billing address
			if (this.ui.billToFirstName)			this.ui.billToFirstName.value		= this.session.billToFirstName;
			if (this.ui.billToLastName)				this.ui.billToLastName.value		= this.session.billToLastName;
			if (this.ui.billToTitle)				this.ui.billToTitle.value			= this.session.billToTitle;
			if (this.ui.billToCompany)				this.ui.billToCompany.value			= this.session.billToCompany;
			if (this.ui.billToAddress1)				this.ui.billToAddress1.value		= this.session.billToAddress1;
			if (this.ui.billToAddress2)				this.ui.billToAddress2.value		= this.session.billToAddress2;
			if (this.ui.billToCity)					this.ui.billToCity.value			= this.session.billToCity;
			if (this.ui.billToState)				this.ui.billToState.value			= this.session.billToState;
			if (this.ui.billToPostalCode)			this.ui.billToPostalCode.value		= this.session.billToPostalCode;
			if (this.ui.billToCountry)				this.ui.billToCountry.value			= this.session.billToCountry;
			if (this.ui.billToDayPhone)				this.ui.billToDayPhone.value 		= this.session.billToDayPhone;
			if (this.ui.billToEveningPhone) 		this.ui.billToEveningPhone.value 	= this.session.billToEveningPhone;
			if (this.ui.billToPhone)				this.ui.billToPhone.value			= this.session.billToPhone;

			// shipping address
			if (this.ui.shipToBillTo && this.ui.shipToBillTo.checked) {
				if (this.ui.shipToFirstName)		this.ui.shipToFirstName.value		= this.session.billToFirstName;
				if (this.ui.shipToLastName)			this.ui.shipToLastName.value		= this.session.billToLastName;
				if (this.ui.shipToTitle)			this.ui.shipToTitle.value			= this.session.billToTitle;
				if (this.ui.shipToCompany)			this.ui.shipToCompany.value			= this.session.billToCompany;
				if (this.ui.shipToAddress1)			this.ui.shipToAddress1.value		= this.session.billToAddress1;
				if (this.ui.shipToAddress2)			this.ui.shipToAddress2.value		= this.session.billToAddress2;
				if (this.ui.shipToCity)				this.ui.shipToCity.value			= this.session.billToCity;
				if (this.ui.shipToState)			this.ui.shipToState 				= this.printStateProvinces(this.ui.shipToState,this.session.billToCountry,this.session.billToState);
				if (this.ui.shipToPostalCode)		this.ui.shipToPostalCode.value		= this.session.billToPostalCode;
				if (this.ui.shipToCountry)			this.ui.shipToCountry.setSelected(this.session.billToCountry);
				if (this.ui.shipToPhone)			this.ui.shipToPhone.value			= this.session.billToDayPhone;

			} else {
				if (this.ui.shipToFirstName)		this.ui.shipToFirstName.value		= this.session.shipToFirstName;
				if (this.ui.shipToLastName)			this.ui.shipToLastName.value		= this.session.shipToLastName;
				if (this.ui.shipToTitle)			this.ui.shipToTitle.value			= this.session.shipToTitle;
				if (this.ui.shipToCompany)			this.ui.shipToCompany.value			= this.session.shipToCompany;
				if (this.ui.shipToAddress1)			this.ui.shipToAddress1.value		= this.session.shipToAddress1;
				if (this.ui.shipToAddress2)			this.ui.shipToAddress2.value		= this.session.shipToAddress2;
				if (this.ui.shipToCity)				this.ui.shipToCity.value			= this.session.shipToCity;
				if (this.ui.shipToState)			this.ui.shipToState					= this.printStateProvinces(this.ui.shipToState,this.session.shipToCountry,this.session.shipToState);
				if (this.ui.shipToPostalCode)		this.ui.shipToPostalCode.value		= this.session.shipToPostalCode;
				if (this.ui.shipToCountry)			this.ui.shipToCountry.setSelected(this.session.shipToCountry);
				if (this.ui.shipToPhone)			this.ui.shipToPhone.value			= this.session.shipToPhone;
			}
			
			// shipping type
			if (this.ui.shipToResidential) this.ui.shipToResidential.checked = (this.session.shipToResidential)?true:false;
			if (this.ui.shipToBusiness) this.ui.shipToBusiness.checked = (this.session.shipToResidential)?false:true;
			
			// email
			if (this.ui.email)						this.ui.email.value					= this.session.email;
			if (this.ui.mailingListOptIn)			this.ui.mailingListOptIn.checked	= this.session.mailingListOptIn;
			
			// special instructions
			if (this.ui.specialInstructions)		this.ui.specialInstructions.value	= this.session.specialInstructions;
			
			// gift wrapping
			if (this.ui.gift)						this.ui.gift.checked = (this.session.gift)?true:false;
			if (this.ui.giftMessage)				this.ui.giftMessage.value			= this.session.giftMessage;
			
			// advertising source
			if (this.ui.advertisingSource)			this.ui.advertisingSource.setSelected(this.session.advertisingSource);
			
			// shipping date
			if (this.ui.shipOnDate)					this.ui.shipOnDate.value 			= this.session.shipOnDate;
			
			// shipping method
			if (this.ui.shippingMethod)				this.ui.shippingMethod.setSelected(this.session.shippingMethod);
			
		} catch(error) {
			this.logError(error);
		}
	},
	
	//update the session with data from customer profile, then print the address
	loadCustomerProfile: function() {
		if(!$defined(this.session)) this.session = this.getCartInstance();
		
		if(!this.customer) this.customer = this.getCustomerProfile();
		
		if(this.customer) {
			if (this.customer.email) this.session.email = this.customer.email;
			if (this.customer.firstName) this.session.billToFirstName = this.customer.firstName;
			if (this.customer.lastName) this.session.billToLastName = this.customer.lastName;
			if (this.customer.title) this.session.billToTitle = this.customer.title;
			if (this.customer.company) this.session.billToCompany = this.customer.company;
			if (this.customer.address1) this.session.billToAddress1 = this.customer.address1;
			if (this.customer.address2) this.session.billToAddress2 = this.customer.address2;
			if (this.customer.city) this.session.billToCity = this.customer.city;
			if (this.customer.state) this.session.billToState = this.customer.state;
			if (this.customer.postalCode) this.session.billToPostalCode = this.customer.postalCode;
			if (this.customer.country) this.session.billToCountry  = this.customer.country;
			if (this.customer.dayPhone) this.session.billToDayPhone = this.customer.dayPhone;
			if (this.customer.eveningPhone) this.session.billToEveningPhone = this.customer.eveningPhone;
		}
		
		this.updateCart();
		
	},
	
	// update the session with user input for shipping, billing and payment 
	updateSession: function() {
		if(!$defined(this.session)) this.session = this.getCartInstance();
		
		// Make sure that shipOnDate and deliveryDate exist
		if (!$defined(this.session.shipOnDate)) this.session.shipOnDate = null;
		if (!$defined(this.session.deliveryDate)) this.session.deliveryDate = null;
		
		try {

			// shipping address
			if (this.ui.billToFirstName) this.session.billToFirstName = this.ui.billToFirstName.value;
			if (this.ui.billToLastName) this.session.billToLastName = this.ui.billToLastName.value;
			if (this.ui.billToTitle) this.session.billToTitle = this.ui.billToTitle.value;
			if (this.ui.billToCompany) this.session.billToCompany = this.ui.billToCompany.value;
			if (this.ui.billToAddress1) this.session.billToAddress1 = this.ui.billToAddress1.value;
			if (this.ui.billToAddress2) this.session.billToAddress2 = this.ui.billToAddress2.value;
			if (this.ui.billToCity) this.session.billToCity = this.ui.billToCity.value;
			if (this.ui.billToState) this.session.billToState = this.ui.billToState.value;
			if (this.ui.billToPostalCode) this.session.billToPostalCode = this.ui.billToPostalCode.value;
			if (this.ui.billToCountry) this.session.billToCountry = this.ui.billToCountry.value;
			if (this.ui.billToDayPhone) this.session.billToDayPhone = this.ui.billToDayPhone.value;
			if (this.ui.billToEveningPhone) this.session.billToEveningPhone = this.ui.billToEveningPhone.value;
			if (this.ui.billToPhone) this.session.billToPhone = this.ui.billToPhone.value;

			// billing address
			if ($defined(this.ui.shipToBillTo) && this.ui.shipToBillTo.checked) {

				this.session.shipToFirstName = this.session.billToFirstName;
				this.session.shipToLastName = this.session.billToLastName;
				this.session.shipToTitle = this.session.billToTitle
				this.session.shipToCompany = this.session.billToCompany;
				this.session.shipToAddress1 = this.session.billToAddress1;
				this.session.shipToAddress2 = this.session.billToAddress2;
				this.session.shipToCity = this.session.billToCity;
				this.session.shipToState = this.session.billToState;
				this.session.shipToPostalCode = this.session.billToPostalCode;
				this.session.shipToCountry = this.session.billToCountry;
				this.session.shipToDayPhone = this.session.billToDayPhone;
				this.session.shipToEveningPhone = this.session.billToEveningPhone;
				this.session.shipToPhone = this.session.billToDayPhone;
			} 
			else {

				if (this.ui.shipToFirstName) this.session.shipToFirstName = this.ui.shipToFirstName.value;
				if (this.ui.shipToLastName) this.session.shipToLastName = this.ui.shipToLastName.value;
				if (this.ui.shipToTitle) this.session.shipToTitle = this.ui.shipToTitle.value;
				if (this.ui.shipToCompany) this.session.shipToCompany = this.ui.shipToCompany.value;
				if (this.ui.shipToAddress1) this.session.shipToAddress1 = this.ui.shipToAddress1.value;
				if (this.ui.shipToAddress2) this.session.shipToAddress2 = this.ui.shipToAddress2.value;
				if (this.ui.shipToCity) this.session.shipToCity = this.ui.shipToCity.value;
				if (this.ui.shipToState) this.session.shipToState = this.ui.shipToState.value;
				if (this.ui.shipToPostalCode) this.session.shipToPostalCode = this.ui.shipToPostalCode.value;
				if (this.ui.shipToCountry) this.session.shipToCountry = this.ui.shipToCountry.value;
				if (this.ui.shipToDayPhone) this.session.shipToDayPhone = this.ui.shipToDayPhone.value;
				if (this.ui.shipToEveningPhone) this.session.shipToEveningPhone = this.ui.shipToEveningPhone.value;
				if (this.ui.shipToPhone) this.session.shipToPhone = this.ui.shipToPhone.value;
			}
			
			// shipping type
			if (this.ui.shipToResidential) this.session.shipToResidential = (this.ui.shipToResidential.checked)?true:false;
			
			// email
			if (this.ui.email) this.session.email = this.ui.email.value;
			if (this.ui.mailingListOptIn) this.session.mailingListOptIn = this.ui.mailingListOptIn.checked;

			// special instructions
			if (this.ui.specialInstructions) this.session.specialInstructions = this.ui.specialInstructions.value;
			
			// gift options
			if (this.ui.gift) this.session.gift = (this.ui.gift.checked)?true:false;
			if (this.ui.giftMessage) this.session.giftMessage = this.ui.giftMessage.value;
			
			// advertising source
			if (this.ui.advertisingSource) this.session.advertisingSource = this.ui.advertisingSource.value;
			
			// shipping method					
			if (this.ui.shippingMethod) this.session.shippingMethod = this.ui.shippingMethod.value;
			
			// now we need to get the shipping cost by looping through an array of shipping method objects
			if (this.session.shippingMethod) {
				var results = (this.shippingEstimates && this.shippingEstimates.length >= 1)?this.shippingEstimates:this.estimateShipping();
				results.each(function(method,index) {
					if (this.session.shippingMethod == method.name) this.session.shippingHandling = method.cost;					
				}.bind(this));
			}
			
			// shipping date		
			if (this.ui.shipOnDate)		{
				// Ultracart will generate an error if shipOnDate is a blank string. Make sure it's got a value, or null it out
				this.session.shipOnDate = (!$defined(this.ui.shipOnDate.value) || this.ui.shipOnDate.value == '')?null:this.ui.shipOnDate.value;				
				//* HACK * For some reason the value of shipOnDate is showing up as a string with value of 'undefined' or 'null'. Likely has something to do with datepicker.js
				if (this.session.shipOnDate == 'undefined' || this.session.shipOnDate == 'null') this.session.shipOnDate = null;
			}
			
			// payment method
			if (this.ui.creditCardType) this.session.creditCardType = this.ui.creditCardType.value;
			if (this.ui.creditCardNumber) this.session.creditCardNumber = this.ui.creditCardNumber.value;
			if (this.ui.creditCardExpirationMonth) this.session.creditCardExpirationMonth = parseInt(this.ui.creditCardExpirationMonth.value);
			if (this.ui.creditCardExpirationYear) this.session.creditCardExpirationYear = parseInt(this.ui.creditCardExpirationYear.value);
			if (this.ui.creditCardVerificationNumber) this.session.creditCardVerificationNumber = this.ui.creditCardVerificationNumber.value;
			
		} catch(error) {
			this.logError(error);
		}
	},
	
	// retrieves and prints advertising sources as select box options in this.ui.advertisingSource
	printAdvertisingSources: function() {
		if (!$defined(this.ui.advertisingSource)) return false;
		var results = this.getAdvertisingSources();
		if ($defined(results) && results.length > 0) {
			var options = '<option value="">Select One<\/option>';
			results.each(function(source,index) {
				options += '<option value="' + source + '">' + source + '<\/option>';
			}.bind(this));
			this.ui.advertisingSource.set('html',options);
			this.ui.advertisingSource.setSelected(this.session.advertisingSource);
		}
	},

	// print the shipping method and costs available for the current session shipping address
	printShippingMethods: function() {
		if (!$defined(this.ui.shippingMethod)) return false;
		
		if (!this.session.needShipping) {
			this.ui.shippingMethod.set('html','<option>None Required</option>');
			return;
		}

		try {
			this.ui.shippingMethod.set('html','');
			var ok = false;
			var results = (this.shippingEstimates && this.shippingEstimates.length >= 1)?this.shippingEstimates:this.estimateShipping();
			switch (results) {
				case null:
				case -1:
				case 0:
					this.ui.shippingMethod.set('html','<option>None available for this address</option>');
					return;
				case 1:
					this.session.shippingMethod = results[0].name;
					this.ui.shippingMethod.set('html','<option value="'+results[0].name+'">'+results[0].displayName + ', $' + results[0].cost + '</option>');
				default:
					var option = new Element('option',{'text':'Select One'});
					this.ui.shippingMethod.adopt(option);
					var cost = [];
					results.each(function(method,index) {
						var estimatedDelivery = '';
						if (method.estimatedDelivery != '') {
							estimatedDelivery = '(' + method.estimatedDelivery + ')';
						}
						option = new Element('option',{'value':method.name,'text':method.displayName + ', $' + method.cost + ' ' + estimatedDelivery});
						cost[index] = method.cost;
						if (this.session.shippingMethod == method.name) {
							ok = true;
							option.setProperty('selected','selected');
						}
						this.ui.shippingMethod.adopt(option);
					}.bind(this));

			}
			if (!ok) this.session.shippingMethod = null;
			
		}
		catch(error) {
			this.logError(error);
		}
	},
	
	// after validating the cart, print errors as an unordered list
	printCartErrors: function(errors) {
		if (!$defined(this.ui.cartErrors)) return false;
		if (errors.length <= 0) return false;
		
		this.ui.cartErrors.empty();
		var ul = new Element('ul');
		
		errors.each(function(error, index) {
			ul.adopt(new Element('li',{'html':error}));
		});
		this.ui.cartErrors.adopt(ul);
		this.ui.cartErrors.tween('height',ul.getSize().y);
	},
	
	// submit payment to ultracart
	submitPayment: function() {
		if (this.ui.submitPayment) this.ui.submitPayment.set('text','Please wait...').addClass('disabled');
		
		(function() {
			this.updateSession();
			this.updateCart();
			
			try {
				var result;
				
				switch (this.session.paymentMethod) {
					case this.constant.paymentMethod.payPal:
						if($defined(this.secureHostName)) {
							result = this.paypalHandoffOnCustomSSL(this.options.secureHostName, this.options.returnOnErrorUrl, 'error');
						} else {
							result = this.paypalHandoff(this.options.returnOnErrorUrl, 'error');
						}
						break;
					case this.constant.paymentMethod.purchaseOrder:
						return false;
						break;
					default:
						if($defined(this.secureHostName)) {
							result = this.checkoutHandoffOnCustomSSL(this.options.secureHostName, this.options.returnOnErrorUrl, 'error');
						} else {
							result = this.checkoutHandoff(this.options.returnOnErrorUrl, 'error');
						}
						break;	
				}
				
				if ($defined(result.errors) && result.errors.length == 0) {
					window.location = result.redirectToUrl;
				} else {
					this.printCartErrors(result.errors);
					if (this.ui.submitPayment) this.ui.submitPayment.set('text','Submit Payment').removeClass('disabled');
				}
			} 
			catch(error) {
				this.logError(error);
			}
		}.bind(this)).delay(500);	
	}
});

