/****************************************************************************
Copyright (c) 2009 The Wojo Group

thewojogroup.com
simplecartjs.com
http://github.com/thewojogroup/simplecart-js/tree/master

The MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

/*
REVISIONS - JG

- Added a unique cookie name
- Changed the '-' and '+' to non-breaking spaces (so a background image could be used)
- Added Moneris specific checkout. Relies on form fields in the a form labelled simplecartform on the shopping cart page.
- Added alert boxes when making choices
- Added to leave a message when the cart is empty; use <div id="empty_msg"></div> to take advantage of feature
*/


// JG: Added to distinguish cart cookie
var COOKIE_ID_NAME 	= "knollwoodCart";
var HST_AMOUNT 		= 0.13;

var NextId=1,Custom="Custom",GoogleCheckout="GoogleCheckout",PayPal="PayPal",Moneris="Moneris",Email="Email",AustralianDollar=AUD="AUD",CanadianDollar=CAD="CAD",CzechKoruna=CZK="CZK",DanishKrone=DKK="DKK",Euro=EUR="EUR",HongKongDollar=HKD="HKD",HungarianForint=HUF="HUF",IsraeliNewSheqel=ILS="ILS",JapaneseYen=JPY="JPY",MexicanPeso=MXN="MXN",NorwegianKrone=NOK="NOK",NewZealandDollar=NZD="NZD",PolishZloty=PLN="PLN",PoundSterling=GBP="GBP",SingaporeDollar=SGD="SGD",SwedishKrona=SEK="SEK",SwissFranc=CHF="CHF",USDollar=USD="USD";
function Cart(){

	var me = this;
	/* member variables */
	me.Version = '2.0.1';
	me.Shelf = new Shelf();
	me.items = {};
	me.isLoaded = false;
	me.pageIsReady = false;
	me.quantity = 0;
	me.total = 0;
	me.taxRate 		= 0.13; // HST
	me.taxRatePST 	= 0.08;
	me.taxRateGST 	= 0.05;
	me.taxCost = 0;
	me.shippingFlatRate = 0;
	me.shippingTotalRate = 0;
	me.shippingQuantityRate = 0;
	me.shippingRate = 0;
	me.shippingCost = 0;
	me.currency = CAD;
	me.checkoutTo = Moneris;
	me.email = "";
	me.merchantId	 = "";
	me.cartHeaders = ['Name','Price','Quantity','Total'];
	
	// Some items in the cart  may not be taxable
	me.totalNonTaxable = 0;
	me.totalTaxable = 0;
	/* 
		cart headers: 
		you can set these to which ever order you would like, and the cart will display the appropriate headers
		and item info.  any field you have for the items in the cart can be used, and 'Total' will automatically 
		be price*quantity.  
		
		there are keywords that can be used:
			
			1) "_input" - the field will be a text input with the value set to the given field. when the user
				changes the value, it will update the cart.  this can be useful for quantity. (ie "Quantity_input")
			
			2) "increment" - a link with "+" that will increase the item quantity by 1
			
			3) "decrement" - a link with "-" that will decrease the item quantity by 1
			
			4) "remove" - a link that will remove the item from the cart 
			
			5) "_image" or "Image" - the field will be an img tag with the src set to the value. You can simply use "Image" if
				you set a field in the items called "Image".  If you have a field named something else, like "Thumb", you can add
				the "_image" to create the image tag (ie "Thumb_image").
				
			6) "_noHeader" - this will skip the header for that field (ie "increment_noHeader")
		
	
	*/
	
	


	/******************************************************
			add/remove items to cart  
 	 ******************************************************/

	me.add = function () {
		var me=this;
		/* load cart values if not already loaded */
		if( !me.pageIsReady 	) { 
			me.initializeView(); 
			me.update();	
		}
		if( !me.isLoaded 		) { 
			me.load(); 
			me.update();	
		}
		
		var newItem = new CartItem();
		
		/* check to ensure arguments have been passed in */
		if( !arguments || arguments.length === 0 ){
			error( 'No values passed for item.');
			return;
		}
		var argumentArray = arguments;
		if( arguments[0] && typeof( arguments[0] ) != 'string' && typeof( arguments[0] ) != 'number'  ){ 
			argumentArray = arguments[0]; 
		} 
	
		newItem.parseValuesFromArray( argumentArray );
		newItem.checkQuantityAndPrice();
		
		
		
		/* if the item already exists, update the quantity */
		if( me.hasItem(newItem) ) {
			var id=me.hasItem(newItem);
			me.items[id].quantity= parseInt(me.items[id].quantity,10) + parseInt(newItem.quantity,10);
			alert("SHOPPING CART\n\nAdded another \"" + newItem.name + "\". You now have "+me.items[id].quantity+" of these in your cart.");
			
		} else {
			me.items[newItem.id] = newItem;
			alert("SHOPPING CART\n\nAdded \"" + newItem.name + "\".");
		}	
		
		me.update();
	};
	
	
	me.remove = function( id ){
		if(confirm("Are you sure you want to remove this item from your shopping cart?")) {
			var tempArray = {};
			for( var item in this.items ){
				if( item != id ){ 
					tempArray[item] = this.items[item]; 
				}
			}
			this.items = tempArray;
		}
	};
	
	me.empty = function () {
		if(confirm("You are about to clear your entire shopping cart, are you sure?")) {
			simpleCart.items = {};
			simpleCart.update();
		}
	};
	
	/******************************************************
			 item accessor functions
     ******************************************************/

	me.find = function (criteria) {
		if( !criteria )
			return null;
		var results = [];
		for( var next in me.items ){
			var item = me.items[next],
				fits = true;
			for( var name in criteria ){
				if( !item[name] || item[name] != criteria[name] )
					fits = false;
			}
			if( fits )
				results.push( me.next )
		}
		return (results.length == 0 ) ? null : results;
	}

	/******************************************************
			 checkout management 
     ******************************************************/

	me.checkout = function() {
		if ($("#simplecartform").valid()) { // Run jQuery Validation on form first before proceeding to next step of form submission
			if( simpleCart.quantity === 0 ){
				error("Cart is empty");
				alert("You have no items in your shopping cart.");
				return;
			}
			switch( simpleCart.checkoutTo ){
				case PayPal:
					simpleCart.paypalCheckout();
					break;
				case GoogleCheckout:
					simpleCart.googleCheckout();
					break;
				case Email:
					simpleCart.emailCheckout();
					break;
				case Moneris:
					simpleCart.monerisCheckout();
					break;				
				default:
					simpleCart.customCheckout();
					break;
			}
		}
	};
	
	me.paypalCheckout = function() {
		
		var me = this,
			winpar = "scrollbars,location,resizable,status",
			strn  = "https://www.paypal.com/cgi-bin/webscr?cmd=_cart" +
		   			"&upload=1" +
		        	"&business=" + me.email + 
					"&currency_code=" + me.currency,
			counter = 1,
			itemsString = "";
			
		
		if( me.taxRate ){
			strn = strn + 
				"&tax_cart=" +  me.currencyStringForPaypalCheckout( me.taxCost );
		}
		
		for( var current in me.items ){
			var item = me.items[current];
			
			var optionsString = "";
			for( var field in item ){
				if( typeof(item[field]) != "function" && field != "id" && field != "price" && field != "quantity" && field != "name" && field != "shipping") {
					optionsString = optionsString + ", " + field + "=" + item[field] ; 
				}
			}
			optionsString = optionsString.substring(2);
			
			itemsString = itemsString 	+ "&item_name_" 	+ counter + "=" + item.name  +
									 	  "&item_number_" 	+ counter + "=" + counter +
										  "&quantity_"		+ counter + "=" + item.quantity +
										  "&amount_"		+ counter + "=" + me.currencyStringForPaypalCheckout( item.price ) + 
										  "&on0_" 			+ counter + "=" + "Options" + 
										  "&os0_"			+ counter + "=" + optionsString;
			counter++;
		}
		
		if( me.shipping() != 0){
			 itemsString = itemsString 	+ "&item_name_" 	+ counter + "=Shipping"  +
									 	  "&item_number_" 	+ counter + "=" + counter +
										  "&quantity_"		+ counter + "=1" + 
										  "&amount_"		+ counter + "=" + me.currencyStringForPaypalCheckout( me.shippingCost );
		}
		
		
		strn = strn + itemsString ;
		window.open (strn, "paypal", winpar);
	};

	me.googleCheckout = function() {
		var me = this;
		if( me.currency != USD && me.currency != GBP ){
			error( "Google Checkout only allows the USD and GBP for currency.");
			return;
		} else if( me.merchantId === "" || me.merchantId === null || !me.merchantId ){
			error( "No merchant Id for google checkout supplied.");
			return;
		} 
		
		var form = document.createElement("form"),
		counter = 1;
		
		form.style.display = "none";
		form.method = "POST";
		form.action = "https://checkout.google.com/api/checkout/v2/checkoutForm/Merchant/" + 
						me.merchantId;
		form.acceptCharset = "utf-8";
		
		for( var current in me.items ){
			var item 				= me.items[current];
			form.appendChild( me.createHiddenElement( "item_name_" 		+ counter, item.name		) );
			form.appendChild( me.createHiddenElement( "item_quantity_" 	+ counter, item.quantity 	) );
			form.appendChild( me.createHiddenElement( "item_price_" 		+ counter, item.price		) );
			form.appendChild( me.createHiddenElement( "item_currency_" 	+ counter, me.currency 	) );
			form.appendChild( me.createHiddenElement( "item_tax_rate_" 	+ counter, me.taxRate 	) );
			form.appendChild( me.createHiddenElement( "_charset_"					 , ""				) );
			
			var descriptionString = "";
			
			for (var field in item) {
				if (	typeof(item[field]) != "function" &&
														field != "id" &&
														field != "quantity"	&&
														field != "price" ) {
						descriptionString = descriptionString + ", " + field + ": " + item[field];				
				}
			}
			
			descriptionString = descriptionString.substring( 1 );
			form.appendChild( me.createHiddenElement( "item_description_" + counter, descriptionString) );
			counter++;
		}
		
		document.body.appendChild(form);
		form.submit();
		document.body.removeChild(form);
	};
	
	
	
	me.emailCheckout = function() {
		return;
	};
	
	me.customCheckout = function() {
		return;
	};


	me.monerisCheckout = function() {
		var self = this;

		// Get an existing form as there will be additional details including
		// the important IDs needed for using the Moneris hosted pay page
		var form = document.getElementById("simplecartform");
		
		if (!form) {
			alert("The online checkout has encountered an error and is unable to complete the purchase process. " +
			 			"Please make your purchase by phone or in-store instead.\n\nSorry for any inconvenience this may have caused.");
			return;
		}
		
		// Must have at least one membership in cart if there are other options. Giftcards are ok on their own.
		var number_of_memberships =
				number_of_giftcards =
				number_of_options = 0;
		for (var i in self.items) {
			if (self.items[i].membership !== undefined) {
				number_of_memberships += 1;				
			} else if (self.items[i].name === "Gift Card") {
				number_of_giftcards += 1;
			} else {
				number_of_options += 1;
			}
		}
		if (number_of_memberships === 0) {
			if (number_of_options > 0) {
				// Options with no membership. Not allowed to pass.
				alert("You must purchase at least one membership for the options that have been selected.");
				return;
			} else {
				// Must be only gift cards in cart. PASS.
			}
		}
		
		//var form = document.createElement("form");
		var counter = 1;
		form.style.display 	= "none";
		form.acceptCharset 	= "utf-8";
		
		// Init the totals
		var charge_total 	= 0.00;
		var hst_tax_total = 0.00;
		
		// Create temp variables for subtotals
		for (var current in self.items) {
			var item 							= self.items[current];			
			var item_subtotal 		= parseFloat(item.quantity) * parseFloat(item.price);
			var hst_tax_subtotal 	= 0.00;
			
			// If the sku is not defined, use the description
			if(item.sku !== undefined) {
				form.appendChild( self.createHiddenElement( "id" 		+ counter, item.sku			) );
			} else {
				form.appendChild( self.createHiddenElement( "id" 		+ counter, item.name		) );
			}
			
			form.appendChild( self.createHiddenElement( "description" + counter, item.name		) );
			form.appendChild( self.createHiddenElement( "quantity" 	+ counter, item.quantity 	) );
			form.appendChild( self.createHiddenElement( "price" 		+ counter, parseFloat(item.price).toFixed(2) ) );
			form.appendChild( self.createHiddenElement( "subtotal" 	+ counter, item_subtotal.toFixed(2) 	) );
						
			// Some items are exempt from being charged HST
			// Add similar if statements for other taxes like PST or GST.
			if (item.notax === undefined) {
				hst_tax_subtotal 	= parseFloat(item_subtotal) * parseFloat(HST_AMOUNT);
				item_subtotal 		= parseFloat(item_subtotal) + parseFloat(hst_tax_subtotal);						
			} 
			
			// Update the running totals
			hst_tax_total 	= parseFloat(hst_tax_total) + parseFloat(hst_tax_subtotal);
			charge_total 	= parseFloat(charge_total) + parseFloat(item_subtotal);
			
			counter++;
		}
		
		var pay_by_installments_12_el = document.getElementById("pay_by_installments_12");
		var pay_by_installments_6_el 	= document.getElementById("pay_by_installments_6"); // NOTE: This is using the "6" element, but is really "3 months" so the elements don't have to be renamed.
		var do_recur_el 							= document.getElementById("do_recur");
		var agree_to_terms_el 				= document.getElementById("agree_to_terms");
		var recur_amount_el 					= document.getElementById("recur_amount");
		var recur_num_el    					= document.getElementById("recur_num");
		var recur_start_date 					= document.getElementById("recur_start_date");
		
		if (pay_by_installments_12_el.checked) {
			var recur_num = 11;
			charge_total = parseFloat(charge_total / parseFloat(recur_num + 1)).toFixed(2);
			recur_amount_el.value = charge_total;
			do_recur_el.value = 1;
			recur_num_el.value = recur_num;
			$("#pay_by_installments_6").remove();
			$("#pay_by_installments_12").attr("name", "rvarInstallments");
		} else if (pay_by_installments_6_el.checked) {
			// NOTE: regarding debit membership recurring payments:
			//
			// 1) Change recur_num to one (1) less than the total number of recurring payments desired.
			// 2) Update the "Debit Memberships" page in the CMS to reference the total number in the body copy.
			// 3) Update shopping-cart.php:
			// 				a) 
			
			//var recur_num = 5;
			var recur_num = 2; // NOTE: This element used to be *6* months, and is now changed to *3* (remember that this recur_num is one (1) integer less than the desired total since the current month is immediately deducted at purchase)
			charge_total = parseFloat(charge_total / parseFloat(recur_num + 1)).toFixed(2);
			do_recur_el.value = 1;
			recur_num_el.value = recur_num;
			$("#pay_by_installments_12").remove();
			$("#pay_by_installments_6").attr("name", "rvarInstallments");
		} else {
			do_recur_el.value = 0;
			$("#pay_by_installments_12").remove();
			$("#pay_by_installments_6").remove();
		}
		
		// Set recurring payment start date.
		if (pay_by_installments_12_el.checked || pay_by_installments_6_el.checked) {
			var MAX_RECURR_START_DAY_NUM = 28; // to handle february
			var today = new Date();
			var today_day_number = today.getDate();
			var today_month_number = today.getMonth() + 1; // Note that getMonth() returns an integer for the month starting from 0 (so January = 0, Feb = 1, etc.)
			var today_year_number = today.getFullYear();
			var next_day_number, next_month_number, next_year_number = "";
			if (today_day_number > MAX_RECURR_START_DAY_NUM) {
				next_day_number = String(MAX_RECURR_START_DAY_NUM);
			} else {
				if (today_day_number < 10) {
					next_day_number = "0" + today_day_number;
				} else {
					next_day_number = String(today_day_number);
				}
			}
			if (today_month_number === 12) { // Current month is December (12) and next month, therefore, needs to be January (01)
				next_month_number = "01";
				next_year_number = String(today_year_number + 1);
			} else { // For any other month, just make the next month one increment from the current month.
				next_month_number = today_month_number + 1;
				next_year_number = String(today_year_number);
				if (next_month_number < 10) { // If the next month number is less than 10, prepend a "0" to make it a two digit string.
					next_month_number = String("0" + next_month_number);
				} else {
					next_month_number = String(next_month_number);
				}				
			}
			var start_date_as_a_string_for_moneris = next_year_number + "/" + next_month_number + "/" + next_day_number;
			//alert(start_date_as_a_string_for_moneris);
			$("#recur_start_date").val(start_date_as_a_string_for_moneris);
		}
		
		// if(pay_by_installments.checked) {
		// 	var recur_amount 	= document.getElementById("recur_amount");
		// 	var recur_num 		= document.getElementById("recur_num");
		// 	var payment 		= parseFloat(charge_total)/( parseFloat(recur_num.value) + 1.0); // recur_num is the nubmer of remaining payments assuming user charged immediately for first payment
		// 	//alert("recur_amount = "+recur_amount.value+"\n"+"recur_num = "+recur_num.value+"\n"+"payment = "+payment+"\n"+"charge_total = "+ parseFloat(charge_total));
		// 	recur_amount.value 	= payment.toFixed(2);
		// 	charge_total 		= payment.toFixed(2);
		// 	do_recur.value = 1;
		// } else {
		// 	do_recur.value = 0;	
		// }

		if (pay_by_installments_12_el.checked || pay_by_installments_6_el.checked) {
			$("#recur_amount").attr("value", parseFloat(charge_total).toFixed(2));
		}
		$("#charge_total").attr("value", parseFloat(charge_total).toFixed(2));
		form.appendChild( self.createHiddenElement( "hst", parseFloat(hst_tax_total).toFixed(2)) );

		// Submit that form to Moneris
		form.submit();	
	}



	/******************************************************
				data storage and retrival 
	 ******************************************************/
	
	/* load cart from cookie */
	me.load = function () {
		var me = this;
		/* initialize variables and items array */
		me.items = {};
		me.total = 0.00;
		me.quantity = 0;
		
		/* retrieve item data from cookie */
		if( readCookie(COOKIE_ID_NAME) ){
			var data = unescape(readCookie(COOKIE_ID_NAME)).split('++');
			for(var x=0, xlen=data.length;x<xlen;x++){
			
				var info = data[x].split('||');
				var newItem = new CartItem();
			
				if( newItem.parseValuesFromArray( info ) ){
					newItem.checkQuantityAndPrice();
					/* store the new item in the cart */
					me.items[newItem.id] = newItem;
				}
 			}
		}
		me.isLoaded = true;
	};
	
	
	
	/* save cart to cookie */
	me.save = function () {
		var dataString = "";
		for( var item in this.items ){
			dataString = dataString + "++" + this.items[item].print();
		}
		createCookie(COOKIE_ID_NAME, dataString.substring( 2 ), 30 );
	};
	
	

	
		
	/******************************************************
				 view management 
	 ******************************************************/
	
	me.initializeView = function() {
		var me = this;
		me.totalOutlets 			= getElementsByClassName('simpleCart_total');
		me.quantityOutlets 			= getElementsByClassName('simpleCart_quantity');
		me.cartDivs 				= getElementsByClassName('simpleCart_items');
		me.taxCostOutlets			= getElementsByClassName('simpleCart_taxCost');
		me.taxRateOutlets			= getElementsByClassName('simpleCart_taxRate');
		me.shippingCostOutlets		= getElementsByClassName('simpleCart_shippingCost');
		me.finalTotalOutlets		= getElementsByClassName('simpleCart_finalTotal');
		
		me.addEventToArray( getElementsByClassName('simpleCart_checkout') , simpleCart.checkout , "click");
		me.addEventToArray( getElementsByClassName('simpleCart_empty') 	, simpleCart.empty , "click" );
		
		me.Shelf.readPage();
			
		me.pageIsReady = true;
		
	};
	
	
	
	me.updateView = function() {
    me.toggleMonthlyPaymentOption();
		me.updateViewTotals();
		if( me.cartDivs && me.cartDivs.length > 0 ){ 
			me.updateCartView(); 
		}
	};
	
	me.updateViewTotals = function() {
		var outlets = [ ["quantity"		, "none"		] , 
						["total"		, "currency"	] , 
						["shippingCost"	, "currency"	] ,
						["taxCost"		, "currency"	] ,
						["taxRate"		, "percentage"	] ,
						["finalTotal"	, "currency"	] ];
						
		for( var x=0,xlen=outlets.length; x<xlen;x++){
			
			var arrayName = outlets[x][0] + "Outlets",
				outputString;
				
			for( var element in me[ arrayName ] ){
				switch( outlets[x][1] ){
					case "none":
						outputString = "" + me[outlets[x][0]];
						break;
					case "currency":
						outputString = me.valueToCurrencyString( me[outlets[x][0]] );
						break;
					case "percentage":
						outputString = me.valueToPercentageString( me[outlets[x][0]] );
						break;
					default:
						outputString = "" + me[outlets[x][0]];
						break;
				}
				me[arrayName][element].innerHTML = "" + outputString;
			}
		}
	};
	
	me.updateCartView = function() {
		var newRows = [],
			x,newRow,item,current,header,newCell,info,outputValue,option,headerInfo;
		
		/* create headers row */
		newRow = document.createElement('div');
		for( header in me.cartHeaders ){
			newCell = document.createElement('div');
			headerInfo = me.cartHeaders[header].split("_");
			
			newCell.innerHTML = headerInfo[0];
			newCell.className = "item" + headerInfo[0];
			for(x=1,xlen=headerInfo.length;x<xlen;x++){
				if( headerInfo[x].toLowerCase() == "noheader" ){
					newCell.style.display = "none";
				}
			}
			newRow.appendChild( newCell );
			
		}
		newRow.className = "cartHeaders";
		newRows[0] = newRow;
		
		/* create a row for each item in the cart */
		x=1;
		for( current in me.items ){
			newRow = document.createElement('div');
			item = me.items[current];
			
			for( header in me.cartHeaders ){
				
				newCell = document.createElement('div');
				info = me.cartHeaders[header].split("_");
				
				switch( info[0].toLowerCase() ){
					case "total":
						outputValue = me.valueToCurrencyString(parseFloat(item.price)*parseInt(item.quantity,10) );
						break;
					case "increment":
						outputValue = me.valueToLink( "&nbsp;" , "javascript:;" , "onclick=\"simpleCart.items[\'" + item.id + "\'].increment();\"" );
						break;
					case "decrement":
						outputValue = me.valueToLink( "&nbsp;" , "javascript:;" , "onclick=\"simpleCart.items[\'" + item.id + "\'].decrement();\"" );
						break;
					case "remove":
						outputValue = me.valueToLink( "Remove" , "javascript:;" , "onclick=\"simpleCart.items[\'" + item.id + "\'].remove();\"" );
						break;
					case "price":
						outputValue = me.valueToCurrencyString( item[ info[0].toLowerCase() ] ? item[info[0].toLowerCase()] : " " );
						break;
					default: 
						outputValue = item[ info[0].toLowerCase() ] ? item[info[0].toLowerCase()] : " ";
						break;
				}	
				
				for( var y=1,ylen=info.length;y<ylen;y++){
					option = info[y].toLowerCase();
					switch( option ){
						case "image":
						case "img":
							outputValue = me.valueToImageString( outputValue );		
							break;
						case "input":
							outputValue = me.valueToTextInput( outputValue , "onchange=\"simpleCart.items[\'" + item.id + "\'].set(\'" + outputValue + "\' , this.value);\""  );
							break;
						case "div":
						case "span":
						case "h1":
						case "h2":
						case "h3":
						case "h4":
						case "p":
							outputValue = me.valueToElement( option , outputValue , "" );
							break;
						case "noheader":
							break;
						default:
							error( "unkown header option: " + option );
							break;
					}
				
				}		  
				newCell.innerHTML = outputValue;
				newCell.className = "item" + info[0];
				newRow.appendChild( newCell );
			}			
			newRow.className = "itemContainer";
			newRows[x] = newRow;
			x++;
		}
		
		
		// Added to leave a message when the cart is empty
		// use <div id="empty_msg"></div> to take advantage of feature
		var empty_msg 	= document.getElementById("empty_msg");
		if(empty_msg) {
			if(x == 1) {
				
				empty_msg.innerHTML = "<p>No items in cart.</p>";
			//alert("cart is empty");
			} else {
				empty_msg.innerHTML = "";
			}
		}
		
		for( current in me.cartDivs ){
			
			/* delete current rows in div */
			var div = me.cartDivs[current];
			while( div.childNodes[0] ){
				div.removeChild( div.childNodes[0] );
			}
			
			for(var j=0, jLen = newRows.length; j<jLen; j++){
				div.appendChild( newRows[j] );
			}
			
			
		}
	};

	me.addEventToArray = function ( array , functionCall , theEvent ) {
		for( var outlet in array ){
			var element = array[outlet];
			if( element.addEventListener ) {
				element.addEventListener(theEvent, functionCall , false );
			} else if( element.attachEvent ) {
			  	element.attachEvent( "on" + theEvent, functionCall );
			}
		}
	};
	
	
	me.createHiddenElement = function ( name , value ){
		var element = document.createElement("input");
		element.type = "hidden";
		element.name = name;
		element.value = value;
		return element;
	};
	
	
	
	/******************************************************
				Currency management
	 ******************************************************/
	
	me.currencySymbol = function() {		
		switch(me.currency){
			case JPY:
				return "&yen;";
			case EUR:
				return "&euro;";
			case GBP:
				return "&pound;";
			case USD:
			case CAD:
			case AUD:
			case NZD:
			case HKD:
			case SGD:
				return "&#36;";
			default:
				return "";
		}
	};
	
	
	me.currencyStringForPaypalCheckout = function( value ){
		if( me.currencySymbol() == "&#36;" ){
			return "$" + parseFloat( value ).toFixed(2);
		} else {
			return "" + parseFloat(value ).toFixed(2);
		}
	};
	
	/******************************************************
				Formatting
	 ******************************************************/
	
	
	me.valueToCurrencyString = function( value ) {
		return parseFloat( value ).toCurrency( me.currencySymbol() );
	};
	
	me.valueToPercentageString = function( value ){
		return parseFloat( 100*value ) + "%";
	};
	
	me.valueToImageString = function( value ){
		if( value.match(/<\s*img.*src\=/) ){
			return value;
		} else {
			return "<img src=\"" + value + "\" />";
		}
	};
	
	me.valueToTextInput = function( value , html ){
		return "<input type=\"text\" value=\"" + value + "\" " + html + " />";
	};
	
	me.valueToLink = function( value, link, html){
		return "<a href=\"" + link + "\" " + html + " >" + value + "</a>";
	};
	
	me.valueToElement = function( type , value , html ){
		return "<" + type + " " + html + " > " + value + "</" + type + ">";
	};
	
	/******************************************************
				Duplicate management
	 ******************************************************/
	
	me.hasItem = function ( item ) {
		for( var current in me.items ) {
			var testItem = me.items[current];
			var matches = true;
			for( var field in item ){
				if( typeof( item[field] ) != "function"	&& 
					field != "quantity"  				&& 
					field != "id" 						){
					if( item[field] != testItem[field] ){
						matches = false;
					}
				}	
			}
			if( matches ){ 
				return current; 
			}
		}
		return false;
	};
	
	
	
	
	/******************************************************
				Cart Update managment
	 ******************************************************/
	
	me.update = function() {
		if( !simpleCart.isLoaded ){
			simpleCart.load();
		} 
		if( !simpleCart.pageIsReady ){
			simpleCart.initializeView();
		}
		me.updateTotals();
		me.updateView();
		me.save();
	};
	
	me.updateTotals = function() {
		me.total = 0 ;
		me.quantity  = 0;
		me.totalNonTaxable = 0;
		me.totalTaxable = 0;
		for( var current in me.items ){
			var item = me.items[current];
			if( item.quantity < 1 ){ 
				item.remove();
			} else if( item.quantity !== null && item.quantity != "undefined" ){
				me.quantity = parseInt(me.quantity,10) + parseInt(item.quantity,10); 
			}
			if( item.price ){ 
				// Differentiate between taxable and non-taxable (added functionality)
				if(item.notax) {
					me.totalNonTaxable = parseFloat(me.totalNonTaxable) + parseInt(item.quantity,10)*parseFloat(item.price); 
				} else {
					me.totalTaxable = parseFloat(me.totalTaxable) + parseInt(item.quantity,10)*parseFloat(item.price); 
				}
			}
		}
		me.shippingCost = me.shipping();
		// Total is the combined taxable and non-taxable items
		me.total = parseFloat(me.totalNonTaxable) + parseFloat(me.totalTaxable);
		// Adjusted tax cost to only apply to taxable items
		me.taxCost = parseFloat(me.totalTaxable)*me.taxRate;
		// Now the final total can be created
		me.finalTotal = me.shippingCost + me.taxCost + me.total;
	};
	
	me.shipping = function(){
		if( parseInt(me.quantity,10)===0 )
			return 0;
		var shipping = 	parseFloat(me.shippingFlatRate) + 
					  	parseFloat(me.shippingTotalRate)*parseFloat(me.total) +
						parseFloat(me.shippingQuantityRate)*parseInt(me.quantity,10),
			nextItem,
			next;
		for(next in me.items){
			nextItem = me.items[next];
			if( nextItem.shipping ){
				if( typeof nextItem.shipping == 'function' ){
					shipping += parseFloat(nextItem.shipping());
				} else {
					shipping += parseFloat(nextItem.shipping);
				}
			}
		}
		
		return shipping;
	}
	
	me.initialize = function() {
		simpleCart.initializeView();
		simpleCart.load();
		simpleCart.update();
    simpleCart.toggleMonthlyPaymentOption();
	};

  // Added by Rob McLarty to toggle monthly payments option on and off based on the existence of a gift card item
  me.toggleMonthlyPaymentOption = function() {
    var items = me.items;
    var gift_card_included = false;
		var debit_membership_included = false;
		var traditional_membership_included = false;
		
    for (var key in items) {
      var item = me.items[key];
			if (item.name === "Gift Card") 							{ gift_card_included = true }
			if (item.name === "Debit Membership") 			{ debit_membership_included = true }
			if (item.name.indexOf("Traditional") >= 0) 	{ traditional_membership_included = true }
    }

		if (traditional_membership_included && !gift_card_included) {
			// Traditional Memberships alone OR (Traditional AND Debit Memberships) can be paid for in 12 monthly payments.
			$("#recurring-payments-option-12").show();
			$("#recurring-payments-option-6").hide();
      $("#recurring-payments-off-message").hide();
		} else if (debit_membership_included && !traditional_membership_included && !gift_card_included) {
			// Only Debit Memberships can be paid for in 6 monthly payments.
			$("#recurring-payments-option-12").hide();
			$("#recurring-payments-option-6").show();
      $("#recurring-payments-off-message").hide();
		} else {
			// Any other combination of options must be paid in full.
			$("#recurring-payments-option-12").hide();
			$("#recurring-payments-option-6").hide();
      $("#recurring-payments-off-message").show();
		}
  }
				
}

/********************************************************************************************************
 *			Cart Item Object
 ********************************************************************************************************/

function CartItem() {
	var d = new Date();
	this.id = "c" + d.getTime(); //NextId++;
	// This is a fix of an issue where conflicting ids were being generated and overwriting cart contents.
	// This issue has been fixed in version 2.2 with https://github.com/wojodesign/simplecart-js/commit/5b352524a3e36ca35783660afb485c18aa9cccd6
	// But since we've heavily modified this file, I've used a datestamp to generate unique ids.
}
	CartItem.prototype.set = function ( field , value ){
		field = field.toLowerCase();
		if( typeof( this[field] ) != "function" && field != "id" ){
			if( field == "quantity" ){
				value = value.replace( /[^(\d|\.)]*/gi , "" );
				value = value.replace(/,*/gi, "");
				value = parseInt(value,10);
			} else if( field == "price"){
				value = value.replace( /[^(\d|\.)]*/gi, "");
				value = value.replace(/,*/gi , "");
				value = parseFloat( value );
			}
			if( typeof(value) == "number" && isNaN( value ) ){
				error( "Improperly formatted input.");
			} else {
				this[field] = value;
				this.checkQuantityAndPrice();
			}			
		} else {
			error( "Cannot change " + field + ", this is a reserved field.");
		}
		simpleCart.update();
	};
	
	CartItem.prototype.increment = function(){
		this.quantity = parseInt(this.quantity,10) + 1;
		simpleCart.update();
	};
	
	CartItem.prototype.decrement = function(){
		if( parseInt(this.quantity,10) < 2 ){
			this.remove();
		} else {
			this.quantity = parseInt(this.quantity,10) - 1;
			simpleCart.update();
		}
	};
	
	CartItem.prototype.print = function () {
		var returnString = '';
		for( var field in this ) {
			if( typeof( this[field] ) != "function" ) {
				returnString+= escape(field) + "=" + escape(this[field]) + "||";
			}
		}
		return returnString.substring(0,returnString.length-2);
	};
	
	
	CartItem.prototype.checkQuantityAndPrice = function() {
		if( !this.price || this.quantity == null || this.quantity == 'undefined'){ 
			this.quantity = 1;
			error('No quantity for item.');
		} else {
			this.quantity = ("" + this.quantity).replace(/,*/gi, "" );
			this.quantity = parseInt( ("" + this.quantity).replace( /[^(\d|\.)]*/gi, "") , 10); 
			if( isNaN(this.quantity) ){
				error('Quantity is not a number.');
				this.quantity = 1;
			}
		}
				
		if( !this.price || this.price == null || this.price == 'undefined'){
			this.price=0.00;
			error('No price for item or price not properly formatted.');
		} else {
			this.price = ("" + this.price).replace(/,*/gi, "" );
			this.price = parseFloat( ("" + this.price).replace( /[^(\d|\.)]*/gi, "") ); 
			if( isNaN(this.price) ){
				error('Price is not a number.');
				this.price = 0.00;
			}
		}
	};
	
	
	CartItem.prototype.parseValuesFromArray = function( array ) {
		if( array && array.length && array.length > 0) {
			for(var x=0, xlen=array.length; x<xlen;x++ ){
			
				/* ensure the pair does not have key delimeters */
				array[x].replace(/||/, "| |");
				array[x].replace(/\+\+/, "+ +");
			
				/* split the pair and save the unescaped values to the item */
				var value = array[x].split('=');
				if( value.length>1 ){
					if( value.length>2 ){
						for(var j=2, jlen=value.length;j<jlen;j++){
							value[1] = value[1] + "=" + value[j];
						}
					}
					this[ unescape(value[0]).toLowerCase() ] = unescape(value[1]);
				}
			}
			return true;
		} else {
			return false;
		}
	};
	
	CartItem.prototype.remove = function() {
		simpleCart.remove(this.id);
		simpleCart.update();
	};
	


/********************************************************************************************************
 *			Shelf Object for managing items on shelf that can be added to cart
 ********************************************************************************************************/

function Shelf(){
	this.items = {};
}	
	Shelf.prototype.readPage = function () {
		this.items = {};
		var newItems = getElementsByClassName( "simpleCart_shelfItem" );
		for( var current in newItems ){
			var newItem = new ShelfItem();
			this.checkChildren( newItems[current] , newItem );
			this.items[newItem.id] = newItem;
		}
	};
	
	Shelf.prototype.checkChildren = function ( item , newItem) {
		
		for(var x=0;item.childNodes[x];x++){
			
			var node = item.childNodes[x];
			if( node.className && node.className.match(/item_[^ ]+/) ){
				
				var data = /item_[^ ]+/.exec(node.className)[0].split("_");
				
				if( data[1] == "add" || data[1] == "Add" ){
					var tempArray = [];
					tempArray.push( node );
					var addFunction = simpleCart.Shelf.addToCart(newItem.id);
					simpleCart.addEventToArray( tempArray , addFunction , "click");
					node.id = newItem.id;
				} else {
					newItem[data[1]]  = node;
				}
			}		
			if( node.childNodes[0] ){ 
				this.checkChildren( node , newItem );	
			}	
		}
	};
	
	Shelf.prototype.empty = function () {
		this.items = {};
	};
	
	
	Shelf.prototype.addToCart = function ( id ) {
		return function(){
			if( simpleCart.Shelf.items[id]){
				simpleCart.Shelf.items[id].addToCart();
			} else {
				error( "Shelf item with id of " + id + " does not exist.");
			}
		};
	};
	

/********************************************************************************************************
 *			Shelf Item Object
 ********************************************************************************************************/


function ShelfItem(){
	this.id = "s" + NextId++;
}	
	ShelfItem.prototype.remove = function () {
		simpleCart.Shelf.items[this.id] = null;
	};
	
	
	ShelfItem.prototype.addToCart = function () {
		var outStrings = [],valueString;
		for( var field in this ){
			if( typeof( this[field] ) != "function" && field != "id" ){
				valueString = "";
				
				switch(field){
					case "price":
						if( this[field].value ){
							valueString = this[field].value; 
						} else if( this[field].innerHTML ) {
							valueString = this[field].innerHTML;
						}
						/* remove all characters from price except digits and a period */
						valueString = valueString.replace( /[^(\d|\.)]*/gi , "" );
						valueString = valueString.replace( /,*/ , "" );
						break;
					case "image":
						valueString = this[field].src;
						break;
					default:
						if( this[field].value ){
							valueString = this[field].value; 
						} else if( this[field].innerHTML ) {
							valueString = this[field].innerHTML;
						} else if( this[field].src ){
							valueString = this[field].src;
						} else {
							valueString = this[field];
						}
						break;
				}
				outStrings.push( field + "=" + valueString );
			}
		}
		
		simpleCart.add( outStrings );
	};
	


/********************************************************************************************************
 * Thanks to Peter-Paul Koch for these cookie functions (http://www.quirksmode.org/js/cookies.html)
 ********************************************************************************************************/
function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}


//*************************************************************************************************
/*
	Developed by Robert Nyman, http://www.robertnyman.com
	Code/licensing: http://code.google.com/p/getelementsbyclassname/
*/	
var getElementsByClassName = function (className, tag, elm){
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
};


/********************************************************************************************************
 *  Helpers
 ********************************************************************************************************/


String.prototype.reverse=function(){return this.split("").reverse().join("");};
Number.prototype.withCommas=function(){var x=6,y=parseFloat(this).toFixed(2).toString().reverse();while(x<y.length){y=y.substring(0,x)+","+y.substring(x);x+=4;}return y.reverse();};
Number.prototype.toCurrency=function(){return(arguments[0]?arguments[0]:"$")+this.withCommas();};


/********************************************************************************************************
 * error management 
 ********************************************************************************************************/

function error( message ){
	try{ 
		console.log( message ); 
	}catch(err){ 
	//	alert( message );
	}
}

var simpleCart = new Cart();

if( typeof jQuery !== 'undefined' ) $(document).ready(function(){simpleCart.initialize();}); 
else if( typeof Prototype !== 'undefined') Event.observe( window, 'load', function(){simpleCart.initialize();});
else window.onload = simpleCart.initialize;

