/**
 * Cart Objects
 * 
 * Requires that a contextID be provided
 */




	/***************************************************************************
	 * Cart Object. 
	 * Contains all basic cart functionality (add/remove/transfer/save)
	 */
	var Cart = base2.Base.extend({
		constructor: function(options) {
			
			this.SetOptions(options);
			this.SetEvents();
			if (this.Options.AutoRefresh) {
				this.Refresh();
			}
		},
		
		Purchase: null,

		SetOptions: function(options) {
			this.Defaults = {
				APIAddToCart: GBPServiceUrl + "/{channelID}/cart/product",
				APIRemoveFromCart: GBPServiceUrl + "/{channelID}/cart/product/remove",
				//APIRemoveProductFromCart: GBPServiceUrl + "/{channelID}/cart/product/{orderGuid}/remove",
				APIRemoveProductFromCart: GBPServiceUrl + "/{channelID}/{contextID}/cart/{cartID}/product/{orderGuid}/remove",
				APIGetCart: GBPServiceUrl + "/" + contextID +"/cart/{cartID}",
				APISaveCart: GBPServiceUrl + "/" + contextID +"/cart/{cartID}/save",
				APIClearCart: GBPServiceUrl + "/" + contextID +"/cart",
				APITransferCart: GBPServiceUrl + "/{channelID}/cart/transfer",
				APITransferToWorkingCart: GBPServiceUrl + "/{channelID}/" + contextID +"/cart/{cartID}/transfer/{orderGuid}",
				APIClearWorkingCart: GBPServiceUrl + "/" + contextID +"/cart/working/clear",
				APICheckout: GBPServiceUrl + "/cart/checkout",
				CheckoutRedirectUrl: "Thankyou.aspx?o=%id%",
				Channel: GBPChannel,
				DateFormat: "yyyy/MM/dd",
				WorkingKey: "",
				AutoRefresh: true,
				CartID: 0
			}
			
			this.Options = jQuery.extend({}, this.Defaults, options);
		},
		
		HasCartID: function() {
			return (this.Options.CartID != 0);
		},
		
		SetEvents: function() {
			
			var cartObject = this;
			
			jQuery(".clearCart").click(function() {
			
				cartObject.Clear( );
				cartObject.Refresh();
				cartList.Refresh();
				cartErrorList.Refresh();
				cartCheckout.Update();
				
				return false;
			});
			
			jQuery("body").delegate(".btnSave", "click", function() {
				if (user != null) {
					cart.Save();
				} else {
					// Show login
					var loginPopup = jQuery("#btnLogin").find(".popup").addClass("popup-active").css({display: "block"})
					var anchorReference = loginPopup.parent().prev().find("a").addClass("active");
					loginPopup.animate({ opacity: 1});
					loginPopup.find("#loginEmail").focus();
					
					jQuery.scrollTo(jQuery(loginPopup), 800);
					
					
				}
				
				return false;
			});
			
			
		},
		
		/**
		 * Searches the Purchase object to see if a component with the specified
		 * details exists.
		 * Returns the component if found
		 * 
		 * @param {Object} productID
		 * @param {Object} salesConfigID
		 * @param {Object} date
		 */
		GetComponent: function(productID, salesConfigID, date) {
			var cartObject = this;
			var component = null;
			
			base2.Array2.forEach(this.Purchase.Products, function(product) {
				
				if (product.ProductCode == productID) {
					//Search the components
					base2.Array2.forEach(product.Components, function(component){
						
						if (component.SalesConfigurationID == salesConfigID) {
							var componentDate = Date.parse(component.ComponentDate).toString(cartObject.Options.DateFormat);
							var dateString = date.toString(cartObject.Options.DateFormat);
							if (componentDate == dateString) return component;
						}
						
					});
				}
			});
			
			return component;
		},
		
		
		/**
		 * Refreshes the Cart from the backend session object
		 */
		Refresh: function() {
			try {
				
				var url = this.Options.APIGetCart.replace("{cartID}", this.Options.CartID) + "?" + CacheBuster();
				
				var response = new APIHandler({
					Url: url,
					Method: APIMETHODS.GET
				}).Response;
				
				if (response.Result) {
					var purchase = response.Value;
					this.Purchase = purchase;
				}
				return response;
			} catch (exception) {
				ShowError("Error retrieving cart data: " + exception, "Cart");
				return false;
			}
		},
		
		Clear: function() {
			try {
				var response = new APIHandler({
					Url: this.Options.APIClearCart + "?" + CacheBuster(),
					Method: APIMETHODS.GET
				});
				
				if (response.Result) {
					var purchase = response.Value;
					this.Purchase = purchase;
				}
				
			} catch (exception) {
				ShowError("Error clearing Cart: " + exception, "Cart");
			}
		},
		
		ClearWorking: function() {
			try {
				var response = new APIHandler({
					Url: this.Options.APIClearWorkingCart + "?" + CacheBuster(),
					Method: APIMETHODS.GET,
					Async: true
				});
				
			} catch (exception) {
				ShowError("Error clearing Working Cart: " + exception, "Working Cart");
			}
		},
		
		/**
		 * Add the specified product to the cart.
		 * @param {Int} productID
		 * @param {Int} salesConfigID
		 * @param {Date} date
		 * @param {Criteria object Array} criteria
		 */
		Add: function(orderGuid, productID, salesConfigID, date, criteria, addonSalesConfigID, callback) {
			var cartObject =  this;
			try {
				var apiAddToCart = this.Options.APIAddToCart.replace("{channelID}", this.Options.Channel);
				var data = {
					OrderGuid: orderGuid,
					Context: contextID,
					ProductID: productID,
					SalesConfigurationID: salesConfigID,
					AddonSalesConfigurationID: addonSalesConfigID,
					SelectedDate: date,
					Criteria: criteria,
					WorkingKey: this.Options.WorkingKey
				}
				
				var response = new APIHandler({
					Url: apiAddToCart,
					Method: APIMETHODS.POST,
					Data: JSON.stringify(data),
					Async: true,
					Callback: function(response) {
						if (response.Result) {
							cartObject.Purchase = response.Value;
							if (callback != null) {
								callback(cartObject.Purchase);
							}
						} else {
							// Error
						}
					}

				}).Response;

			} catch (error) {
				ShowError("error adding product " + productID + " to cart:" + error);
			}
		},

		/**
		 * Remove the specified product to the cart.
		 * @param {Int} productID
		 * @param {Int} salesConfigID
		 * @param {Date} date
		 * @param {Criteria object Array} criteria
		 */
		Remove: function(component, productID, salesConfigID, date, criteria, callback) {
			var cartObject =  this;
			try {
				var apiRemoveFromCart = this.Options.APIRemoveFromCart.replace("{channelID}", this.Options.Channel);
				var data = {
					OrderGuid: component.OrderGuid,
					Context: contextID,
					ProductID: productID,
					SalesConfigurationID: salesConfigID,
					SelectedDate: date,
					Criteria: criteria,
					WorkingKey: this.Options.WorkingKey,
					AddOnOrderGuid: component.AddonOrderGuid
				}
				
				var response = new APIHandler({
					Url: apiRemoveFromCart,
					Method: APIMETHODS.POST,
					Data: JSON.stringify(data),
					Async: true,
					Callback: function(response) {
						if (response.Result) {
							cartObject.Purchase = response.Value;
							if (callback != null) {
								callback(cartObject.Purchase);
							}
						} else {
							// Error
						}
					}


				}).Response;
				
			} catch (error) {
				ShowError("error removing product " + productID + " component from cart:" + error);
			}
		},
		
		/**
		 * 
		 * @param {Object} orderGuid
		 * @param {Object} productID
		 * @param {Object} callback
		 */
		RemoveProduct: function(orderGuid, productID, callback) {
			var cartObject = this;
			
			try {
				
				var apiUrl = this.Options.APIRemoveProductFromCart.replace("{channelID}", this.Options.Channel)
				apiUrl = apiUrl.replace("{orderGuid}", orderGuid);
				apiUrl = apiUrl.replace("{contextID}", contextID);
				apiUrl = apiUrl.replace("{cartID}", this.Options.CartID);
				
				
				var response = new APIHandler({
					Url: apiUrl + "?" + CacheBuster(),
					Method: APIMETHODS.GET,
					Async: true,
					Callback: callback /*function(response) {
						if (response.Result) {
							cartObject.Purchase = response.Value;
							if (callback != null) {
								callback(cartObject.Purchase);
							}

						} else {
							// Error
							ShowError(response.Message, "Cart Error");
						}
					} */
				
				}).Response;
				
			} catch (exception) {
				ShowError("error removing product " + productID + " from cart: " + exception);
			}

		},

		/**
		 * Transfers the component of this cart to the main cart.
		 * @param {Object} cartDestination
		 * @param {Object} orderGuid
		 * @param {Object} criteria
		 * @param {Object} callback
		 */
		TransferTo: function(cartDestination, orderGuid, criteria, callback) {
			var url = this.Options.APITransferCart.replace("{channelID}", this.Options.Channel)

			var data = {
				OrderGuid: orderGuid,
				CartID: this.Options.CartID,
				AddOnly: !(orderGuid.length > 0),
				Criteria: criteria,
				Context: contextID
			}

			var response = new APIHandler({
				Url: url,
				Method: APIMETHODS.POST,
				Data: JSON.stringify(data),
				Async: true,
				Callback: function(response) {
					if (response.Result) {
						cartDestination.Refresh();
						if (callback != null) {
							callback(cartDestination.Purchase);
						}
					} else {
						// Error
						ShowError(response.Message, "Cart Error");
					}
				}
			});

		},

		/**
		 * Transfer the specified Product with orderGuid to a temporary cart in session
		 * @param {Object} orderGuid
		 * @return temporary Purchase object
		 */		
		TransferToWorking: function(orderGuid, callback) {
			var url = this.Options.APITransferToWorkingCart.replace("{channelID}", this.Options.Channel).replace("{orderGuid}", orderGuid);
			url = url.replace("{cartID}", this.Options.CartID);
			
			var response = new APIHandler({
				Url: url + "?" + CacheBuster(),
				Method: APIMETHODS.GET,
				Async: true,
				Callback: callback
			}).Response;

			return response;
		},
		
		/**
		 * Save the cart to the specified user.
		 * User MUST be logged in. 
		 * @param {Object} user
		 */
		Save: function() {

			if (!this.InSave) {
				//Set semaphore
				this.InSave = true;

				var url = this.Options.APISaveCart;
				url = url.replace("{cartID}", this.Options.CartID);

				var data = {
					Name: this.Purchase.Name
				}

				var response = new APIHandler({
					Url: url,
					Method: APIMETHODS.POST,
					Data: JSON.stringify(data),
					Async: true,
					Callback: jQuery.proxy(this.SaveHandler, this)
				}).Response;
			}
		},

		InSave: false,

		SaveHandler: function(response) {
			//Release semaphore
			this.InSave = false;

			if (response.Result) {
				var purchase = response.Value;
				//TODO: 
				window.location.href = "cart.aspx?id=" + purchase.RemoteOrderNumber;
				//Notify("Cart Saved", "Cart");
			} else {
				ShowError("Saving Cart: " + response.Message);
			}
		},

		// Recalculate the cart object.
		Recalculate: function() {

		},


		// Determine if this purchase cart can be checked out.
		CanCheckout: function() {
			return (this.Purchase.IsValid);
		},

		// checkout the purchase cart with specified user details and credit card
		Checkout: function(user, card) {
			var url = this.Options.APICheckout;
			var data = {
				CreditCardDetails: card,
				ChannelID: "PT",
				Context: contextID,
				FirstName: user.FirstName,
				LastName: user.LastName,
				Email: user.Email,
				Country: user.Country,
				City: user.City,
				Phone: user.Phone,
				DateOfBirth: user.DateOfBirth,
				Terms: true,
				CartID: this.Purchase.RemoteOrderNumber
			}

			var response = new APIHandler({
				Url: url,
				Method: APIMETHODS.POST,
				Data: JSON.stringify(data),
				Async: true,
				Callback: jQuery.proxy(this.CheckoutHandler, this)
			}).Response;
		},


		CheckoutHandler: function(response) {

			if (response.Value.Success) {

				// Redirect to the thankyou/summary url specified in options
				var redirectUrl = this.Options.CheckoutRedirectUrl.replace("%id%", response.Value.Purchase.RemoteOrderNumber);
				window.location = redirectUrl;
				//window.location = this.Options.CheckoutRedirectUrl;

			} else {
				Notify(response.Message, "Checkout Error");
			}
			
			HideOverlay();

		}	

	});




	/**
	 * Object to control the rendering of the products in a cart.
	 * Binds relevant events to the items
	 * @param {Object} options
	 */
	var CartProductList = base2.Base.extend({
		constructor: function(options) {
			this.SetOptions(options);
			this.SetEvents();
		},

		Element: null,


		/**
		 * Cart to Render
		 * @param {Object} options
		 */
		Cart: null,

		Container: null,
		
		SetOptions: function(options) {
			this.Defaults = {
				APIAddToCart: GBPServiceUrl + "/{channelID}/cart/product",
				APIRemoveFromCart: GBPServiceUrl + "/{channelID}/cart/product/remove",
				APIGetCart: GBPServiceUrl + "/cart",
				APIClearCart: GBPServiceUrl + "/cart/clear",
				Channel: GBPChannel,
				DateFormat: "dddd d MMMM yyyy",
				Container: "#plan .locations",
				TotalPriceElement: "#TotalAmount",
				CheckOutElement: "#btnBook",
				DatesContainer: "#CartDates",
				ErrorContainer: "#plan .notifications",
				ItemTemplate: "templates/gbp_cart_item.html",
				NameContainer: "#plan h2.name",
				DateAberation: -2
			}
			
			this.Options = jQuery.extend({}, this.Defaults, options);
			
			this.Container = jQuery(this.Options.Container);
		},
		
		SetEvents: function() {
			var container = this.Container;
			var object = this;
			
			//** Make Changes **/
			jQuery(this.Options.Container).delegate(".change","click", function() {
				var trigger = jQuery(this);
				if (trigger.hasClass("thumb")) {
					var productElement = trigger.parent().parent();
				}
				else {
					var productElement = jQuery(this).parent().parent().parent();
				}
				var productData = productElement.data("product");
				
				productSelector.ProductData = productData;
				
				cart.TransferToWorking(productData.OrderGuid, jQuery.proxy(function(response) {
					
				
					var tempPurchase = response.Value;
					if (cartID.length > 0) {
						var tempCart = new Cart({
							CartID: cartID
						});
					} else {
						var tempCart = new Cart();
					}
					tempCart.Purchase = tempPurchase;
					tempCart.Options.WorkingKey = productData.OrderGuid;
					productData = tempPurchase.Products[0];

					productSelector.Cart = tempCart;
					productSelector.Options.LoadCart = true;
					productSelector.OrderGuid = productData.OrderGuid;
					productSelector.WorkingKey = productData.OrderGuid;
					var startDate = new Date(productData.StartDate).add(object.Options.DateAberation).days();
					productSelector.SetDatePicker(startDate);
					//productSelector.LoadProductData(productData); // TODO: Always get the first
					
					productSelector.Show();
					
				}, container));
			});
			
			//** Remove Product from Cart **/
			jQuery(this.Options.Container).delegate(".remove", "click", function() {
				var object = this;
				var productElement = jQuery(this).parent().parent().parent();
				var lineID = productElement.attr("id");
				var productData = productElement.data("product");
				
				productElement.pulse({
					opacity: [.9, .5]
				}, {
					duration: 500,
					times: 3,
					easing: "swing",
					complete: jQuery.proxy(function() {}, this)
				});
				
				
				var callback = function(response) {
					if (response.Result) {
						productElement.stop(true, false).slideUp("normal", function(){
							jQuery(this).remove();
							
							cart.Purchase = response.Value;
							
							// Update cart Listing
							cartList.Cart = cart;
							cartList.UpdateValues();
							
						});
						
						jQuery("div[rel='" + lineID + "']").slideUp("normal", function() {
							jQuery(this).remove();
						})
					} else {
						productElement.stop().animate({opacity: 1});
					}

				}


				cart.RemoveProduct(productData.OrderGuid, productData.ProductCode, callback);
				return false;
			})
			
			
			//** Edit the Purchase Name
			jQuery(this.Options.NameContainer).delegate(".edit", "click", function() {
				var name = jQuery(this).parent();
				var span = name.find("span").eq(0);
				var input = name.find("input");
				var defaultName = input.attr("title");
				
				if (name.hasClass("inplace")) {
					//Editing -> Off
					input.stop();
					name.removeClass("inplace");
					span.html(input.val());
					span.effect("highlight", {}, 2000);
					cart.Purchase.Name = input.val();
					//alert(cart.Purchase.Name);
					
				} else {
					//Off -> Editing
					name.addClass("inplace");
					input.val(span.html()).focus().select();
					input.pulse({
						backgroundColor: ['#FCF1BC','#FDF7DB']}, { duration: 500, times: 1000 } );
				}
			});
			
			jQuery(this.Options.NameContainer).delegate("input", "focusout", function() {
				var name = jQuery(this).parent();
				var span = name.find("span").eq(0);
				var input = name.find("input");
				var defaultName = input.attr("title");
				
				if (name.hasClass("inplace")) {
					//Editing -> Off
					input.stop();
					name.removeClass("inplace");
					span.html(input.val());
					span.effect("highlight", {}, 2000);
					cart.Purchase.Name = input.val();
				}
				
			});

		},

		/**
		 * Refresh the detailed cart display view based on the items in the cart.Purchase object
		 */
		Refresh: function(cartObject) {
			if (cartObject) {
				this.Cart = cartObject;
			}
			this.Load();
			
			//Check for Checkout validy
			
		},


		Load: function() {
			this.Render(this.Container);
			this.UpdateValues();
			
			jQuery(this.Options.Container).disableTextSelect();

			this.CheckValidity();
		},
		
		/**
		 * Updates the values for a cart
		 */
		UpdateValues: function() {
			this.SetTotal(this.Options.TotalPriceElement);
			this.SetTotal("#ExperienceAmount");
			this.SetCartDates();
			this.SetName();
			this.CheckValidity();		
			
			// Checkout
		},

		CheckValidity: function() {
			if (!this.Cart || !this.Cart.Purchase || !this.Cart.Purchase.IsValid) {
				jQuery(this.Options.TotalPriceElement).removeClass("valid");
				jQuery(this.Options.CheckOutElement).addClass("disabled");
			} else {
				jQuery(this.Options.TotalPriceElement).addClass("valid");
				jQuery(this.Options.CheckOutElement).removeClass("disabled");
			}

			//Disable Checkout button 
		},
		
		
		/**
		 * Renders a fresh Cart within the specified container.
		 * Clears the container first.
		 * @param {Object} container
		 */
		Render: function(container) {
			var cartList = this;
			container.empty();
			var itemTemplate = LoadTemplate(this.Options.ItemTemplate);

			// Render Products
			if (this.Cart == undefined || !this.Cart.Purchase) {
				return;
			}
			var products = this.Cart.Purchase.Products;
			if (products) {
				
				base2.Array2.forEach(products, function(product) {
					
					var productContent = new ProductContent(product.ProductCode, {
						Callback: jQuery.proxy(function(response) {
							var productContent = response.Value;
							
							// Dates
							var dateFrom = new Date();
							var dateTo = new Date();
							
							var salesConfiguration = product.SalesConfigurations[0];
							var componentDate = null;
							
							try {
		
								// Occupants/Guests
								var guests = "";
								base2.Array2.forEach(product.CriteriaDefinitions, function(criteriaDefinition){
									var guestValue = criteriaDefinition.DefaultSelection.Value;
									if (criteriaDefinition.LastSelected) guestValue = criteriaDefinition.LastSelected.Value; 
									guests += "<dt>" + criteriaDefinition.Display + "</dt><dd>" + guestValue + "</dd>"
									
								});
		
								var image = GetContent(productContent.Content, "Email Image");
								var imageAlt = image.Media[0].Label.Text;
								var imageUrl = image.Media[0].Url;
		
								template = itemTemplate;
								template = template.replace("%COLORCSS%", (product.ProviderColour != "") ? product.ProviderColour : "blue1");
								template = template.replace("%IMAGEALT%", imageAlt);
								template = template.replace("%IMAGE%", imageUrl);
								template = template.replace("%PRODUCTNAME%", product.ProductName);
								//template = template.replace("%DATEFROM%", dateFrom.toString(cartList.Options.DateFormat));
								//template = template.replace("%DATETO%", dateTo.toString(cartList.Options.DateFormat));
								template = template.replace("%DATEFROM%", product.StartDate);
								template = template.replace("%DATETO%", product.EndDate);
								template = template.replace("%DAYSPAN%", "")
								
								var price = new Price(product.DisplayAmount, { Currency: product.DisplayCurrency, Caption: product.DisplayTax});
								template = template.replace("%PRICE%", price.Render());
								template = template.replace("%SALESCONFIGNAME%", salesConfiguration.Name);
								
								template = template.replace("%PROVIDERNAME%", productContent.ProviderName == "" ? "Missing Provider Name" : productContent.ProviderName);
								template = template.replace("%OCCUPANTS%", guests);
								
								var validity = (product.IsValid) ? "valid" : "";
								template = template.replace("%VALIDITY%", validity);
								
								var item = jQuery(template);
								var itemID = "order_" + product.OrderGuid;
								
								//Show extras
								var extrasContainer = item.find(".extras");
								var extrasLabel = extrasContainer.prev().css({ display: "none"});
								if (product.SelectedAddons.length > 0) {
									extrasLabel.css({display: "block"});
									
									base2.Array2.forEach(product.SelectedAddons, function(extra){
										var extraElement = jQuery("<dt />");
										extraElement.html(extra);
										
										extrasContainer.append(extraElement);
									})
								}
								
								
								item.attr("id", itemID);
								item.data("product", product);
								//cartList.setEvent(item, product);
								
								// Product Line Warnings
								base2.Array2.forEach(product.Warnings, function(warning) {
									var warningObj = new Warning({
										Message: warning.Message
									});
									
									var warningElement = warningObj.Render();
									warningElement.addClass("productNotification");
									warningElement.attr({ rel: itemID});
									
									container.append(warningElement);
									
								})
								
								// Product Line Errors
								base2.Array2.forEach(product.Errors, function(error) {
		
									var errorObj = new Error({
										Message: error.Message
									});
									
									var errorElement = errorObj.Render();
									errorElement.addClass("productNotification");
									errorElement.attr({ rel: itemID})
									
									container.append(errorElement);
									
									item.addClass("invalid");
									
								});
								
								container.append(item);
							} catch (exception) {
								ShowError(exception);
							}
						}, this)
					});

					
				});
			}
		},

		SetTotal: function(totalElementSelector) {
			if (this.Cart && this.Cart.Purchase) {
				var total = this.Cart.Purchase.DisplayAmount;
				if (total == null) 
					total = 0;
				var currency = this.Cart.DisplayCurrency;
				var caption = this.Cart.DisplayTax;
				
				var price = new Price(total, {
					Currency: currency,
					Caption: caption
				});
				
				var element = jQuery(totalElementSelector)
				var markup = price.Render();
				element.html(markup);
			}
		},
		
		
		SetCartDates: function() {
			var dateContainer = jQuery(this.Options.DatesContainer);

			dateContainer.empty();
			
			if (this.Cart && this.Cart.Purchase) {
				if (this.Cart.Purchase.StartDate != "" && this.Cart.Purchase.EndDate != "") {
					dateContainer.append("<dt>Start date:</dt>");
					dateContainer.append("<dd>" + this.Cart.Purchase.StartDate + "</dd>");
					dateContainer.append("<dt>End date:</dt>");
					dateContainer.append("<dd>" + this.Cart.Purchase.EndDate + " <span>(" + this.Cart.Purchase.DurationOfStay + ")</span></dd>")
					
					if (this.Cart.Purchase.DurationOfStay != "") 
						;
				}
			}
			
		},
		
		SetName: function(name) {
			if (name == undefined) {
				name = cart.Purchase.Name;
			}
			
			if (name == "" || name == null) {
				name = "(No Name)";
			}
			
			var h2 = jQuery(this.Options.NameContainer);
			h2.find("span").eq(0).html(name);
			h2.find("span.bookingNumber").html(cart.Purchase.RemoteOrderNumber);
		}
	});

	
	
	/**
	 * Check out the cart
	 * @param {Object} options
	 */
	var CartCheckout = base2.Base.extend({
		constructor: function(options){
			this.SetOptions(options);
			this.LoadTemplates();
			this.SetEvents();
		},
		
		Cart: null,
		
		Container: null,
		
		Trigger: null,
		
		Templates: {},
		
		Form: null,
		
		InCheckout: false,
		
		SetOptions: function(options) {
			this.Defaults = {
				Container: "#checkout",
				Form: "#frmCheckout",
				Trigger: "#btnBook",
				Submit: "#submit",
				APICheckout: GBPServiceUrl + "/cart/checkout",
				APICheckoutMethod: APIMETHODS.POST,
				DateFormat: "yyyy/MM/dd",
				TemplateTrigger: "templates/gbp_checkout_trigger.html",
				TemplatePaymentCreditCard: "templates/gbp_checkout_payment_cc.html",
				TemplatePaymentUserDetails: "templates/gbp_checkout_userdetails.html",
				OverlayID: "checkoutOverlay"
			}
			
			this.Options = jQuery.extend({}, this.Defaults, options);
			
			this.Container = jQuery(this.Options.Container);

		},
		
	
		SetEvents: function() {
			var object = this;
			
			// Check out
			this.Container.delegate(this.Options.Trigger + ":not(.disabled)", "click", function() {
				var trigger = this;
				if (object.Cart.Purchase.IsValid) {
					var payment = jQuery("#payment:not(:animated)");
					
					// Load user details (if logged in)
					if (user) {
						payment.find("#first").val(user.FirstName);
						payment.find("#last").val(user.LastName);
						payment.find("#email").val(user.Email);
						payment.find("#phone").val(user.Phone);
					}
					
					
					var paymentHeight = payment.height();
					
					if (payment.length > 0) {
						if (payment.hasClass("active")) {
						
							var content = jQuery("#content:not(:animated)");
							var contentHeight = content.height();
							
							//Show -> Hide
							//content.animate({ height: contentHeight + paymentHeight }, "slow", "swing", function() { payment.css({ display: "block").animate({ opacity: 0}) })
							payment.removeClass("active").css({	display: "block" }).stop(true, true).animate({ opacity: 0 }, "normal", "swing", function(){ content.stop().animate({ height: contentHeight - paymentHeight })});
						}
						else {
							//Hide -> Show
							var content = jQuery("#content:not(:animated)");
							var contentHeight = content.height();
							
							content.stop(true, true).animate({
								height: contentHeight + paymentHeight
							}, "slow", "swing", function(){
								payment.css({ display: "block", opacity: 0 }).stop().animate({ opacity: 1 }).addClass("active");
								
								jQuery.scrollTo(jQuery(payment), 800);
							});

						}
					}
				}

                return false;

			});

			// Check out false
			this.Container.delegate(this.Options.Trigger + ".disabled", "click", function() {
				return false;
			});
			
			
			// Submit the order
			this.Container.delegate(this.Options.Submit, "click", jQuery.proxy(function() {
				this.Submit(user)

				return false;
			}, object));
		},

		LoadTemplates: function() {

			this.Templates.Trigger = LoadTemplate(this.Options.TemplateTrigger);
			this.Templates.PaymentCreditCard = LoadTemplate(this.Options.TemplatePaymentCreditCard);
			this.Templates.PaymentUserDetails = LoadTemplate(this.Options.TemplatePaymentUserDetails);
		},
		

		Load: function() {
			var object = this;
			// Insert Trigger
			var trigger = jQuery(this.Templates.Trigger);

			this.Container.append(trigger);
			this.Trigger = trigger;

			// Insert User Details
			var userDetails = jQuery(this.Templates.PaymentUserDetails);
			userDetails.hide();
			this.Container.append(userDetails);
			
			if (!user || !user.CanPayOnAccount) {
				// Insert Credit Card Details
				var credit = jQuery(this.Templates.PaymentCreditCard);
				userDetails.find(".form1").append(credit);
			}

			// Datepicker
			this.Container.find(".datepicker").each(function() {
				var a = jQuery('.trigger', this);
				var today = Date.today();

				var datePopup = jQuery('<div class="datepopup"></div>');
				jQuery(this).append(datePopup);
				datePopup.datepicker({
					changeMonth: false,
					changeYear: false,
					yearRange: '-70:0',
					//defaultDate: today.toString('yy MM dd'),
					inline: true,
					dateFormat: 'dd MM yy',
					onSelect: function(date, inst){
						a.find('span').html(date.toUpperCase()).end().
							parents('.datepicker').
								removeClass('datepicker-active').
								find('input[type="hidden"]').val(date).end();
					}
				});
				jQuery('.trigger', this).click(function(){
					jQuery(this.parentNode).toggleClass('datepicker-active');
					return false;
				});
			});

			// Initialize Validate plugin
			this.Form = this.Container.find(this.Options.Form);
			this.Container.find(this.Options.Form).validate();

		},


		Update: function() {
			if (this.Cart.Purchase.IsValid) {
				this.Trigger.removeClass("disabled");
			} else {
				this.Trigger.addClass("disabled");
			}
		},


		Open: function(option) {
			// Check for a valid cart.
			if (this.Cart.IsValid) {
				
			}
		},

		Close: function() {

		},

		/** Submit the order to the backend **/
		Submit: function(checkoutUser) {
			if (checkoutUser == null || checkoutUser == undefined) {
				var checkoutUser = new User();
			}

			checkoutUser.FirstName = this.Container.find("#first").val();
			checkoutUser.LastName = this.Container.find("#last").val();
			checkoutUser.Email = this.Container.find("#email").val();
			checkoutUser.Country = this.Container.find("#country").val();
			checkoutUser.City = this.Container.find("#city").val();
			checkoutUser.Phone = this.Container.find("#phone").val();
			// checkoutUser.DateOfBirth = this.GetDateOfBirth().toString(this.Options.DateFormat)
			checkoutUser.CanPayOnAccount = (checkoutUser.CanPayOnAccount) ? true : false;

			var cc = {
				CCV: this.Container.find("#ccv").val(),
				ExpiryMonth: this.Container.find("#ccexp1").val(),
				ExpiryYear: this.Container.find("#ccexp2").val(),
				Number: this.Container.find("#ccnumber").val(),
				NameOnCard: this.Container.find("#ccname").val(),
				TypeCode: this.Container.find("#cctype").val()
			}

			if (this.IsValid(checkoutUser, cc)) {
				ShowOverlay();
				ShowWaiting("Please wait...", "Submitting Order");
				this.InCheckout = true;
				
				cart.Checkout(checkoutUser, cc);
			} else {
				ShowError("Please supply all required information to book your order", "Required Fields Missing");
				HideOverlay();
				this.InCheckout = false;
			}

		},

		/**
		 * Check if the supplied user and card are valid for checkout
		 * @param {Object} checkoutUser
		 * @param {Object} card
		 */
		IsValid: function(checkoutUser, card) {

			if (checkoutUser.FirstName == null || checkoutUser.FirstName == "") return false;
			if (checkoutUser.LastName == null || checkoutUser.LastName == "") return false;
			if (checkoutUser.Email == null || checkoutUser.LastName == "") return false;
			//if (checkoutUser.Password == null || checkoutUser.Password == "") return false;
			if (checkoutUser.Country == null || checkoutUser.Country == "") return false;
			if (checkoutUser.City == null || checkoutUser.City == "") return false;
			if (checkoutUser.Phone == null || checkoutUser.Phone == "") return false;

			if (card.CCV == "") return false;
			if (card.ExpiryMonth == "") return false;
			if (card.ExpiryYear == "") return false;
			if (card.Number == "") return false;
			if (card.NameOnCard == "") return false;
			if (card.TypeCode == "") return false;

			return true;

		},

		/**
		 * Selected Date Picker
		 */
		GetDateOfBirth: function() {
			var datePopup = this.Container.find(".datepopup");
			var dateData = datePopup.data("datepicker");

			var dateObj = {
				year: dateData.selectedYear,
				month: dateData.selectedMonth,
				day: dateData.selectedDay
			}

			var date = new Date().set(dateObj).clearTime();

			return date;

		}

	});
