/**
 * Basic Invite Javascript File
 *
 * This file contains all the master javascript code for Basic Invite. This file
 * defines classes which are responsible for managing the product page, the 
 * ordering process, the personalization process, and much more.
 *
 * @version 0.1 rev $Rev: 161 $
 * @date $Date: 2010-04-12 22:21:44 -0400 (Mon, 12 Apr 2010) $
 * @author Joshua Gitlin, Digital Fruition, LLC josh -at- digitalfruition.com
 * @copyright Basic Invite, LLC
 */

DFTools.namespace('com.basicinvite');

/**
 * Public Config
 *
 * Public configuration options such as CSS selectors, URLs, text strings, etc.
 */
com.basicinvite.config = {
	
	/**
	 * Is the Basic Invite system enabled? A master "on/off" switch.
	 *
	 */
	enabled: true,
	
	initialPrepopIndex: '0-1',
	
	minimum_quantity: 25,
	
	qtyInputObserverFrequency: 1.5,
	productFormObserverFrequency: 3,
	cartFormObserverFrequency: 1,
	
	/**
	 * Time limit, in seconds that an ajax Add To Cart request may take. Longer than this and an error will be displayed.
	 *
	 */
	addToCartTimeout: 40,
	
	debugAddToCart: false,
	
	haltAddToCartAfterChainedItems: false,
	
	addChainedItemsSimultaneously: true,
	
	default_pocket_color: 'Onyx',
	default_pocket_style: 'Syracuse',
	
	urls: {
		productStepsView:		'/yscene7/index/productsteps/',
		getPersonalizationData:	'/yscene7/index/getpersonalizations/',
		savePersonalizationData:'/yscene7/index/savepersonalizationdata/',
		ajaxAddToCart:			'/checkout/cart/ajaxadd/bihashid/'+Math.floor(Math.random()*11),
		cart:					'/checkout/cart/',
		deleteCartItem:			'/checkout/cart/delete/id/#{item_id}/uenc/aHR0cDovLzY3LjIyOC4yMzkuMTYxL2NoZWNrb3V0L2NhcnQvaW5kZXgv/',
		rushChargeProduct:		'/rush-processing.html/',
		upload:					'/yscene7/index/upload/',
		loadingIndicator: 		'/images/upload-loading.gif',
		emptyPhoto:				'/images/spacer.gif',
		checkoutComplete:		'/checkout/onepage/success/'
	},
	
	selectors: {
		productBox:				'div#main form#product_addtocart_form',
		productForm:			'form#product_addtocart_form',
		productStepsParent:		'div.product-shop',
		chainedItemsBox:		'div.BasicInvite.related-items',
		chainedItems:			'li div.product-images a',
		addToCartBox:			'div.product-info-box',
		productName:			'h3.product-name',
		productSteps:			'div.BasicInvite.productSteps',
		productPriceBox:		'div.price-box',
		productImageBox:		'div.product-img-box',
		mainProductImage:		'p.product-image',
		moreViews:				'div.more-views',
		productPriceContainer:	'.price_outer',
		productPriceDisplay:	'.price_outer .price',
		productOptionBoxes:		'.product-options',
		wordingBox:				'dl.wording',
		discountRow:			'ul.product-pricing li',
		cartTable:				'table#shopping-cart-table',
		cartLastDeleteLink:		'tbody tr:last-child td:last-child a'
	},
	
	colorPicker: {
			height:		375,
			width:		295
	},
	
	scene7: {
		prepop_param:			'prepop',
		default_size:			10,
		fonttable_param:		'$fonttbl',
		resetColorTable:		false,
		disableCache:			false,
		ugcUrl:					'http://s7w2p1.scene7.com/is/image/basicinvite/ugc/'
	},
	
	shipping: {
		methodCookieName: 'shipMethod'
	},
	
	upload: {
		file_size_limit: '100 MB',
		file_type_limit: '*.jpg;*.gif;*.png;*.psd',
		file_types_description: "Image Files (*.jpg;*.gif;*.png;*.psd)",
		
		uploadFailedMessage: "Sorry, an image could not be uploaded. #{message} (#{error})",
		
		button: {
			src: '/images/upload_btn_sprite.png',
			width:  "112",
			height: "22"
		}
	},
	
	strings: {
		tabs: {
			quantity: {
				qtyTextInput_label: '',
				qtyDropdown_label: '',
				qtyTextInputDropdownOrText: 'OR'
			},
			
			envelopes: {
				outerEnvelopeInstructions: '* Only square envelopes require extra postage.  Check with post office for rates.',
				innerEnvelopeInstructions: '* This envelope is optional as we only recommend double envelopes (inner and outer) if you will be ordering a Response Card, and one or more additional enclosure cards.',
				rapInstructions: '* Printed in black ink with matching font, on back flap of envelope.<span>Tips:<br />- Including a name is not necessary.<br />- Do not abbreviate.<br /></span>'
			},
			
			options: {
				addToCartLoadingText: 'Please Wait While We Add Your Order To The Shopping Cart',
				pocketInstructions: '*Assembly not included.'
			}
		},
		
		errors: {
			addToCartForm_requiredFieldsError: 'Please check to ensure all required fields were properly filled out',
			requiredFieldAdvice: 'This is a required field',
			photoTooSmall: 'This image is too small. The minimum resolution for this area is #{regionSize[0]}x#{regionSize[1]} pixels. '+
							'Your image was #{photo.size} pixels. Please upload a higher resolution. ',
			leaveCartPageDirty: 'You have made changes to the items in your cart. These changes will be lost unless you click "Apply".',
			checkoutWithCartPageDirty: 'We\'ve noticed you haven\'t applied some changes, do you wish to apply them now?',
			
			addProductAndChainedItemsSimultaneouslyError: 'We\'re very sorry, something went wrong while trying to add these items to your cart. '+
				'Please try to add the items to your cart again. If this error persists, please contact us. '
		},
		
		productInCart: {
			title:		'Item is already in cart',
			
			prompt:		'This item, #{product.name}, is already in your cart.' +
						'  Do you wish to: ',
			
			continueBtn:'<img src="/images/edit_item_btn.png" alt="Edit This Item">',
			cancelBtn:	'<img src="/images/continue_shopping_btn.png" alt="Cancel Edit and Continue Shopping">',
						
			layout:		'<div id="productInCartBox"><p>#{prompt}</p><ol><li>#{cancelBtn}</li><li>Or</li><li>#{continueBtn}</li></ol></div>',
			
			loadingText:'Please Wait...',
			
			height:			300,
			width:			400,
			overlayOpacity: 0.75
		},
		
		initialLoadingMessage: 'Please Wait...'
	}
};

com.basicinvite.Exception = Class.create(
{
	initialize: function(message)
	{
		this.message = message
	}
});

com.basicinvite.Exception.ProductInCart = Class.create(com.basicinvite.Exception,
{
	initialize: function($super)
	{
		$super("Product is already in cart");
	}
});

com.basicinvite.Utility = {
	generateProductOptionsPriceAndOpconfig: function(optionsPriceData,productOptionsData)
	{
		return function()
		{
			var optionsPrice, opConfig, myProductOptions;
			
			var newPrototype = {};
			$H(Product.Options.prototype).each(function(pair)
			{
				eval("newPrototype[pair.key] = "+pair.value.toString());
			});
			
			myProductOptions = Class.create(Product.Options,newPrototype);
			
			optionsPrice = new Product.OptionsPrice(optionsPriceData);
			
			opConfig = new myProductOptions(productOptionsData);
			
			return {
				opConfig: function(){ return opConfig; },
				optionsPrice: function(){ return optionsPrice;}
			};
		}();
	}
};

com.basicinvite.Tabs = Class.create(Control.Tabs,
{
	initialize: function($super,container,options)
	{
		this._step = 0;
		
		this.productStepsScale = 1;
		
		this.subtabs = $A([]);
		
		$super(container,options);
	},
	
	_hasNextSubtab: function()
	{
		var step = this.step();
		
		var subtabs = this.subtabs[step];
		
		return (subtabs && subtabs.links[subtabs.links.length-1] != subtabs.activeLink);
	},
	
	_hasPrevSubtab: function()
	{
		var step = this.step();
		
		var subtabs = this.subtabs[step];
		
		return (subtabs && subtabs.links[0] != subtabs.activeLink);
	},
	
	next: function($super)
	{
		if(this._hasNextSubtab())
		{
			DFTools.console.debug("com.basicinvite.Tabs#next called, we have subtabs, passing next along");
			
			return this.subtabs[this.step()].next();
		}
		
		return $super();
	},
	
	previous: function($super)
	{
		if(this._hasPrevSubtab())
		{
			DFTools.console.debug("com.basicinvite.Tabs#previous called, we have subtabs, passing prev along");
			
			var subtabs = this.subtabs[this.step()];
			result = subtabs.previous();
			var activeTab = subtabs.containers.get(subtabs.activeLink.key);
			DFTools.console.debug("sending afterChange event to",subtabs,"with",activeTab);
			subtabs.notify("afterChange", activeTab);
			
			return result;
		}
		
		return $super();
	},
	
	prev: function($super)
	{
		this.previous();
	},
	
	step: function()
	{
		var step = -1;
		
		try
		{
			return this.activeContainer.previousSiblings().length+1;
			
			var re = /.*#BasicInvite_step_(.*)/;
			
			var str = this.activeContainer.id;
			
			str = $(this.activeContainer).up('div.productSteps').down('ul li a.active').href;
			
			var m = str.match(re);
			
			DFTools.console.debug("com.basicinvite.ProductSteps#step: match array is:",m,"matched on:",str,this);
			
			step = parseInt(m[1]);
		}
		catch(ex)
		{
			DFTools.console.error("com.basicinvite.ProductSteps#step: caught an exception:",ex,this);
			
			step = -1;
		}
		
		return step;
	},
	
	_uiEventHandler: function(e)
	{

	},
	
	scale: function(perc)
	{
		DFTools.console.debug("Scaling productSteps from",this.productStepsScale,"to",perc);
		
		if(this.productStepsScale != perc)
		{
			new Effect.Scale($$('div.BasicInvite.productSteps')[0],(perc/this.productStepsScale) * 100,{
				scaleX:false,
				scaleY:true,
				scaleContent:false,
				duration: 0.75
			});
			
			this.productStepsScale = perc;
		}
	}
});

com.basicinvite.ProductSteps = Class.create(com.basicinvite.Tabs,
{
	next: function($super)
	{
		var step = this.step();
		
		var tab = $('BasicInvite_step_'+step);
		
		var subtabs = this.subtabs[step];
		
		if(this._hasNextSubtab() || (subtabs && subtabs._hasNextSubtab()))
		{
			DFTools.console.debug("com.basicinvite.ProductSteps#next called, we have subtabs, passing next along");
			
			return subtabs.next();
		}
		else
		{
			DFTools.console.debug("com.basicinvite.ProductSteps#next called, no subtabs, calling $super");
			
			if(step == 1 && !productAddToCartForm.validator.validate())
			{
				DFTools.console.log("com.basicinvite.ProductSteps#next called but productAddToCartForm failed validation.");
				
				return false;
			}
			
			var required_fields = tab.select('.required-entry');
			
			var field_errors = required_fields.collect($F).invoke('empty');
			
			if(field_errors.any())
			{
				DFTools.console.log("com.basicinvite.ProductSteps#next called but a required field was empty.");
				
				field_errors.each(function(isError,index)
				{
					if(isError)
					{
						new Effect.Highlight(required_fields[index]);
						required_fields[index].addClassName('validation-failed');
						var advice = Validation.getAdvice('cantBeEmpty',required_fields[index]);
						
						if(!advice)
							advice = Validation.createAdvice('cantBeEmpty',required_fields[index],false,com.basicinvite.config.strings.errors.requiredFieldAdvice);
						
						Validation.showAdvice(required_fields[index],advice,'cantBeEmpty');
					}
					else
					{
						required_fields[index].removeClassName('validation-failed');
					}
				});
			}
			else
			{
				return $super();
			}
		}
	},
	
	
	previous: function($super)
	{
		var step = this.step();
		
		var tab = $('BasicInvite_step_'+step);
		
		var subtabs = this.subtabs[step];
		
		if(this._hasPrevSubtab()|| (subtabs && subtabs._hasPrevSubtab()))
		{
			DFTools.console.debug("com.basicinvite.Tabs#previous called, we have subtabs, passing prev along");
			
			return this.subtabs[this.step()].previous();
		}
		
		return $super();
	}
})


com.basicinvite.ChainedItem = Class.create(
{
	initialize: function(options)
	{
		this._setOptions($H(options));
		
		this._loaded = false;
		
		this.index = com.basicinvite.ChainedItem.count++;
		
		if(this.autoload)
		{
			new PeriodicalExecuter((function(pe){
				if(com.basicinvite.ChainedItem.loadQueueSize <= 0)
				{
					pe.stop()
					this.load();
				}
			}).bind(this),2);
		}
	},
	
	defaultOptions: function()
	{
		return {
			url: 			'',
			autoload:		true,
			name:			'New Product',
			container:		false,
			tieredPricing:	true
		};
	},
	
	qty: function()
	{
		var qty = this._qty;
		
		if(isNaN(qty) || typeof(qty) == 'undefined')
			qty = 0;
		
		return qty;
	},
	
	id: function()
	{
		return this._id;
	},
	
	getOptions: function()
	{
		var opts = {};
		
		var matchRe = new RegExp('^options\\[(\\d+)\\]-'+this._id+'$')
		
		$H(Form.serializeElements(Form.getElements(this.form),true)).collect(function(pair)
		{
			var match = pair.key.match(matchRe);
			if(match && match[1])
				opts[match[1]] = pair.value;
		});
		
		return opts;
	},
	
	addToCart: function()
	{
		var qty = this.qty();
		
		if(qty)
		{
			params = Form.serializeElements(Form.getElements(this.form),true);
			
			params.qty = qty;
			
			new Ajax.Request(this.addToCartUrl,{
				asynchronous:true,
				parameters:params,
				evalJS: false,
				onSuccess: this._handleAddToCartSuccess.bind(this),
				onFailure: this._handleAddToCartFailure.bind(this)
			});
		}
		else
		{
			DFTools.console.log("Chained Item "+this.name+" not added to cart because the quantity was zero");
			this.fire('addToCart','Quantity was zero');
		}
	},
	
	load: function()
	{
		if(!this._loaded)
		{
			if(!this.url)
				throw new TypeError("com.basicinvite.ChainedItem.url property is undefined; cannot load");
			
			com.basicinvite.ChainedItem.loadQueueSize++;
			
			var r = $(this.url);
			
			this._handleLoadSuccess(r);
			
		}
	},
	
	loaded: function()
	{
		return this._loaded;
	},
	
	recalculatePrice: function()
	{
		var optionsPrice = 0;
		
		try
		{
			if(this._opConfig)
			{
				this._opConfig.opConfig().reloadPrice();
				optionsPrice = this._opConfig.optionsPrice().optionPrices.options;
			}
		}
		catch(err)
		{
			DFTools.console.error("com.basicinvite.ChainedItem#recalculatePrice caught an error while trying to determine Magento option pricing:",err);
			DFTools.console.log("Assuming an option price of $0.00...");
			optionsPrice = 0;
		}
		
		DFTools.console.debug("Chained item",this.name,"price for options is:",optionsPrice);
		
		this.total_price = (this.priceForQty(this._qty) + optionsPrice)*this._qty;
	},
	
	setQty: function(qty)
	{
		qty = parseInt(qty);
		
		if(isNaN(qty) || typeof(qty) == 'undefined')
			qty = 0;
		
		this._qty = qty;
		
		if(this._qtyEl)
			this._qtyEl.value = this.qty();
		
		var old_price = this.total_price;
		
		this.recalculatePrice();
		
		this.fire('priceChanged',this,old_price,this.total_price);
	},
	
	_setOptions: function(options)
	{
		var defaults = this.defaultOptions();
		
		$H(defaults).each(function(v){
			this[v.key] = (typeof(options.get(v.key)) == 'undefined') ? v.value : options.get(v.key);
		},this);
	},
	
	_extractProductOptionsPriceFromHtml: function(html)
	{
		var m = html.match(/^.*new Product\.OptionsPrice\((.*)\);\s*$/m);
		return m && m[1] ? m[1].evalJSON() : false;
	},
	
	_extractProductOptionsConfigFromHtml: function(html)
	{
		var m = html.match(/^.*new Product\.Options\((.*)\);\s*$/m);
		return m && m[1] ? m[1].evalJSON() : false;
	},
	
	_setupProductOptionsPriceAndOpconfig: function(html)
	{
		var optionsPriceData,productOptionsData;
		
		optionsPriceData = this._extractProductOptionsPriceFromHtml(html);
		DFTools.console.debug("options price data:",optionsPriceData);
		productOptionsData = this._extractProductOptionsConfigFromHtml(html);
		DFTools.console.debug("product options price data:",productOptionsData);
		
		this._opConfig = com.basicinvite.Utility.generateProductOptionsPriceAndOpconfig(optionsPriceData,productOptionsData);
	},
	
	priceForQty: function(n) { return 0; },
	
	_handleLoadSuccess: function(r)
	{
		DFTools.console.debug('Received a chained item AJAX response',r,this);
		
		try
		{
			var domNode = $(document.createElement('div')).hide();
			
			//domNode.innerHTML = r.responseText;
			domNode.innerHTML = r.innerHTML;
			
			var productDiv = domNode.down(com.basicinvite.config.selectors.productBox);
			
			var productForm = domNode.down(com.basicinvite.config.selectors.productForm);
			
			var img = false;
			
			var detailsList = false;
			
			if(productDiv)
			{
				DFTools.console.debug('found product div in chained item response');
			
				var nameEl = productDiv.down(com.basicinvite.config.selectors.productName);
				
				if(nameEl)
				{
					DFTools.console.debug('name el found');
					this.name = nameEl.innerHTML.replace(/^\s\s*/, '').replace(/\s\s*$/, '');;
				} else {
					DFTools.console.debug('name el not found');
				}
				
				img = productDiv.down('p.product-image img');
				
				detailsList = domNode.down('div.product-collateral ul');
			}
			
			if(productForm)
			{
				DFTools.console.debug("Found product form in chained item AJAX response");
				
				this.addToCartUrl = productForm.action;
				
				var chainForm = new Element('form',{action:productForm.action});
				
				chainForm = new Element('div').addClassName('chainedItemDetails');
				
				this.form = chainForm;
				
				this._id = $F(productForm['product']);
				
				this._qtyEl = productForm.down('input.qty');
				
				this._qtyEl.id += "-chainedItem-"+this.index;
				this._qtyEl.name = this._qtyEl.name + "-chainedItem-"+this.index;
				
				var qtyContainer = this._qtyEl.wrap('div').addClassName('chained-qty');
				
				this._qtySelect = new Element('select',{'class':'qty'});
				
				var discountList = productForm.select(com.basicinvite.config.selectors.discountRow);
				
				if(this.tieredPricing)
				{
					var prices = discountList.invoke('down','.price').pluck('innerHTML');
					var qtys = discountList.pluck('innerHTML').invoke('match',/Buy ([0-9]+) .*/).pluck(1);
					
					this._qtySelect.appendChild(new Element('option',{value:'0'}).update('--Select--'));
					this._qtySelect.appendChild(new Element('option',{value:'0'}).update('None'));
					
					qtys.zip(prices).each(function(qtyPrice)
					{
						var qty=parseInt(qtyPrice[0]);
						var price = parseFloat(qtyPrice[1].replace('$',''));
						var price_total = price*qty;
						price_total = price_total.numberFormat('$#,###.##');
						this._qtySelect.appendChild(new Element('option',{value:qtyPrice[0]}).update(qtyPrice[0]+' @ '+price_total));
					},this);
					
					qtyContainer.appendChild(new Element('label',{'for':this._qtyEl.identify()}).update('OR'));
					qtyContainer.appendChild(this._qtySelect);
					
					this.priceForQty = function(q)
					{
						for(var i = 0; i < qtys.length && parseFloat(qtys[i]) <= q; ++i);
						
						i = Math.max(i-1,0);
						
						DFTools.console.debug("found price to be index:",i,qtys,prices);
						
						return parseFloat(prices[i].replace('$',''));
					}
					
					this._qtySelect.observe('change',function()
					{
						var qty = parseInt($F(this._qtySelect));
						
						this.setQty(qty);
					}.bind(this));
				}
				else
				{
					var price = productForm.down('div.price-box span.price').innerHTML;
					
					price = parseFloat(price.replace('$',''));
					
					this.priceForQty = function(q)
					{
						return price;
					}
				}
				
				var qtyElChangeHandler = function()
				{
					var qty = parseInt($F(this._qtyEl));
					
					if($F(this._qtyEl) == '')
					{
						this.setQty(qty);
						this._qtyEl.value = '';
						return false;
					}
					if(isNaN(qty))
					{
						this._qtyEl.value = '0';
						return false;
					}
					
					this.setQty(qty);
				}.bind(this);
				
				var optionsChangeHandler = function()
				{
					var old_price = this.total_price;
					
					this.recalculatePrice();
					
					if(this.total_price != old_price)
						this.fire('priceChanged',this,old_price,this.total_price);
				}.bind(this);
				
				this._qtyEl.observe('change',qtyElChangeHandler);
				
				new Form.Element.Observer(this._qtyEl, com.basicinvite.config.qtyInputObserverFrequency, qtyElChangeHandler);
				
				//this._setupProductOptionsPriceAndOpconfig(r.responseText);
				this._setupProductOptionsPriceAndOpconfig(r.innerHTML);
				
				this.setQty(0);
				
				var megentoProductOptionsBoxes = productForm.select(com.basicinvite.config.selectors.productOptionBoxes);
				
				if(megentoProductOptionsBoxes.length)
				{
					this._magentoProductOptionsList = megentoProductOptionsBoxes[0].down('dl');
					
					DFTools.console.debug("Found chained item options list:",this._magentoProductOptionsList);
					
					this._magentoProductOptionsList.insert({top: qtyContainer.wrap('dd')});
					this._magentoProductOptionsList.insert({top: new Element('label').update('Quantity:').wrap('dt')});
					
					this.form.appendChild(this._magentoProductOptionsList.wrap('div').addClassName('options'));
					
					Form.getElements(this.form).without(this._qtyEl,this._qtySelect).each(function(formItem)
					{
						formItem.name += "-"+this._id;
						formItem.observe('change',optionsChangeHandler);
					},this);
					
					this._magentoProductOptionsList.select('dd ul.options-list').invoke('down','li input').each(function(radio){
						radio.checked = true;
					})
				}
				else
				{
					this.form.appendChild(qtyContainer);
				}
			}
			
			if(this.container)
			{
				this.container.addClassName('chainedItem');
				this.container.appendChild(this.form);
				
				
				if(img)
				{
					DFTools.console.debug("container - img");
					img.src = img.src.replace('$ProductDetails$','$ChainedItem$');
					this.container.appendChild(img.wrap('div').addClassName('chainedItemImage'));
				}
				
				//this.container.appendChild(new Element('input',{type:'checkbox',name:'chained'}));
				
				var myCssName = this.name.replace(/[^A-Za-z0-9 ]/g,'-');
				
				this.form.insert({top:new Element('h3').addClassName('product-name '+myCssName).update(this.name)});
				
				if(this.form)
					this.container.appendChild(this.form);
				
				if(img && this.container.down('h3.product-name.Traditional.Pocket'))
				{
					// This is a traditional pocket invitation and needs image swapping
					
					DFTools.console.debug("traditional pocket - sub");
					var optionSelects = this._magentoProductOptionsList.select('select');
					
					var pocketStyleSelect = optionSelects[1];
					var pocketColorSelect = optionSelects[2];
					
					var onPocketOptionChange = function()
					{
						var style,color;
						
						style = pocketStyleSelect.selectedIndex;
						color = pocketColorSelect.selectedIndex;
						
						style = style ? pocketStyleSelect.options[style].innerHTML : com.basicinvite.config.default_pocket_style;
						style = style.match(/([^+]*)(\+.*)?/)[1].trim();
						
						color = color ? pocketColorSelect.options[color].innerHTML : com.basicinvite.config.default_pocket_color;
						color = color.match(/([^+]*)(\+.*)?/)[1].trim();
						
						img.src = 'http://s7d5.scene7.com/is/image/basicinvite/'+style+' - '+color+'?$EnvelopeChoice$';
					}
					
					$A(pocketColorSelect.options).each(function (option){
						if(/.*\+\$[0-9]+/.test(option.innerHTML))
							option.innerHTML+=' ea.';
					});
					
					onPocketOptionChange();
					
					pocketStyleSelect.observe('change',onPocketOptionChange).observe('df:change',onPocketOptionChange);
					pocketColorSelect.observe('change',onPocketOptionChange).observe('df:change',onPocketOptionChange);
					
					this.form.appendChild(new Element('div').addClassName('instructions').update(
						com.basicinvite.config.strings.tabs.options.pocketInstructions));
					
					// Add a class for this image
					if (img) {
						if (img.up('div')) {
							img.up('div').addClassName('pocket');
						} else {
							imgdiv = this.container.down('div.chainedItemImage');
							imgdiv.addClassName('pocket');
						}
					}
					
				}
				else if(img && this.container.down('h3.product-name.Square.Pocket'))
				{
					// This is a square pocket invitation and needs image swapping
					
					DFTools.console.debug("square pocket - sub");
					
					var optionSelects = this._magentoProductOptionsList.select('select');
					var pocketColorSelect = optionSelects[1];
					
					var onPocketOptionChange = function()
					{
						var color;
						
						color = pocketColorSelect.selectedIndex;
						color = color ? pocketColorSelect.options[color].innerHTML : com.basicinvite.config.default_pocket_color;
						color = color.match(/([^+]*)(\+.*)?/)[1].trim();
						
						img.src = 'http://s7d5.scene7.com/is/image/basicinvite/Sabino - '+color+'?$EnvelopeChoice$';
					}
					
					$A(pocketColorSelect.options).each(function (option){
						if(/.*\+\$[0-9]+/.test(option.innerHTML))
							option.innerHTML+=' ea.';
					});
					
					onPocketOptionChange();
					
					pocketColorSelect.observe('change',onPocketOptionChange).observe('df:change',onPocketOptionChange);
					
					this.form.appendChild(new Element('div').addClassName('instructions').update(
						com.basicinvite.config.strings.tabs.options.pocketInstructions));
					
					// Add a class for this image
					if (img) {
						if (img.up('div')) {
							img.up('div').addClassName('pocket');
						} else {
							imgdiv = this.container.down('div.chainedItemImage');
							imgdiv.addClassName('pocket');
						}
					}
					
				}
				
				if(detailsList)
				{
					this.form.insert(Element.wrap(detailsList,'div').addClassName('attributes'));
				}
			}
			
			this._loaded = true;
			
			DFTools.console.debug('Loaded a chained item',this.name,this);
			
			domNode.innerHTML = '';
			
			delete domNode;
			
			$$('.yui-ac-content').each(function(d,i){ if(i) d.remove(); });
			
			DFTools.console.debug("about to fire load");
			
			this.fire('load');
		}
		catch(err)
		{
			DFTools.console.error('com.basicinvite.ChainedItem#_handleLoadSuccess caught an error:',err,r,this);
		}
		
		com.basicinvite.ChainedItem.loadQueueSize--;
	},
	
	_handleAddToCartSuccess: function(r)
	{
		DFTools.console.log("Chained Item "+this.name+" added to cart successfully. Parsing response...");
		
		try
		{
			var domNode = $(document.createElement('div')).hide();
			
			domNode.innerHTML = r.responseText;
			
			var delLink = domNode.down(com.basicinvite.config.selectors.cartTable).down(com.basicinvite.config.selectors.cartLastDeleteLink);
			
			DFTools.console.debug('Found the delete URL to be',delLink.href,this);
			
			var cartItem = new com.basicinvite.CartItem({
				id: this.id(),
				name: this.name,
				remove_url: delLink,
				details_url: this.url
			});
			
			BasicInvite.addCartItem(cartItem);
			
			domNode.innerHTML = '';
			
			delete domNode;
			
			$$('.yui-ac-content').each(function(d,i){ if(i) d.remove(); });
		}
		catch(err)
		{
			DFTools.console.error('com.basicinvite.ChainedItem#_handleAddToCartSuccess caught an error:',err,r,this);
		}
		
		this.fire('addToCart',r);
	},
	
	_handleAddToCartFailure: function(r,e)
	{
		DFTools.console.error("Caught an exception while adding ChainedItem "+this.name+" to cart");
		DFTools.console.log("Requester:",r,"Exception:",e);
	}
});
com.basicinvite.ChainedItem.addMethods(com.digitalfruition.Std.EventListener);
com.basicinvite.ChainedItem.count = 0;
com.basicinvite.ChainedItem.loadQueueSize = 0;


com.basicinvite.CartItem = Class.create(
{
	initialize: function(data)
	{
		this._setOptions($H(data));
		
	},
	
	defaultOptions: function()
	{
		return {
			id:				0,
			details_url: 	'',
			remove_url:		'',
			name:			''
		};
	},
	
	_setOptions: function(options)
	{
		var defaults = this.defaultOptions();
		
		$H(defaults).each(function(v){
			this[v.key] = (typeof(options.get(v.key)) == 'undefined') ? v.value : options.get(v.key);
		},this);
	},
	
	remove: function(callback)
	{
		new Ajax.Request(this.remove_url,{
			asynchronous:true,
			method:		'get',
			evalJS:		false,
			onSuccess:	this._handleRemoveSuccess.bind(this)
		});
	},
	
	_handleRemoveSuccess: function(r)
	{
		DFTools.console.log("Remove Cart item AJAX request successful. Parsing response...");
		
		try
		{
			var domNode = $(document.createElement('div')).hide();
			
		}
		catch(err)
		{
			DFTools.console.error('com.basicinvite.CartItem#_handleRemoveSuccess caught an error:',err,r,this);
		}
		
		this.fire('remove',r);
	},
	
	_handleRemoveFailure: function(r,e)
	{
		DFTools.console.log("Caught an exception while removing CartItem "+this.name,this);
		DFTools.console.log("Requester:",r,"Exception:",e);
	}
});
com.basicinvite.ChainedItem.addMethods(com.digitalfruition.Std.EventListener);

com.basicinvite.PersonalizerController = Class.create(
{
	initialize: function(options)
	{
		this._setOptions($H(options));
	},
	
	defaultOptions: function()
	{
		return {
			url: 		'',
			autoload:	true,
			name:		'New Product',
			container:	false
		};
	},
	
	_setOptions: function(options)
	{
		var defaults = this.defaultOptions();
		
		$H(defaults).each(function(v){
			this[v.key] = (typeof(options.get(v.key)) == 'undefined') ? v.value : options.get(v.key);
		},this);
	}
});
com.basicinvite.PersonalizerController.addMethods(com.digitalfruition.Std.EventListener);

BasicInvite = function()
{
	/**
	 * Public BasicInvite members
	 *
	 * This object will be returned and accesable to other scripts on the page. It
	 * contains the public and privileged members of the class.
	 * @return value
	 */
	var BasicInvite = { };
	
	BasicInvite.MODE_DISABLED = 'disabled';
	BasicInvite.MODE_PRODUCTPAGE = 'productPage';
	BasicInvite.MODE_CARTPAGE = 'checkoutPage';
	BasicInvite.MODE_CHECKOUTPAGE = 'checkoutPage';
	BasicInvite.MODE_UNKNOWN = 'unknown';
	
	
	/*** Private Variables_________________________________________________________ ***/
	var myMode = BasicInvite.MODE_UNKNOWN;
	
	BasicInvite.myProductId = 0;
	
	BasicInvite.myElements = {
		productPageContainer:	false,
		productForm:			false,
		productStepsContainer:	false,
		ChainedItemsContainer:	false,
		magentoAddToCartBox:	false,
		qtyInput:				false,
		qtySelect:				false
	};
	
	BasicInvite.myControls = {};
	
	BasicInvite.myPersonalizationDataRestored = false;
	
	BasicInvite.myPersonalizationData = {
		sides: $H(),
		product_id: 0,
		cartItems: $A(),
		dirty: false
	};
	
	BasicInvite.savedFormData = {};
	
	BasicInvite.myShippingData = {};
	
	BasicInvite.myFulfillmentDates = ['',''];
	
	BasicInvite.myPersonalizationDataLoaded = false;
	
	BasicInvite.tmp_src_holder = '';
	
	BasicInvite.TheRegion = {
		text: '',
		lines: $A()
	};

	var myRushChargeProduct= false;
	
	BasicInvite.myScene7State = {
		activeSide: -1
	}
	
	var myProductStepBox = {
		currentStep: 0
	}
	
	var myProductQty = 100;
	
	var myProductPrice = {
		perPiece: 0,
		shipping: 0,
		total: 0,
		elements: $H()
	}
	
	var myWordingCategories = $A();
	var myWording = $A();
	
	var myAddToCartWatcher = false;
	var myChainedItems = $A();
	var myLoadingChainedItems = $A();
	
	/*** Private Methods___________________________________________________________ ***/
	
	var mySavePersonalizationData = function(callback)
	{
		if(BasicInvite.myPersonalizationData.dirty)
		{
			BasicInvite.myPersonalizationData.dirty = false;
			
			new Ajax.Request(com.basicinvite.config.urls.savePersonalizationData,{
				method: 'post',
				parameters: {
					asynchronous:true,
					product_id: BasicInvite.myProductId,
					qty: myProductQty,
					data: $H(BasicInvite.myPersonalizationData).toJSON()
				},
				onSuccess: function(){ if(typeof(callback) == 'function') { callback(); } }
			});
		}
	}
	
	var myPeriodicallySaveData = new PeriodicalExecuter(mySavePersonalizationData,0.5);
	
	var myUpdateProductPrice = function()
	{
		myProductPrice.elements.set('options',optionsPrice.optionPrices.options);
		
		DFTools.console.debug("myUpdateProductPrice: myProductPrice.elements: ",myProductPrice.elements);
		
		myProductPrice.total = myProductPrice.elements.inject(0,function(acc,pair){return acc + pair.value*myProductQty;});
		
		myProductPrice.total += myProductPrice.shipping;
		
		DFTools.console.debug("myUpdateProductPrice: myChainedItems: ",myChainedItems);
		
		myProductPrice.total += myChainedItems.pluck('total_price').inject(0,function(acc,v){DFTools.console.debug("myUpdateProductPrice: myChainedItems:  function: ",acc,v);return acc + v;});
		
		DFTools.console.debug("myUpdateProductPrice: price is: ",myProductPrice.total,"for a quantity of:",myProductQty);
		
		if(isNaN(myProductPrice.total))
			return;
		
		var price = myProductPrice.total.numberFormat('$#,###.##');
		
		BasicInvite.myElements.productPageContainer.select(com.basicinvite.config.selectors.productPriceDisplay).invoke('update',price);
	}
	
	/**
	 * Handler for chained item price changes
	 *
	 * This function takes care of updating the total price when a chained item's price changes.
	 *
	 * @return void
	 */
	var myChainedItemPriceChangeHandler = function(event,item,old_price,new_price)
	{
		DFTools.console.debug("myChainedItemPriceChangeHandler called with:",arguments);
		
		var item_index = myChainedItems.indexOf(item);
		
		myUpdateProductPrice();
	}
	
	/**
	 * Handler for chained item data loading
	 *
	 * This function potsprocesses chained items with private data from the BasicInvite object,
	 * like the form data from myPersonalizationData.formData
	 *
	 * @return void
	 */
	var myChainedItemLoadHandler = function()
	{
		var tmp_last_ci_name = '';
		
		if(!BasicInvite.myPersonalizationDataLoaded)
		{
			DFTools.console.debug("myChainedItemLoadHandler called but personalization data not loaded, defer 0.1 sec...");
			myChainedItemLoadHandler.bind(this).delay(0.1);
			return -1;
		}
		
		myLoadingChainedItems = myLoadingChainedItems.without(this);
		
		if(!myLoadingChainedItems.length)
		{
			BasicInvite.myElements.productStepsContainer.select('div.chaineditems div.loading').invoke('hide');
		}
		
		if(BasicInvite.savedFormData)
		{
			DFTools.console.debug("myChainedItemLoadHandler is filling in old form data for a chained item...",this);
			
			var saveThis = this;
			
			Form.getElements(this.form).each(function(formEl)
			{
				try
				{
					var val;
					
					if(formEl.tagName)
					{
						var tag = formEl.tagName + '';
						tag = tag.toLowerCase();
						
						if (!formEl.name) {
							if (tag == 'select') {
								val = BasicInvite.savedFormData[tmp_last_ci_name];
								saveThis.setQty(val);
							} else {
								return;
							}
						} else {
							val = BasicInvite.savedFormData[formEl.name];
						}
					
						tmp_last_ci_name = formEl.name;
						
						DFTools.console.debug("myChainedItemLoadHandler: checking a chainedItem val: ",formEl.name,val,BasicInvite.savedFormData);
						//DFTools.console.debug('myChainedItemLoadHandler: control info: ',formEl.class,formEl.type);
						
						if(!val)
							return;
						
						DFTools.console.debug("myChainedItemLoadHandler: Restoring a chainedItem: ",tag,val);
						
						switch(tag)
						{
							case 'textarea':
								if(BrowserDetect.browser == "Explorer") formEl.innerText = val;
								else formEl.update(val.replace('&','&amp;'));
								break;
							
							case 'select':		var index = $A(formEl.options).pluck('value').indexOf(val);
												DFTools.console.debug("index is: "+index);
												formEl.selectedIndex = Math.max(index,0);
												break;
							
							case 'radio':		formEl.checked = (formEl.value == val);
							
							default:	formEl.value = val; break;
						}
						
					}
					else if(formEl.length)
					{
						val = BasicInvite.savedFormData[formEl[0].name];
						
						if(!val)
							return;
						
						$A(formEl).each(function(theFormEl)
						{
							if(theFormEl.type && theFormEl.type.toLowerCase() == 'radio' && theFormEl.value == val)
							{
								theFormEl.checked = true;
							}
						});
					}
				}
				catch(field_ex)
				{
					DFTools.console.error("ChainedItem failed to restore field for ",formEl,this,"because:",field_ex);
				}
			});
		}
	}
	
	/**
	 * Create a ChainedItem from a url
	 *
	 * DESCRIPTION
	 * @return value
	 */
	var myCreateChainedItemFromUrl = function(url)
	{
		DFTools.console.debug("myCreateChainedItemFromUrl",url);
		var container = new Element('div');
		
		var item = new com.basicinvite.ChainedItem({
			url: url,
			autoload: true,
			container: container
		});
		
		item.observe('load',myChainedItemLoadHandler).observe('priceChanged',myChainedItemPriceChangeHandler);
		
		myChainedItems.push(item);
		myLoadingChainedItems.push(item);
	};

	var myLoadRushChargeProduct = function()
	{
		var container = new Element('div').hide();
		
		myRushChargeProduct = new com.basicinvite.ChainedItem({
			url: com.basicinvite.config.urls.rushChargeProduct,
			autoload: true,
			container: container,
			tieredPricing: false
		});
		
		myChainedItems.push(myRushChargeProduct);
		
		// after rush charge we now fire the other chained items
		if(BasicInvite.myElements.ChainedItemsContainer)
		{
			DFTools.console.debug("Found the chained items container:",BasicInvite.myElements.ChainedItemsContainer);
			
			// if we found a chained item container, hide it...
			BasicInvite.myElements.ChainedItemsContainer.hide();
			// and now extract the the chained item URLs
			var chainedItemUrls = BasicInvite.myElements.ChainedItemsContainer.select(com.basicinvite.config.selectors.chainedItems).pluck('href');
			
			// for each chained item, fetch and store in memory the chained item page
			chainedItemUrls.each(myCreateChainedItemFromUrl);
		}
	};
	
	var myAddToCartLoadingIndicator = false;
	
	var myAddChainedItemsToCartInSerial = function(cb)
	{
		var completed = $A();
		
		var currentItem = 0;
		
		var onAdded = function(){ completed.push(this); if(++currentItem < myChainedItems.length) myChainedItems[currentItem].addToCart(); };
		
		myAddToCartWatcher = new PeriodicalExecuter(function(pe){
			if(completed.length == myChainedItems.length)
			{
				DFTools.console.log("myAddToCartWatcher: All chained items successfully added to cart...");
				
				pe.stop();
				
				cb();
			}
		},0.5);
		
		myChainedItems.invoke('observe','addToCart',onAdded);
		myChainedItems[0].addToCart();
	}
	
	var myAddProductAndChainedItemsSimultaneouslyTries = 0;
	
	var myAddProductAndChainedItemsSimultaneously = function(cb)
	{
		DFTools.console.debug("myAddProductAndChainedItemsSimultaneously called()");
		
		var products = $A();
		
		var opts = {};
		
		var matchRe = new RegExp('^options\\[(\\d+)\\]$')
		
		$H(BasicInvite.myElements.productForm.serialize(true)).collect(function(pair)
		{
			var match = pair.key.match(matchRe);
			if(match && match[1])
				opts[match[1]] = pair.value;
		});
		
		products.push({
		  id: BasicInvite.myProductId,
		  qty: myProductQty,
		  options: opts
		});
		
		myChainedItems.each(function(i)
		{
			var qty = i.qty();
			
			if(qty)
			{
				products.push({
					qty: qty,
					id: i.id(),
					options: i.getOptions()
				});
			}
		});
		
		var failureTimeout;
		
		var handleFailure = function(r,e)
		{
			DFTools.console.error("myAddProductAndChainedItemsSimultaneously: Error while adding items to cart...",r,e);
			
			if(myAddProductAndChainedItemsSimultaneouslyTries < 3)
			{
				DFTools.console.log("This was attempt #",myAddProductAndChainedItemsSimultaneouslyTries,"trying again.");
				window.clearTimeout(failureTimeout);
				myAddProductAndChainedItemsSimultaneously(cb);
				
			}
			else
			{
				DFTools.console.log("This was attempt #",myAddProductAndChainedItemsSimultaneouslyTries,"giving up.");
				
				alert(com.basicinvite.config.strings.errors.addProductAndChainedItemsSimultaneouslyError);
				
				$$('div.DFThemeObject-LoadingIndicator.BIAddToCartLoading').invoke('hide');
				
				window.clearTimeout(failureTimeout);
			}
		}
		
		failureTimeout = handleFailure.delay(com.basicinvite.config.addToCartTimeout);
		
		var handleSuccess = function(r)
		{
			DFTools.console.log("myAddProductAndChainedItemsSimultaneously: All items successfully added to cart...");
			try
			{
				DFTools.console.debug("Response JSON was: ",r.responseJSON);
				
				window.clearTimeout(failureTimeout);
				
				if(!r.responseJSON.success)
					throw new Error("Server returned a failure");
				
				myPeriodicallySaveData.stop();
				
				BasicInvite.myPersonalizationData.cartItems = $A();
				
				$A(r.responseJSON.cart).each(function(cartItem)
				{
					BasicInvite.addCartItem(
						new com.basicinvite.CartItem({
							name: cartItem.name,
							id: cartItem.product_id,
							remove_url: com.basicinvite.config.urls.deleteCartItem.interpolate(cartItem)
						})
					);
				});
				
				new Ajax.Request('/checkout/cart/',{
					asynchronous:true,
					onSuccess:cb
				});
			}
			catch(err)
			{
				handleFailure(r,err);
			}
		}
		
		DFTools.console.log("myAddProductAndChainedItemsSimultaneously: submitting AJAX request to: "+com.basicinvite.config.urls.ajaxAddToCart);
		
		postData = BasicInvite.myElements.productForm.serialize(true);
		postData.dfChainedProductsJSON = products.toJSON();
		
		myAddProductAndChainedItemsSimultaneouslyTries++;
		
		new Ajax.Request(com.basicinvite.config.urls.ajaxAddToCart,{
			asynchronous:true,
			method: 'post',
			parameters: { products: products.toJSON() },
			onSuccess: handleSuccess,
			onFailure: handleFailure
		});
	};
	
	var myAddChainedItemsSimultaneously = function(cb)
	{
		var products = $A();
		
		myChainedItems.each(function(i)
		{
			var qty = i.qty();
			
			if(qty)
			{
				products.push({
					qty: qty,
					id: i.id(),
					options: i.getOptions()
				});
			}
		});
		
		var handleFailure = function(r,e)
		{
			DFTools.console.error("myAddChainedItemsSimultaneously: Error while adding items to cart...",r,e);
		}
		
		var handleSuccess = function(r)
		{
			DFTools.console.log("myAddChainedItemsSimultaneously: All chained items successfully added to cart...");
			try
			{
				DFTools.console.debug("Response JSON was: ",r.responseJSON);
				
				if(!r.responseJSON.success)
					throw new Error("Server returned a failure");
				
				BasicInvite.myPersonalizationData.cartItems = $A();
				
				$A(r.responseJSON.cart).each(function(cartItem)
				{
					BasicInvite.addCartItem(
						new com.basicinvite.CartItem({
							name: cartItem.name,
							id: cartItem.product_id,
							remove_url: com.basicinvite.config.urls.deleteCartItem.interpolate(cartItem)
						})
					);
				});
				
				cb(r);
			}
			catch(err)
			{
				handleFailure(r,err);
			}
		}
		
		new Ajax.Request(com.basicinvite.config.urls.ajaxAddToCart,{
			asynchronous:true,
			method: 'post',
			parameters: {
				products: products.toJSON()
			},
			onSuccess: handleSuccess,
			onFailure: handleFailure
		});
	};
	
	
	var myProductFormSubmitHandler = function(e)
	{
		var userError = {userError: true, message: ''};
		
		try
		{
			DFTools.console.log("myProductFormSubmitHandler called for event:",e);
			
			var l = new com.digitalfruition.ThemeObject.LoadingIndicator({
				el: $('body'),
				text: com.basicinvite.config.strings.tabs.options.addToCartLoadingText,
				cssClass: 'BIAddToCartLoading'
			});
			
			var required_fields = BasicInvite.myElements.addToCartForm.select('.required-entry');
			
			var field_errors = required_fields.collect($F).invoke('empty');
			
			if(field_errors.any())
			{
				if(field_errors.collect(function(isError,index)
				{
					if(isError && required_fields[index].up('div.chainedItem'))
					{
						if($F(required_fields[index].up('div.chainedItem').down('div.chained-qty input')) == "0")
						{
							required_fields[index].removeClassName('validation-failed');
							return false;
						}
					}
					
					if(isError)
					{
						new Effect.Highlight(required_fields[index]);
						required_fields[index].removeClassName('validation-passed').addClassName('validation-failed');
						required_fields[index].scrollTo();
						
						var advice = Validation.getAdvice('cantBeEmpty',required_fields[index]);
						
						if(!advice)
							advice = Validation.createAdvice('cantBeEmpty',required_fields[index],false,com.basicinvite.config.strings.errors.requiredFieldAdvice);
						
						Validation.showAdvice(required_fields[index],advice,'cantBeEmpty');
						
						return true;
					}
					else
					{
						required_fields[index].removeClassName('validation-failed');
						return false;
					}
				}).any()) {
					userError.message = com.basicinvite.config.strings.errors.addToCartForm_requiredFieldsError;
					throw userError;
				}
			}
			
			l.show();
			
			var addChainedItemsSuccess = function(r)
			{
				try
				{
					DFTools.console.log("BasicInvite#myProductFormSubmitHandler onAddChainedItemsSuccess called; readyState=#{readyState}; status=#{status}; statusText=#{statusText}; ".interpolate(r));
					
					if(com.basicinvite.config.debugAddToCart)
					{
						DFTools.console.log("myAddToCartWatcher is halting because com.basicinvite.config.debugAddToCart is set");
						
						var debugTextarea = $('debugAddToCart').down('textarea');
						
						debugTextarea.innerText += "myProductFormSubmitHandler Ajax responseText: \n"+r.responseText+"\n\n----------------------------------\n\n";
						debugTextarea.innerText += "DFTools.console log: \n"+DFTools.console.getLog()+"\n\n----------------------------------\n\n";
						debugTextarea.innerText += "DFTools.console debug log: \n"+DFTools.console.getDebugLog()+"\n\n----------------------------------\n\n";
						
						alert('Please copy the debug text and send to a developer');
						
						l.hide();
						return false;
					}
					
					if(com.basicinvite.config.haltAddToCartAfterChainedItems)
					{
						DFTools.console.log("myAddToCartWatcher is halting because haltAddToCartAfterChainedItems is set");
						if(!confirm('go to cart?'))
						{
							l.hide();
							return false;
						}
					}
					
					var redir = function()
					{
						window.location = com.basicinvite.config.urls.cart;
					};
					
					mySavePersonalizationData(redir);
					redir.delay(10);
				}
				catch(addChainedItemsSuccessEx)
				{
					DFTools.console.error("onComplete caught an exception: ",addChainedItemsSuccessEx);
					alert('Sorry, an error occurred: '+addChainedItemsSuccessEx);
				}
			}
			
			var productAddToCartSuccess = function(r)
			{
				try
				{
					DFTools.console.log("BasicInvite#myProductFormSubmitHandler productAddToCartSuccess called; readyState=#{readyState}; status=#{status}; statusText=#{statusText};".interpolate(r));
					
					if(com.basicinvite.config.debugAddToCart)
					{
						var debugTextarea = $('debugAddToCart').down('textarea');
						
						debugTextarea.innerText += "productAddToCartSuccess Ajax responseText: \n"+r.responseText+"\n\n----------------------------------\n\n";
					}
					
					if(com.basicinvite.config.addChainedItemsSimultaneously)
						myAddChainedItemsSimultaneously(addChainedItemsSuccess);
					else
						myOldAddChainedItemsToCart(addChainedItemsSuccess);
				}
				catch(productAddToCartSuccessEx)
				{
					DFTools.console.error("productAddToCartSuccess caught an exception: ",productAddToCartSuccessEx);
					alert('Sorry, an error occurred: '+productAddToCartSuccessEx);
				}
			}
			
			DFTools.console.log("BasicInvite#myProductFormSubmitHandler Ajax POST to: "+BasicInvite.myElements.productForm.action);
			
			if(com.basicinvite.config.debugAddToCart)
			{
				var debugTextarea = new Element('div',{id:'debugAddToCart'});
				
				document.body.appendChild(debugTextarea);
				
				debugTextarea.appendChild(new Element('textarea'));
				
				debugTextarea = debugTextarea.down();
				
				debugTextarea.update("Please send the following debugging info to a developer: \n\n");
				debugTextarea.innerText += "Product Add to cart POSTDATA: \n"+BasicInvite.myElements.productForm.serialize(false)+"\n\n----------------------------------\n\n";
			}
			
			myAddProductAndChainedItemsSimultaneously(addChainedItemsSuccess);

		}
		catch(err)
		{
			DFTools.console.error("myProductFormSubmitHandler caught an error:",err);
			
			if(err === userError)
			{
				alert(err.message);
			}
			
			l.hide();
		}
		
		e.stop();
		
	}.bindAsEventListener(BasicInvite);
	
	BasicInvite.myUpdateWordingMenus = function(update_menus)
	{
		var wordingOptionsHtml = myWordingCategories.inject('<option value="-1">--Select--</option>',function(html,category,categoryIndex){  
			
			var optgroup = myWording[categoryIndex].inject('<optgroup label="'+category+'">',function(acc,c,n){
				var val = categoryIndex+'-'+n;
				var sel = (val == com.basicinvite.config.initialPrepopIndex) ? ' selected' : '';
				return acc+'<option value="'+val+'"'+sel+'>&nbsp;&nbsp;&nbsp;'+c.label+'</option>';
			});
			
			return html+optgroup+'</optgroup>';
		});
		
		if(typeof update_menus == 'undefined' || update_menus)
			$$('select.wording').invoke('update',wordingOptionsHtml).invoke('fire','df:change');
		else
			$$('select.wording').invoke('update',wordingOptionsHtml);
	}
	
	/**
	 * Handler for myLoadWording() ajax call
	 *
	 * DESCRIPTION
	 * @return value
	 */
	var myLoadWordingSuccess = function()
	{
		DFTools.console.debug('myLoadWordingSuccess:');
		
		var domNode = $('wording-success');
		
		var wordingBox = domNode.down(com.basicinvite.config.selectors.wordingBox);
		
		myWordingCategories = $A();
		myWording = $A();
		
		wordingBox.select('dt').each(function(dt){
			var categoryLabel = dt.innerHTML;
			
			var categoryIndex = myWordingCategories.push(categoryLabel) - 1;
			myWording[categoryIndex] = $A();
			
			dt.next().select('div.wording_samples').each(function(wording){
				var wordingLabel = wording.down('span').innerHTML;
				var wording = wording.down('p').innerHTML.split(/\n?\<br\/?>\n?/i);
				
				wording = wording.invoke('trim');
				
				myWording[categoryIndex].push({label: wordingLabel, lines: wording});
				
				DFTools.console.debug("Found wording:",categoryLabel,wordingLabel,wording);
			});
		});
		
		domNode.innerHTML = '';
		
		delete domNode;
		
		$$('.yui-ac-content').each(function(d,i){ if(i) d.remove(); });
		
		DFTools.console.log('Loaded wording choices');
		
		BasicInvite.myUpdateWordingMenus();
	};
	
	var mySuspendWordingMenuChangeEvents = false;
	
	BasicInvite.myWordingMenuChangeHandler = function(e)
	{
		var el = e.element();
		
		var val = $F(el).split('-');
		
		DFTools.console.debug("myWordingMenuChangeHandler called; event:",e,"element:",el,"val:",val);
		
		if(mySuspendWordingMenuChangeEvents)
		{
			DFTools.console.debug("Taking no action because mySuspendWordingMenuChangeEvents is set");
			return -1;
		}
		
		var wordingCategory = parseInt(val[0]);
		var wordingIndex = parseInt(val[1]);
		
		var wording = myWording[wordingCategory][wordingIndex];
		
		el.up('div.inner').select('textarea').each(function(input,n){
			var theLine = wording.lines[n] ? wording.lines[n] : ' '
			input.value = theLine;
			input.update(theLine).fire('df:change');
		});
	};
	
	/**
	 * Set up the quantity box and menu, and make sure that as they change, the prices are updated
	 *
	 * @access private
	 * @return void
	 */
	var mySetupQuantityDiscountBox = function(container)
	{
		if(BasicInvite.myElements.magentoAddToCartBox)
		{
			var qtyInput = BasicInvite.myElements.magentoAddToCartBox.down('input.qty');
		
			if(!qtyInput)	throw new Error('Could not locate the quantity box');
			
			container.appendChild(new Element('label',{'for':qtyInput.identify()}).update(com.basicinvite.config.strings.tabs.quantity.qtyTextInput_label));
			container.appendChild(qtyInput);
			
			DFTools.console.log("myProductQty: ",myProductQty);
			
			qtyInput.value = myProductQty;
			
			DFTools.console.log("qtyinputval: ",qtyInput.value);
			
			var discountList = BasicInvite.myElements.productPageContainer.select(com.basicinvite.config.selectors.discountRow);
		
			if(discountList.length)
			{
				DFTools.console.debug("mySetupQuantityDiscountBox found a discountList:",discountList);
				
				var qtySelect = new Element('select',{'id':'qtySelectMenu'});
				
				var prices = discountList.invoke('down','.price').pluck('innerHTML');
				var qtys = discountList.pluck('innerHTML').invoke('match',/Buy ([0-9]+) .*/).pluck(1);
				
				qtySelect.appendChild(new Element('option',{value:'-'}).update('--Select--'));
				
				qtys.zip(prices).each(function(qtyPrice)
				{
					var qty=parseInt(qtyPrice[0]);
					var price = parseFloat(qtyPrice[1].replace('$',''));
					var price_total = price*qty;
					price_ea = price.numberFormat('$#,###.##');
					price_total = price_total.numberFormat('$#,###.##');
					qtySelect.appendChild(new Element('option',{value:qtyPrice[0]}).update(qtyPrice[0]+' @ '+price_total+' &nbsp;&nbsp;('+price_ea+' ea.)'));
				});
				
				container.appendChild(new Element('span').addClassName('qtyOrText').update(com.basicinvite.config.strings.tabs.quantity.qtyTextInputDropdownOrText));
				container.appendChild(new Element('label',{'for':'qtySelectMenu'}).update(com.basicinvite.config.strings.tabs.quantity.qtyDropdown_label));
				container.appendChild(qtySelect);
				
				BasicInvite.priceForQty = function(q)
				{
					for(var i = 0; i < qtys.length && parseFloat(qtys[i]) <= q; ++i);
					
					i = Math.max(i-1,0);
					
					DFTools.console.debug("found price to be index:",i,qtys,prices);
					
					return parseFloat(prices[i].replace('$',''));
				}
				
				qtySelect.selectedIndex = 4;
				
				qtySelect.observe('change',function()
				{
					var qty = $F(qtySelect);
					
					qtyInput.value = qty;
					
					myProductQty = parseInt(qty)
					
					myProductPrice.elements.set('product',BasicInvite.priceForQty(myProductQty));
					
					myUpdateProductPrice();
				});
				
				var qtyInputChangeHandler = function(validate)
				{
					var qty = $F(qtyInput);
					
					qty = (parseInt(qty));
					
					if(qty < com.basicinvite.config.minimum_quantity)
					{
						qty = com.basicinvite.config.minimum_quantity;
						if(validate)
							qtyInput.value = qty;
					}
					
					myProductQty = qty;
					
					myProductPrice.elements.set('product',BasicInvite.priceForQty(myProductQty));
					
					myUpdateProductPrice();
				};
				
				qtyInput.observe('change',qtyInputChangeHandler.curry(true));
				
				new Form.Element.Observer(qtyInput, com.basicinvite.config.qtyInputObserverFrequency, qtyInputChangeHandler.curry(false));
				
				myProductQty = parseInt($F(qtyInput)) || 100;
				
				myProductPrice.elements.set('product',BasicInvite.priceForQty(myProductQty));
				
				myUpdateProductPrice();
				
				opConfig.reloadPrice = opConfig.reloadPrice.wrap(function(orig){
					orig();
					BasicInvite.refreshPrice();
				});
			}
			
			DFTools.console.log("qtyinputval: ",qtyInput.value);
		}
		else
		{
			DFTools.console.error("Could not set up quantity boxes because myElements.magentoAddToCartBox is undefined.");
		}
	};
	
	var mySetupShippingControlDiv = function(container)
	{
		try
		{
			var rushContainer = container.down('div.rush');
			var rushMenu = rushContainer.down('select');
			
			var selectedShippingMethod = '';
			var selectedShippingMethodPrice = 0;
			
			myLoadRushChargeProduct();
			
			var updateShippingPrice = function()
			{
				var rushCharge = parseInt($F(rushMenu));
				
				DFTools.console.debug("rush val found: ",rushCharge);
				
				myProductPrice.shipping = selectedShippingMethodPrice;
				container.select('span.date').invoke('update',BasicInvite.myFulfillmentDates[rushMenu.selectedIndex]);
				
				if(rushCharge)
				{
					if(myRushChargeProduct)
						myRushChargeProduct.setQty(1);
				}
				else
				{
					if(myRushChargeProduct) {
						myRushChargeProduct.setQty(0);
					}
				}
				
				myUpdateProductPrice();
			}
			
			rushMenu.observe('change',updateShippingPrice);
			
			//if (BasicInvite.savedFormData) {
						
			//	DFTools.console.debug("rush saved data: ",BasicInvite.savedFormData);
				
			//	if (BasicInvite.savedFormData['qty-chainedItem-0'] == '1') {
			//		rushMenu.selectedIndex = 1;
					
			//	} 
				
			//} 
			
			updateShippingPrice();
		}
		catch (ex)
		{
			DFTools.console.error("mySetupShippingControlDiv caught an error:",ex.message,ex);
		}
	}
	
	var mySetupPapertypeSelect = function(container)
	{
		var paperTypeLabelRegexp = /Paper Choice.*/; 
		
		var paperTypeLabel = $$('label').find(function(e){return paperTypeLabelRegexp.test(e.innerHTML);});
		
		if(paperTypeLabel)
		{
			DFTools.console.debug("Found paper type label: ",paperTypeLabel);
			
			var paperType = paperTypeLabel.up('dt');
			
			paperType.hide();
			
			paperType = paperType.next('dd');
			
			var sel = paperType.down('select');
			
			sel.selectedIndex=1;
			container.appendChild(sel);
		}
		else
		{
			DFTools.console.error("Could not set up quantity boxes because we couldn't find the paper type label.")
		}
	};
	
	var myAddEnvelopeImages = function(container)
	{
		var envelopeLabelRegexp = /Envelope Choice.*/;
		
		var envelopeLabel = container.select('label').find(function(e){return envelopeLabelRegexp.test(e.innerHTML);});
		
		if(envelopeLabel)
		{
			DFTools.console.debug("Found outer envelope label: ",envelopeLabel);
			
			var outerEnvelopeOptionsContainer = envelopeLabel.up('dt').next('dd');
			
			outerEnvelopeOptionsContainer.addClassName('envelope');
			var outerEnvelopeRadios = outerEnvelopeOptionsContainer.select('input');
			
			outerEnvelopeRadios[0].checked = true;
			
			var outerEnveloperImg = new Element('img');
			
			var onOuterEnvelopeChange = function()
			{
				var index = Math.max(outerEnvelopeRadios.pluck('checked').indexOf(true),0);
				var envelopeName = outerEnvelopeRadios[index].next().down('label').innerHTML;
				envelopeName = envelopeName.match(/([^<]*)( <.*)?/)[1].trim();
				outerEnveloperImg.src = 'http://s7d5.scene7.com/is/image/basicinvite/'+envelopeName.replace('6.5','6').replace(' ','-')+'?$EnvelopeChoice$';
			}
			
			onOuterEnvelopeChange();
			onOuterEnvelopeChange.delay(4);
			
			outerEnvelopeRadios.invoke('observe','click',onOuterEnvelopeChange).invoke('observe','df:change',onOuterEnvelopeChange);
			
			envelopeLabel.up('dt').insert({top:outerEnveloperImg.wrap('div').addClassName('envelope')});
			
			envelopeLabel.up('dt').next('dd').insert(new Element('p').addClassName('envelope_instructions').update(
				com.basicinvite.config.strings.tabs.envelopes.outerEnvelopeInstructions));
		}
		else
		{
			DFTools.console.error("Could not set up outer envelope choices")
		}
		
		envelopeLabelRegexp = /Double Envelope.*/;
		
		envelopeLabel = container.select('label').find(function(e){return envelopeLabelRegexp.test(e.innerHTML);});
		
		if(envelopeLabel)
		{
			DFTools.console.debug("Found inner envelope label: ",envelopeLabel);
			
			var innerEnvelopeOptionsContainer = envelopeLabel.up('dt').next('dd');
			
			innerEnvelopeOptionsContainer.addClassName('envelope');
			var innerEnvelopeRadios = innerEnvelopeOptionsContainer.select('input');
			
			innerEnvelopeRadios[0].checked = true;
			
			var innerEnveloperImg = new Element('img');
			
			var onInnerEnvelopeChange = function()
			{
				var index = Math.max(innerEnvelopeRadios.pluck('checked').indexOf(true),1)
				var envelopeName = innerEnvelopeRadios[index].next().down('label').innerHTML;
				envelopeName = envelopeName.match(/([^<]*)( <.*)?/)[1].trim();
				innerEnveloperImg.src = 'http://s7d5.scene7.com/is/image/basicinvite/'+envelopeName.replace('6.5','6').replace(' ','-')+'?$EnvelopeChoice$';
			}
			
			onInnerEnvelopeChange();
			onInnerEnvelopeChange.delay(4);
			
			innerEnvelopeRadios.invoke('observe','click',onInnerEnvelopeChange).invoke('observe','df:change',onInnerEnvelopeChange);
			
			envelopeLabel.up('dt').insert({top:innerEnveloperImg.wrap('div').addClassName('envelope')});
			
			envelopeLabel.up('dt').next('dd').insert(new Element('p').addClassName('envelope_instructions').update(
				com.basicinvite.config.strings.tabs.envelopes.innerEnvelopeInstructions));
		}
		else
		{
			DFTools.console.error("Could not set up inner envelope choices")
		}
		
		
		rapRegexp = /Add Return Address Printing.*/;
		
		rapLabel = container.select('label').find(function(e){return rapRegexp.test(e.innerHTML);});
		
		if(rapLabel)
		{
			DFTools.console.debug("Found rap label: ",rapLabel);
			
			var rapContainer = rapLabel.up('dt').next('dd');
			
			rapContainer.insert(new Element('p').addClassName('rap_instructions').update(
				com.basicinvite.config.strings.tabs.envelopes.rapInstructions));
		}
		else
		{
			DFTools.console.log("Could not set up rap box because we didn't find a rap label.")
		}
	}
	
	var mySetupScene7UrlOptionBox = function(container)
	{

	};
	
	var mySetupScene7UrlCartBox = function()
	{
		var s7UrlLabelRegexp = /s7PreviewUrl/;
		
		$$('label').findAll(function(e){return s7UrlLabelRegexp.test(e.innerHTML);}).each(function(s7UrlLabel)
		{
			DFTools.console.debug("Found scene 7 URL label: ",s7UrlLabel);
			
			var s7Url = s7UrlLabel.up('dt');
			
			s7Url.hide();
			
			s7Url = s7Url.next('dd');
			
			s7Url.hide();
			
			s7UrlLabel.up('tr').down('td img').src = $F(s7UrlLabel.up('dt').next('dd').down('input'))
		});
	};
	
	var myInsertProductOptionsInto = function(div,option)
	{
		if(typeof(option) == 'undefined')
		{
			BasicInvite.myElements.megentoProductOptionsBoxes.each(myInsertProductOptionsInto.curry(div));
		}
		else
		{
			div.appendChild(option.down('dl'));
		}
	};
	
	BasicInvite.myRedrawTabsBox = function()
	{
		$$('.product-info-box_outer').invoke('hide').invoke('setStyle',{display:'block'});
	}
	
	BasicInvite.myWireProductStepsView = function()
	{
		DFTools.console.log("myWireProductStepsView() started");
		
		try
		{
			
			BasicInvite.myElements.productStepsContainer = BasicInvite.myElements.productPageContainer.down(com.basicinvite.config.selectors.productSteps);
			
			var ul_box = $('ul_tabs_ps');
			
			if(BasicInvite.myElements.productStepsContainer)
			{
				var beforeTabChange = function(old_container)
				{
					var userError = {};
					
					try
					{
						if(old_container)
						{
							var required_fields = old_container.select('.required-entry');
							
							var field_errors = required_fields.collect($F).invoke('empty');
							
							if(field_errors.any())
							{
								if(field_errors.collect(function(isError,index)
								{
									if(isError && required_fields[index].up('div.chainedItem'))
									{
										if($F(required_fields[index].up('div.chainedItem').down('div.chained-qty input')) == "0")
										{
											required_fields[index].removeClassName('validation-failed');
											return false;
										}
									}
									
									if(isError)
									{
										new Effect.Highlight(required_fields[index]);
										required_fields[index].removeClassName('validation-passed').addClassName('validation-failed');
										required_fields[index].scrollTo();
										
										DFTools.console.debug("required field not filled out",required_fields[index]);
										
										var advice = Validation.getAdvice('cantBeEmpty',required_fields[index]);
										
										if(!advice)
											advice = Validation.createAdvice('cantBeEmpty',required_fields[index],false,com.basicinvite.config.strings.errors.requiredFieldAdvice);
										
										Validation.showAdvice(required_fields[index],advice,'cantBeEmpty');
										
										return true;
									}
									else
									{
										required_fields[index].removeClassName('validation-failed');
										return false;
									}
								}).any()) {
									userError.message = com.basicinvite.config.strings.errors.addToCartForm_requiredFieldsError;
									throw userError;
								}
							}
						}
					}
					catch(beforeTabChangeError)
					{
						DFTools.console.error("ProductSteps beforeTabChange caught an exception:",beforeTabChangeError);
						
						if(beforeTabChangeError === userError)
							throw $break;
					}
				};
				
				var afterTabChange = function(new_container)
				{
					try
					{
						DFTools.console.debug("myWireProductStepsView afterTabChange");
						
						var step = this.step(); 
						
						DFTools.console.log("Advanced to step",step,this);
						
						BasicInvite.myRedrawTabsBox();
						
						if(step == 1)
						{
							if(false && BasicInvite.myElements.personalizedImage)
							{
								BasicInvite.myElements.personalizedImage.hide();
								BasicInvite.myElements.productImage.show();
								
								if(BasicInvite.myElements.moreViews)
									BasicInvite.myElements.moreViews.show();
							}
							
							$$(com.basicinvite.config.selectors.productPriceContainer).invoke('setStyle',{visibility: 'visible'});

						}
						else if(step == 2)
						{
							if(BasicInvite.myElements.personalizedImage)
							{
								BasicInvite.myElements.personalizedImage.show();
							}
							
							$$(com.basicinvite.config.selectors.productPriceContainer).invoke('setStyle',{visibility: 'hidden'});

						}
						else if(step == 3)
						{
							$$(com.basicinvite.config.selectors.productPriceContainer).invoke('setStyle',{visibility: 'visible'});
						}
						else if(step == 4)
						{
							$$(com.basicinvite.config.selectors.productPriceContainer).invoke('setStyle',{visibility: 'visible'});
						}
					}
					catch(afterTabChangeError)
					{
						DFTools.console.error("ProductSteps afterTabChange caught an exception:",afterTabChangeError);
					}
				};
				
				DFTools.console.debug("Creating product steps system");
				
				BasicInvite.productStepBox = new com.basicinvite.ProductSteps(ul_box,{
					afterChange: afterTabChange,
					beforeChange: beforeTabChange
				});
				
				if(BasicInvite.side_tabs)
				{
					DFTools.console.debug("Setting product steps subtabs to:",BasicInvite.side_tabs);
					BasicInvite.productStepBox.subtabs[2] = BasicInvite.side_tabs;
				}
				else
				{
					DFTools.console.debug("Couldn't set product steps subtabs!");
				}
				
				BasicInvite.myElements.productStepsContainer.select('a.prev').invoke('observe','click',function(e){
					BasicInvite.productStepBox.prev();
					Event.stop(e);
				});
				
				BasicInvite.myElements.productStepsContainer.select('a.next').invoke('observe','click',function(e){
					BasicInvite.productStepBox.next();
					Event.stop(e);
				});
				
				// Load all the product information in:
				BasicInvite.myElements.productStepsContainer.select('div.product').each(function(div)
				{
					var className = $w(div.className).without('product')[0];
					
					switch(className)
					{
						case 'quantity':
							DFTools.console.debug("Found QUANTITY control container:",div,", calling mySetupQuantityDiscountBox()");
							mySetupQuantityDiscountBox(div); break;
						
						case 'papertype':
							DFTools.console.debug("Found PAPERTYPE control container:",div,", calling mySetupPapertypeSelect()");
							mySetupPapertypeSelect(div); break;
						
						case 'shipping':
							DFTools.console.debug("Found SHIPPING control container:",div,", calling mySetupPapertypeSelect()");
							mySetupShippingControlDiv(div); break;
							
						case 'scene7':
							
							DFTools.console.debug("Found Scene7 controls container:",div,", appending controls:",BasicInvite.myElements.personalizationControls);
							div.appendChild(BasicInvite.myElements.personalizationControls);
						
							BasicInvite.myElements.personalizationControls.show();
							
							break;
						
						case 'options':
							if(BasicInvite.myElements.magentoProductOptionsList)
							{
								DFTools.console.debug("Found options container:",div,", appending options:",BasicInvite.myElements.magentoProductOptionsList);

								div.appendChild(BasicInvite.myElements.magentoProductOptionsList);
								
								myAddEnvelopeImages(div);
							}
							else
							{
								DFTools.console.debug("Found options container:",div,", but couldn't find options to append!");
							}
							break;
						
						case 'chaineditems':
							//(function(){
								DFTools.console.log("Found chained items container, appending ",myChainedItems.length,"chained items to it");
								myChainedItems.pluck('container').each(function(c){div.appendChild(c);});
							//}).delay(2);
							break;
							
						case 'addtocart':
							var link = new Element('a',{href:'#'}).update('<img src="/skin/frontend/default/basic_invite/images/Add_To_Cart_Button.png" alt="Add To Cart" />');
							link.observe('click',myProductFormSubmitHandler);
							div.appendChild(link);
							break;
					}
				});
				
				mySetupScene7UrlOptionBox();
				
				var priceUpdater = {
					runs: 1,
					pe: false,
					update: function()
					{
						if(this.runs>0)
						{
							opConfig.reloadPrice();
							
							myUpdateProductPrice();
							
							this.runs--;
						}
					}
				}
				
				priceUpdater.update = priceUpdater.update.bind(priceUpdater);
				
				priceUpdater.pe = new PeriodicalExecuter(priceUpdater.update,0.5);
				
				var formChangeHandler = function()
				{
					priceUpdater.runs++;
					
					BasicInvite.myPersonalizationData.formData = BasicInvite.myElements.productForm.serialize(true);
					BasicInvite.myPersonalizationData.dirty = true;
				};
				
				var formKeypressHandler = function(event)
				{
					var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
					
					var el = event.element();
					
					if (keyCode == 13)
					{
						if(el && el.tagName && el.tagName.toLowerCase() == 'textarea' && !(el.up('#BasicInvite_step_2')))
							return false;
						
						DFTools.console.log("formKeypressHandler caught a keypress 13 (enter), disabling event.");
						event.stop();
					}
					
					if(el.up('div#BasicInvite_step_2'))
					{
						// This was a keypress in the design tab -- doesn't affect price. Ignore!
						return false;
					}
					
					priceUpdater.runs++;
				};
				
				BasicInvite.myElements.productForm.getElements().invoke('observe','keypress',formKeypressHandler);
				
				new Form.Observer(BasicInvite.myElements.productForm, com.basicinvite.config.productFormObserverFrequency, formChangeHandler);
				
				BasicInvite.myElements.productForm.setStyle({display:''});
				
				if(BasicInvite.myPersonalizationData.formData)
				{
					DFTools.console.debug("myWireProductStepsView is filling in old form data...");
					
					$H(BasicInvite.myPersonalizationData.formData).each(function(pair){
						var formEl = BasicInvite.myElements.productForm[pair.key];
						
						if(!formEl)
							return;
						
						if(BrowserDetect.browser == "Explorer" && pair.key == "qty" && formEl.length)
							formEl = formEl[0];
						
						if(formEl.tagName)
						{
							var tag = formEl.tagName + '';
							tag = tag.toLowerCase();
							DFTools.console.debug("Restoring a: "+tag+' key: '+pair.key+' val: '+pair.value);
							
							switch(tag)
							{
								case 'textarea':
									if(BrowserDetect.browser == "Explorer") formEl.innerText = pair.value;
									else formEl.update(pair.value.replace('&','&amp;'));
									break;
								
								case 'select':		formEl.selectedIndex = $A(formEl.options).pluck('value').indexOf(pair.value);
								
								default:	formEl.value = pair.value; break;
							}
							
							if (pair.key == 'qty') {
								var s_el_menu = $('qtySelectMenu');
								
								if (parseInt(pair.value) % 25 === 0) {
									s_el_menu.selectedIndex = $A(s_el_menu.options).pluck('value').indexOf(pair.value);	
								}
							
							}
						}
						else if(formEl.length)
						{
							DFTools.console.debug("found an element array");
							
							$A(formEl).each(function(theFormEl)
							{
								if(theFormEl.type && theFormEl.type.toLowerCase() == 'radio' && theFormEl.value == pair.value)
								{
									theFormEl.checked = true;
								}
							})
						}
					});
				}
				
				BasicInvite.myPersonalizationDataLoaded = true;
				
				DFTools.console.debug("myWireProductStepsView() is finished");
			}
		}
		catch (ex)
		{	
			DFTools.console.error("myWireProductStepsView caught an exception and cannot continue:",ex.message,ex);
			DFTools.console.log("Product steps boxes will probably not be fully functional.");
		}
	};
	
	var mySetupProductPage = function()
	{
		// Hide the standard Add To Cart form:
		
		DFTools.console.debug('in mySetupProductPage()');
		
		BasicInvite.myElements.megentoProductOptionsBoxes = BasicInvite.myElements.productPageContainer.select(com.basicinvite.config.selectors.productOptionBoxes);
		
		if(BasicInvite.myElements.magentoAddToCartBox)
		{
			var productStepsView = $$(com.basicinvite.config.selectors.productSteps);
			
			if(productStepsView.length == 1)
			{
				DFTools.console.debug('found a product steps view:',productStepsView);
				
				productStepsView = productStepsView[0];
				
				BasicInvite.myElements.magentoAddToCartBox.hide();
				
				BasicInvite.myElements.magentoAddToCartBox.next().insert({before:productStepsView});
				
				productStepsView.show();
				
				BasicInvite.myElements.magentoProductOptionsList = BasicInvite.myElements.megentoProductOptionsBoxes[0].down('dl');
			}
		}
		else if (BasicInvite.myElements.megentoProductOptionsBoxes.length)
		{
			BasicInvite.myElements.megentoProductOptionsBoxes.invoke('hide');
			
			BasicInvite.myElements.magentoProductOptionsList = BasicInvite.myElements.megentoProductOptionsBoxes[0].down('dl');
			
			BasicInvite.myElements.megentoProductOptionsBottom = BasicInvite.myElements.productPageContainer.down('div.product-options-bottom');
			
			if(!BasicInvite.myElements.megentoProductOptionsBottom)
				throw new Error("Fixme: Found product options but not add to cart; add case to mySetupProductpage()");
			
			BasicInvite.myElements.megentoProductOptionsBottom.hide();
			
			new Ajax.Updater(BasicInvite.myElements.megentoProductOptionsBottom,com.basicinvite.config.urls.productStepsView,{
				insertion: 	'after',
				onComplete:	BasicInvite.myWireProductStepsView
			});
		}
	};
	
	var myGenerateScene7ImageUrl = function(side_data)
	{
		var newsrc = side_data.image_src;
		
		if (newsrc.indexOf('is/agm') != -1) {
			newsrc = newsrc + side_data.parameters.toQueryString().replace(/%24/g,'$');

			newsrc = newsrc.replace(/layer%3D([0-9]+)%26op_colorize%3D=([0-9A-Fa-f]{6})/g,'layer=$1&op_colorize=$2');
		
			newsrc = newsrc.replace(/UgCf-([0-9]+)-([0-9]+)-([0-9]+)?/g,'is{basicinvite/ugc/$1.tif}');
			
			// Fix for the color table, if there is one
			if(com.basicinvite.config.resetColorTable)
			{
				newsrc += '&$ct=';
			}
			
			newsrc += '&wid=430&fmt=png';
			
			DFTools.console.log("Setting image src to: ",newsrc);
			
		} else {
			newsrc = newsrc + side_data.parameters.toQueryString().replace(/%24/g,'$');

			newsrc = newsrc.replace(/layer%3D([0-9]+)%26op_colorize%3D=([0-9A-Fa-f]{6})/g,'layer=$1&op_colorize=$2');
		
			newsrc = newsrc.replace(/UgCf-([0-9]+)-([0-9]+)-([0-9]+)?/g,'{ugc-file:$1?wid=$2%26hei=$3%26fit=crop}');
			
			// Fix for the color table, if there is one
			if(com.basicinvite.config.resetColorTable)
			{
				newsrc += '&$ct=';
			}
			
			newsrc += '&$ProductDetails$';
		}
		
		
		if(com.basicinvite.config.scene7.disableCache)
		{
			newsrc += '&cache=off';
		}
		
		return newsrc;
	}
	
	var myGenerateScene7ImageUrlFXG = function(side_data)
	{
		var newsrc = side_data.image_src;

		newsrc = newsrc.replace(/layer%3D([0-9]+)%26op_colorize%3D=([0-9A-Fa-f]{6})/g,'layer=$1&op_colorize=$2');
	
		newsrc = newsrc.replace(/UgCf-([0-9]+)-([0-9]+)-([0-9]+)?/g,'is{basicinvite/ugc/$1.tif}');
		
		// Fix for the color table, if there is one
		if(com.basicinvite.config.resetColorTable)
		{
			newsrc += '&$ct=';
		}
		
		newsrc += '&wid=430&fmt=png';
		
		DFTools.console.log("Setting image src to: ",newsrc);
		
		if(com.basicinvite.config.scene7.disableCache)
		{
			newsrc += '&cache=off';
		}
		
		return newsrc;
	}
	
	BasicInvite.myRefreshScene7Image = function(rebuild)
	{

		var side = BasicInvite.myPersonalizationData.sides.get(BasicInvite.myScene7State.activeSide);
		
		if (side.image_src.indexOf('is/agm') != -1) {
			/* we need to loop through each panel and make sure we include all possible parameters in our url string */
			BasicInvite.tmp_src_holder = myGenerateScene7ImageUrlFXG(side);
			
			BasicInvite.myPersonalizationData.sides.each(function(pair) {
				
				BasicInvite.tmp_src_holder = BasicInvite.tmp_src_holder + '&';
				BasicInvite.tmp_src_holder = BasicInvite.tmp_src_holder + pair.value.parameters.toQueryString().replace(/%24/g,'$');
				
				if(BasicInvite.myElements.scene7PreviewUrlInput) {
					BasicInvite.myElements.scene7PreviewUrlInput.value = BasicInvite.tmp_src_holder;
				}
						
            });
			
			var newsrc = BasicInvite.tmp_src_holder;
			newsrc = newsrc.replace(/UgCf-([0-9]+)-([0-9]+)-([0-9]+)?/g,'is{basicinvite/ugc/$1.tif}');

			if(rebuild)
			{
				if(BasicInvite.myElements.personalizedImage.down('img'))
					BasicInvite.myElements.personalizedImage.down('img').remove();
				
				BasicInvite.myElements.personalizedImage.appendChild(new Element('img',{src: newsrc}));
			}
			else
			{
				DFTools.console.debug("Setting image src to: ",newsrc);
				if (side.width) {	
					BasicInvite.myElements.personalizedImage.setStyle({position:'relative',width:side.width+'px', height:side.height+'px'});
		
					BasicInvite.myElements.personalizedImage.down('img').setStyle({position:'absolute',top:'0px',left:'0px',width:side.width+'px'});
				} else {
					BasicInvite.myElements.personalizedImage.setStyle({position:'relative',width:'auto', height:'auto'});
					BasicInvite.myElements.personalizedImage.down('img').setStyle({width:'auto', height:'auto'});
				}
				BasicInvite.myElements.personalizedImage.down('img').src = newsrc;
				DFTools.console.debug("Image src is now: ",BasicInvite.myElements.personalizedImage.down('img').src);
			}
			
		
		} else {
			var newsrc = myGenerateScene7ImageUrl(side);
			
			newsrc = newsrc.replace('$fonttbl=%7B%0C0%20', '$fonttbl=%7B%5Cf0%20');
			
			if(rebuild)
			{
				if(BasicInvite.myElements.personalizedImage.down('img'))
					BasicInvite.myElements.personalizedImage.down('img').remove();
				
				BasicInvite.myElements.personalizedImage.appendChild(new Element('img',{src: newsrc}));
			}
			else
			{
				DFTools.console.debug("Setting image src to: ",newsrc);
				if (side.width) {	
					BasicInvite.myElements.personalizedImage.setStyle({position:'relative',width:side.width+'px', height:side.height+'px'});
		
					BasicInvite.myElements.personalizedImage.down('img').setStyle({position:'absolute',top:'0px',left:'0px',width:side.width+'px'});
				} else {
					BasicInvite.myElements.personalizedImage.setStyle({position:'relative',width:'auto', height:'auto'});
					BasicInvite.myElements.personalizedImage.down('img').setStyle({width:'auto', height:'auto'});
				}
				BasicInvite.myElements.personalizedImage.down('img').src = newsrc;
				DFTools.console.debug("Image src is now: ",BasicInvite.myElements.personalizedImage.down('img').src);
			}
			if(BasicInvite.myElements.scene7PreviewUrlInput)
				BasicInvite.myElements.scene7PreviewUrlInput.value = newsrc;
		}
		
		
		
		if (side.width) {	
			
			BasicInvite.myElements.personalizedImage.setStyle({position:'relative',width:side.width+'px', height:side.height+'px'});
			var thetop = Number(side.top);
			var toptop = thetop-10;
			var theleft = Number(side.left);
			var thebottom = Number(side.height) + thetop;
			var theright = Number(side.width) + theleft;
			var widthwidth = side.width-10;
			//alert(toptop);
			
			if (toptop < 0) {
				toptop = 0;
			}
			
			BasicInvite.myElements.personalizedImage.down('img').setStyle({position:'absolute',top:'-'+toptop+'px',left:'-'+theleft+'px',width:widthwidth+'px',clip:'rect('+thetop+'px '+theright+'px '+thebottom+'px '+theleft+'px)'});
		} else {
			BasicInvite.myElements.personalizedImage.setStyle({position:'relative',width:'auto', height:'auto'});
			BasicInvite.myElements.personalizedImage.down('img').setStyle({width:'auto', height:'auto'});
		}
		
		
	}
	
	BasicInvite.myPersonalizationControlChangeHandler = function(e)
	{
		DFTools.console.debug("myPersonalizationControlChangeHandler fired; event:",e);
		
		try
		{
		
			var el = e.element();
			
			if(el.up('div#cp_custom_color_box'))
			{
				DFTools.console.debug("Change was inside the color picker -- ignoring!");
				return true;
			}
			
			DFTools.console.debug("element was:",el);
			
			if(/^\$|^layer/.test(el.name) || el.up('div').hasClassName('instructions'))
			{
				var side = BasicInvite.myPersonalizationData.sides.get(BasicInvite.myScene7State.activeSide);
				
				var val = $F(el);
				
				if(val == '')
					val = '  ';
				
				var sizeMenu = el.up('tr');
				
				if(sizeMenu && (sizeMenu = sizeMenu.down('td.size select')) && !el.hasClassName('font'))
				{
					var size = parseInt($F(sizeMenu))*2;
					
					if(size)
						val = '{\\fs'+size+' '+val+'}';
				}
				
				if(side.parameters.get(el.name) != val)
				{
					side.parameters.set(el.name,val);
					BasicInvite.myPersonalizationData.dirty = true;
					BasicInvite.myRefreshScene7Image();
				}
			}
		}
		catch(ex)
		{
			DFTools.console.log("myPersonalizationControlChangeHandler caught an error; event:",e,"error:",ex);
		}
	}.bindAsEventListener(this);
	
	BasicInvite.myCreateSwfUploader = function(container,options)
	{
		
		var swfupload = {
			flash_url: '/swf/swfupload.swf',
			upload_url: com.basicinvite.config.urls.upload,
			file_size_limit: com.basicinvite.config.upload.file_size_limit,
			file_types: com.basicinvite.config.upload.file_type_limit,
			file_types_description: com.basicinvite.config.upload.file_type_description,
			
			custom_settings: {
				controller: this
			},
			post_params: {
				
			}, 
			
			button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT,
			button_cursor: SWFUpload.CURSOR.HAND
		};
		
		swfupload.swfupload_loaded_handler = function()
		{
			DFTools.console.debug("SWFUpload has loaded.");
		}
		
		swfupload.file_dialog_complete_handler = function(numFiles, numQueued, totalQueued)
		{
			try
			{
				DFTools.console.log("SWFUpload file_dialog_complete. Files selected: ",numFiles);
				
				if (numFiles > 0)
				{
					DFTools.console.log("calling startUpload()");
					
					this.startUpload();
				}
			}
			catch(ex)
			{
				DFTools.console.error("caught an exception while handing swfupload file_dialog_complete: "+ex.message);
			}
		};
		
		swfupload.file_queued_handler = function()
		{
			try
			{
				DFTools.console.debug("SWFUpload file_queued: ",arguments);
			}
			catch(ex)
			{
				DFTools.console.error("caught an exception while handing swfupload file_queued: "+ex.message);
			}
		}
		
		swfupload.file_queue_error_handler = function()
		{
			try
			{
				DFTools.console.error("SWFUpload file_queue_error: ",arguments);
				
				alert("Sorry, something went wrong. Please check the file(s) you are trying to upload and make sure they are JPEG, PNG or GIF files");
			}
			catch(ex)
			{
				DFTools.console.error("caught an exception while handing swfupload file_queue_error: "+ex.message);
			}
		}
		
		swfupload.upload_start_handler = function()
		{
			try
			{
				DFTools.console.debug("SWFUpload upload_start: ",arguments);
				
				DFTools.console.log("Upload started -- Showing loading indicator");
				
				if((typeof options == 'object') && (options['loadingIndicator']))
					options.loadingIndicator.show();
			}
			catch(ex)
			{
				DFTools.console.error("caught an exception while handing swfupload upload_start: "+ex.message);
			}
		}
		
		swfupload.upload_progress_handler = function(uploadObj,bytesComplete,bytesTotal)
		{
			try
			{
				var progress = (bytesComplete/bytesTotal)*100;
				
				DFTools.console.debug("SWFUpload upload_progress: ",progress,arguments);
				
				if ((Math.round(progress*100)/100) == 100) {
					options.loadingIndicator.down('p.progress').update('Updating Preview');
				} else {
					options.loadingIndicator.down('p.progress').update(Math.round(progress*100)/100+'%');
				}
				
			}
			catch(ex)
			{
				DFTools.console.error("caught an exception while handing swfupload upload_progress: "+ex.message);
			}
		}
		
		swfupload.upload_success_handler = function(file,data,recvd_response)
		{
			try
			{
				DFTools.console.log("SWFUpload upload_success: ",arguments);
				
				result = data.evalJSON(true);
				
				if(result.success)
				{
					if((typeof options == 'object') && (typeof options['callback'] == 'function'))
					{
						options.callback(result,file);
					}
				}
				else
				{
					DFTools.console.log("SWFUpload upload_success: Result from server doesn't indicate success. No image data sent. data.success=",data.success);
					
					if(result.error)
						DFTools.console.log("Server error message was: ",result.error);
					
					var errMsg = com.basicinvite.config.upload.uploadFailedMessage.interpolate(result);
					
					DFTools.console.log("Alerting user: ",errMsg);
					
					alert(errMsg);
				}
				
				var stats = this.getStats();
				
				var currentFile = stats.successful_uploads + stats.upload_errors + stats.upload_cancelled + 1;
				
				var totalFiles = currentFile+stats.files_queued-1;
				
				DFTools.console.debug('Now uploading file '+currentFile+' of '+totalFiles);
			}
			catch(ex)
			{
				DFTools.console.error("caught an exception while handing swfupload uploadSuccess: "+ex.message);
			}
		};
		
		swfupload.upload_complete_handler = function(file)
		{
			try
			{
				DFTools.console.debug("SWFUpload upload_complete: ",arguments);
				
				var queued = this.getStats().files_queued;
				
				if (queued > 0)
				{
					DFTools.console.debug("Upload queue has",queued,"more files, starting upload.");
					
					this.startUpload();
					
					if((typeof options == 'object') && (options['loadingIndicator']))
						options.loadingIndicator.show();
				}
				else
				{
					DFTools.console.debug("Upload queue is empty -- hiding loading indicator.");
					
					if((typeof options == 'object') && (options['loadingIndicator']))
						options.loadingIndicator.hide();
					
					DFTools.console.log("Photo upload completed.");
				}
			}
			catch(ex)
			{
				DFTools.console.error("caught an exception while handing swfupload uploadComplete: "+ex.message);
			}
		};
		
		swfupload.button_placeholder_id = container.identify();
		
		swfupload.button_image_url = com.basicinvite.config.upload.button.src;
		swfupload.button_width = com.basicinvite.config.upload.button.width;
		swfupload.button_height = com.basicinvite.config.upload.button.height;
		
		var swfUploader = new SWFUpload(swfupload);
		
		return swfUploader;
	}
	
	BasicInvite.prepopControlChangeHandler = function(e,regionName)
	{
		DFTools.console.debug("prepopControlChangeHandler: ",e);
		
		try
		{
			var el = e.element();
			
			DFTools.console.debug("element was:",el);
			
			if(el.up('div.changeAll'))
			{
				if(el.hasClassName('size'))
				{
					el.up('div.region').select('tr select.size').each(function(s){ s.selectedIndex = el.selectedIndex; s.fire('df:change');});
				}
				else if(el.hasClassName('font'))
				{
					var code = el.next('div.fontPicker').down('a').innerHTML;
					
					el.up('div.region').select('tr input.font').each(function(i){ 
						i.value = el.value;
						i.fire('df:change');
						i.next('div.fontPicker').down('a').update(code);
					});
				}
				
				return 1;
			}
			
			if(el.hasClassName('size') || el.hasClassName('font'))
				el = el.up('tr').down('textarea');
			
			var name_parts = el.name.split('_');
			
			var lineNumber = parseInt(name_parts[name_parts.length-1])
			
			var text = $F(el);
			
			var size = parseInt($F(el.up('tr').down('td.size select')))*2;
			
			var font = $F(el.up('tr').down('td.font input'));
			
			var fontIndex = font.length ? BasicInvite.TheRegion[regionName].getFontIndex(font) : -1;
			
			var fontCode = '';
			
			if(fontIndex >= 0)
				fontCode = '\\f'+fontIndex;
			
			var rtf = size ? '{\\fs'+size+fontCode+' '+text+'}' : '{'+fontCode+' '+text+'}';
			
			var side = BasicInvite.myPersonalizationData.sides.get(BasicInvite.myScene7State.activeSide);
			
			BasicInvite.TheRegion[regionName].lines[lineNumber] = rtf;
			
			if(BasicInvite.TheRegion[regionName].fonts.length == 0)
			{
				
				var initialtbl = side.parameters.get(com.basicinvite.config.scene7.fonttable_param);
				
				var re1 = /{\\f([0-9]+) ([^;]+);}/g;
				var re2 = /{\\f([0-9]+) ([^;]+);}/;
				
				$A(initialtbl.match(re1)).invoke('match',re2).each(function(row){
					BasicInvite.TheRegion[regionName].fonts[parseInt(row[1])] = row[2];
				});
			}
			
			var fontTbl = BasicInvite.TheRegion[regionName].fonts.collect(function(f,i){return '{\\f'+i+' '+f+';}';}).join('');
			
			var val = BasicInvite.TheRegion[regionName].lines.join('\\par ');
			
			DFTools.console.log("val was:",val);
			
			if(side.parameters.get(BasicInvite.TheRegion[regionName].param_name) != val || side.parameters.get(com.basicinvite.config.scene7.fonttable_param) != fontTbl)
			{
				side.parameters.set(BasicInvite.TheRegion[regionName].param_name,val);
				side.parameters.set(com.basicinvite.config.scene7.fonttable_param,fontTbl);
				BasicInvite.myPersonalizationData.dirty = true;
				
				BasicInvite.myRefreshScene7Image();
			}
			
		}
		catch(ex)
		{
			DFTools.console.error("myPersonalizationControlChangeHandler caught an error; event:",e,"error:",ex);
		}
		
	};
	
	BasicInvite.myHandleProductInCart = function()
	{
		DFTools.console.log("myHandleProductInCart called: This product is in the cart, displaying message for user to choose action");
		
		var cartIndex = BasicInvite.myPersonalizationData.cartItems.pluck('id').indexOf(BasicInvite.myProductId+'');
		
		var data = {
			product:	BasicInvite.myPersonalizationData.cartItems[cartIndex]
		};
		
		$H(com.basicinvite.config.strings.productInCart).keys().each(function(k){
			data[k] = com.basicinvite.config.strings.productInCart[k];
		})
		
		data.prompt = data.prompt.interpolate(data);
		
		data.cancelBtn = '<a href="#" class="cancel">#{cancelBtn}</a>'.interpolate(data);
		data.continueBtn = '<a href="#" class="continue">#{continueBtn}</a>'.interpolate(data);
		
		data.html = data.layout.interpolate(data);
		 
		var l = new com.digitalfruition.ThemeObject.LoadingIndicator({
			el: $('body'),
			text: data.loadingText,
			cssClass: 'BIAddToCartLoading BIAlreadyInCartLoading'
		});
		
		var onClose = function(e)
		{
			if(e && (typeof e.stop == 'function'))
				e.stop();
			
			try { $('sb-container').hide(); } catch(e) {};
			
			l.show();
			l.repos();
			
			window.location=com.basicinvite.config.urls.cart;
		}
		
		var onCancel = function(e)
		{
			if(e && (typeof e.stop == 'function'))
				e.stop();
			
			try { $('sb-container').hide(); } catch(e) {};
			
			l.show();
			l.repos();
			
			window.location='/';
		}
		
		var onContinue = function(e)
		{
			if(e && (typeof e.stop == 'function'))
				e.stop();
			
			try { $('sb-container').hide(); } catch(e) {};
			
			l.show();
			l.repos();
			
			BasicInvite.emptyCart();
			
			var redir = function(){
				var l = window.location.toString();
				window.location=l.substring(0,l.length);
			};
			
			redir.delay(5);
		}
		
		var setup = function()
		{
			$('sb-container').addClassName('alreadyInCart');
			
			$('sb-title').addClassName('alreadyInCart');
			
			$('sb-container').down('a.cancel').observe('click',onCancel);
			$('sb-container').down('a.continue').observe('click',onContinue);
		};
		
		var sb = Shadowbox.open({
			content:	data.html,
			player:		"html",
			title:		data.title,
			height:		data.height,
			width:		data.width,
			options: {
				overlayOpacity: data.overlayOpacity,
				showOverlay: true,
				onFinish:	setup,
				onClose:	onClose
			}
		});
	}
	
	var mySetupCartFormObserver = function()
	{
		var cartFormDirty = false;
		
		DFTools.pageUnload.addUnloadWarning(function()
		{
			if(cartFormDirty)
			{
				return com.basicinvite.config.strings.errors.leaveCartPageDirty;
			}
			
			return false;
		})
		
		new Form.Observer(BasicInvite.myElements.cartForm, com.basicinvite.config.cartFormObserverFrequency, function()
		{
			DFTools.console.log("Cart form item changed... marking form as dirty");
			
			if(!cartFormDirty)
			{
				BasicInvite.myElements.cartForm.select('button.form-button-alt').each(function(s)
				{
					s.observe('click',function(){ cartFormDirty=false; });
					new Effect.Pulsate(s.down('span'),{duration:120,pulses:60});
				});
			}
			
			cartFormDirty = true;
		});
		
		$$('ul.checkout-types li a').invoke('observe','click',function(e)
		{
			if(cartFormDirty)
			{
				if(confirm(com.basicinvite.config.strings.errors.checkoutWithCartPageDirty))
				{
					e.stop();
					cartFormDirty = false;
					BasicInvite.myElements.cartForm.submit();
				}
				else
				{
					cartFormDirty = false;
				}
			}
		})
	}
	
	/**
	 * Initial setup of the Basic Invite controller
	 *
	 * This function perfroms initial setup of the Basic Invite controller system
	 *
	 * @return void
	 */
	var mySetup = function()
	{
		if(!com.basicinvite.config.enabled)
		{
			myMode = BasicInvite.MODE_DISABLED;
			return false;
		}
		
		// Search the page, see if we can find known elements:
		BasicInvite.myElements.productPageContainer = $('product_addtocart_form');
		
		if(BasicInvite.myElements.productPageContainer)
		{
			BasicInvite.myElements.magentoAddToCartBox = BasicInvite.myElements.productPageContainer.down(com.basicinvite.config.selectors.addToCartBox);
			BasicInvite.myElements.productImage = BasicInvite.myElements.productPageContainer.down(com.basicinvite.config.selectors.mainProductImage);
			BasicInvite.myElements.moreViews = BasicInvite.myElements.productPageContainer.down(com.basicinvite.config.selectors.moreViews);
			
			$$('a.enlarge-image').invoke('observe','click',function(e)
			{
				e.stop();
				
				var url = BasicInvite.myElements.productImage.down('img').src.replace('$ProductDetails$','$Embiggened$');
				
				if(BasicInvite.myElements.personalizedImage && BasicInvite.myElements.personalizedImage.visible())
				{
					url = BasicInvite.myElements.personalizedImage.down('img').src+'&$Embiggened$';
				}
				
				Shadowbox.open({
					content:	url,
					player:		"img",
					title:		'Enlarged Image',
					//height:		800,
					//width:		600,
					options: {
						//overlayOpacity: 0,
						showOverlay: true,
						//onFinish:	setup,
						//onClose:	onClose,
						enableKeys:	false
					}
				});
			});
			
			if($$(com.basicinvite.config.selectors.productSteps).length)
			{
				// We're on a product page because we found a product box. Set our mode and
				// locate other elements
				
				myMode = BasicInvite.MODE_PRODUCTPAGE;
				
				BasicInvite.myElements.productImage.setStyle({visibility: 'hidden'});
				
				$$('.product-info-box_outer')[0].insert({
					before: '<div class="steps-loading"><img src="/images/loading_01.gif"><br>'+com.basicinvite.config.strings.initialLoadingMessage+'</div>'
				});
				
				var setPricesLoading = function(){
					var priceLoading = '<img src="/images/loading_01.gif">';
					BasicInvite.myElements.productPageContainer.select(com.basicinvite.config.selectors.productPriceDisplay).invoke('update',priceLoading);
				};
				
				//setPricesLoading();
				//setPricesLoading.delay(1);
				
				myLoadWordingSuccess();
				
				BasicInvite.myElements.productForm = $(document.body).down(com.basicinvite.config.selectors.productForm);
				
				BasicInvite.myElements.ChainedItemsContainer = $(document.body).down(com.basicinvite.config.selectors.chainedItemsBox);
				
				BasicInvite.myElements.addToCartForm = $('product_addtocart_form');
				
				BasicInvite.myProductId = parseInt($F(BasicInvite.myElements.addToCartForm.product));
				
				mySetupProductPage();
				
				// trigger observers
				YLoader();
				
				
				//var rushMenu = $('productStepsShippingRush');
				
				//rushMenu.fire('change');
				
				//myUpdateProductPrice();
				
				
				// load fontpicker js
				YFontPick();
				
				// load patternpicker js
				YPatternPick();
				
				// load colorpicker js
				YColorPick();
				
			}
			else
			{
				// We're on a product page but it's not a customizable product
				
				// Show a loading indicator for the main product image:
				
				new PeriodicalExecuter(function(pe)
				{
					if(BasicInvite.myElements.productImage.down('img').complete)
					{
						DFTools.console.debug('BasicInvite.myElements.productImage loaded');
						BasicInvite.myElements.productPageContainer.down(com.basicinvite.config.selectors.productImageBox).down('div.loading').hide();
						pe.stop();
					}
				},0.1);
			}
		}
		else if (document.location.pathname==com.basicinvite.config.urls.cart)
		{
			// We're on a the view cart page
			myMode = BasicInvite.MODE_CARTPAGE;
			
			mySetupScene7UrlCartBox();
			
			BasicInvite.myElements.cartForm=$('main').down('form');
			
			mySetupCartFormObserver();
			
			$$('img.cartItem.productId.800').each(function(pocketImg)
			{
				var pocketOptions = pocketImg.up('tr').select('select');
				
				var url = 'http://s7d5.scene7.com/is/image/basicinvite/';
				url += pocketOptions[0].options[pocketOptions[0].selectedIndex].innerHTML.trim();
				url += ' - ';
				url += pocketOptions[1].options[pocketOptions[1].selectedIndex].innerHTML.replace('+$0.35','').trim();
				url += '?$CategoryThumbnail$';
				
				pocketImg.src = url;
			});
			
			$$('img.cartItem.productId.801').each(function(pocketImg)
			{
				var pocketOptions = pocketImg.up('tr').select('select');
				
				var url = 'http://s7d5.scene7.com/is/image/basicinvite/Sabino - ';
				url += pocketOptions[0].options[pocketOptions[0].selectedIndex].innerHTML.replace('+$0.35','').trim();
				url += '?$CategoryThumbnail$';
				
				pocketImg.src = url;
			});
			
		}
		
		// Warn if Flash is not installed:
		if(!DetectFlashVer(8,0,0))
		{
			//$$('div.flashNotInstalledWarning').invoke('show');
		}
		
		// Look for shipping method choices
		var restoreShippingMethod = function()
		{
			
		};
		
		restoreShippingMethod();
		
		if(typeof(shipping) == 'object' && shipping.onComplete)
		{
			shipping.onComplete = shipping.onComplete.wrap(function(originalFunction)
			{
				DFTools.console.debug('BasicInvite object intercepted a call to shipping.onComplete...');
				
				var args = [];
				 
				for(var i = 1; i < arguments.length; i++) { args.push(arguments[i]); }
				
				originalFunction.apply(shipping,args);
				
				restoreShippingMethod();
			});
		}
		
		if(typeof(billing) == 'object' && billing.onComplete)
		{
			billing.onComplete = shipping.onComplete.wrap(function(originalFunction)
			{
				DFTools.console.debug('BasicInvite object intercepted a call to billing.onComplete...');
				
				var args = [];
				 
				for(var i = 1; i < arguments.length; i++) { args.push(arguments[i]); }
				
				originalFunction.apply(billing,args);
				
				restoreShippingMethod();
			});
		}
	};
	
	var myShowShadowbox = function(options)
	{
		DFTools.console.debug("Creating a shadowbox");
		
		var reposition = function()
		{
			var top = document.viewport.getScrollOffsets()[1]+'px';
			
			$('sb-container').addClassName('designStep').setStyle({top: top});
		}
		
		var setup = function()
		{
			$('sb-container').addClassName('designStep');
			
			reposition();
			
			$(document).observe('scroll',reposition);
			
			var drag = new Draggable($('sb-wrapper'),{
				handle: $('sb-title'),
				//starteffect: '',
				onDrag: function(){ DFTools.console.debug('onDrag:',arguments); }
				
			});
			
			$('sb-overlay').observe('mousemove',function(e)
			{
				if(drag.dragging)
				{
					DFTools.console.debug('overlay mousemove:',arguments,drag);
					
					var p = e.pointer();
					drag.updateDrag(e,[p.x,p.y]);
					
				}
			});
			
			$('sb-title').addClassName('designStep');
			
			if(typeof options.setup == 'function')
				options.setup(options);
		};
		
		var onClose = function()
		{
			DFTools.console.debug("onClose");
			
			$(document).stopObserving('scroll',reposition);
			
			$('sb-container').removeClassName('designStep').setStyle({top: 'auto'});
			
			$('sb-overlay').show();
			
			if(typeof options.close == 'function')
				options.close(options);
		}
		
		Shadowbox.open({
			content:	options.content,
			player:		"html",
			title:		options.title,
			height:		options.height,
			width:		options.width,
			options: {
				overlayOpacity: 0,
				showOverlay: true,
				onFinish:	setup,
				onClose:	onClose,
				enableKeys:	false
			}
		});
	}
	
	/** Protected Functions:________________________________________________________ */
	
	BasicInvite.refreshPrice = function()
	{
		myUpdateProductPrice();
	};
	
	BasicInvite.addToCart = function()
	{
		productAddToCartForm.submit();
	};
	
	BasicInvite.showColorPicker = function(input,initialColor)
	{
		DFTools.console.log("Showing color picker");
		
		if(!initialColor)
			initialColor = input.value;
		
		if(!initialColor)
			initialColor = 'ffffff';
		
		var setColor = function(hex)
		{
			DFTools.console.debug("Hex is:",hex);
			
			input.value = hex;
			
			var btn = input.next('div.colorPicker');
			
			if(btn)
				btn.down('a').setStyle({backgroundColor:'#'+hex});
			
			input.fire('df:change');
		};
		
		var select = function(event)
		{
			DFTools.console.debug("Shadowbox select called with:",event);
			var el = event.element();
			var rgb = el.getStyle('backgroundColor');
			
			DFTools.console.debug("RGB is:",rgb);
			
			var color = rgb.match(/#([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})/i);
			
			var hex = initialColor ? initialColor : 'ffffff';
			
			DFTools.console.debug("Color hex match is:",color);
			
			if(color)
			{
				color.shift();
				hex = color.join('');
			}
			else
			{
				color = rgb.match(/rgb\(([0-9]+), *([0-9]+), *([0-9]+) *\)/);
				
				DFTools.console.debug("Color rgb match is:",color);
				
				color.shift();
				
				hex = color.collect(function(c){return parseInt(c).toColorPart();}).join('');
			}
			
			$('CLCPbasicHex').value=hex;
			CLCPupdateBasicFromForm(null,"CLCPbasicHex");
			
		};
		
		var setup = function()
		{
			DFTools.console.debug("Setting up color picker shadowbox");
			
			$('most_popular_colors').select('td').invoke('observe','click',select.bindAsEventListener(BasicInvite));
			
			var first = true;
			
			CLCPHandler = function(hex)
			{
				if(first)
				{
					DFTools.console.debug("This is the first (incorrect) CLCPHandler call -- ignoring:");
					first = false;
				}
				else
				{
					DFTools.console.debug("CLCPHandler called, setting color...:");
					setColor(hex);
				}
			};
			// Settings:
			_CLCPdisplay = "block"; // Values: "none", "block". Default "none"
			_CLCPisDraggable = false; // Values: true, false. Default true
			_CLCPposition = "relative"; // Values: "absolute", "relative". Default "absolute"
			_CLCPinitHex = initialColor; // Values: Any valid hex value. Default "ffffff"
			CLCPinitPicker();
		};
		
		myShowShadowbox({
			content:	BasicInvite.myElements.colorPicker.innerHTML,
			title:		"Select a Color",
			height:		com.basicinvite.config.colorPicker.height,
			width:		com.basicinvite.config.colorPicker.width,
			setup:		setup
		});
	};
	
	BasicInvite.showPatternPicker = function(input)
	{
		DFTools.console.log("Showing pattern picker");
		
		var select = function(event)
		{
			DFTools.console.debug("Shadowbox select called with:",event);
			var el = event.element();
			
			var pattern = el.alt;
			var patternSrc = "is{basicinvite/"+pattern+"}";
			
			input.value = patternSrc;
			
			var btn = input.next('div.patternPicker');
			
			input.fire('df:change');
		};
		
		var setup = function()
		{
			$('pattern_container').select('div.pattern img').invoke('observe','click',select.bindAsEventListener(BasicInvite));
		};
		
		myShowShadowbox({
			content:	BasicInvite.myElements.patternPicker.innerHTML,
			title:		"Select a Pattern",
			height:		422,
			width:		205,
			setup:		setup
		});
	};
	
	
	BasicInvite.showFontPicker = function(input)
	{
		DFTools.console.log("Showing font picker");
		
		var doselect = function(event)
		{
			DFTools.console.debug("Shadowbox select called with:",event);
			var el = event.element();
			
			var fontCode = el.title;
			var fontName = BasicInvite.fonts.get(fontCode);
			
			input.value = fontName;
			
			var btn = input.next('div.fontPicker');
			
			if(btn)
				btn.down('a').update(fontCode);
			
			input.fire('df:change');
		};
		
		var setup = function()
		{
			$$('img.font').invoke('observe','click',doselect);
		};
		
		myShowShadowbox({
			content:	BasicInvite.myElements.fontPicker.innerHTML,
			title:		"Select a Font",
			height:		422,
			width:		350,
			setup:		setup
		});
	};
	
	BasicInvite.addCartItem = function(cartItem)
	{
		if(!(cartItem instanceof com.basicinvite.CartItem))
			throw new TypeError("BasicInvite.addCartItem expects a com.basicinvite.CartItem");
		
		BasicInvite.myPersonalizationData.cartItems.push(cartItem);
		
		BasicInvite.myPersonalizationData.dirty = true;
	}
	
	BasicInvite.emptyCart = function()
	{
		var cart = BasicInvite.myPersonalizationData.cartItems;
		
		BasicInvite.myPersonalizationData.cartItems = $A();
		
		BasicInvite.myPersonalizationData.dirty = true;
		
		cart.each(function(i)
		{
			if(i instanceof com.basicinvite.CartItem)
				i.remove();
		});
	}
	
	BasicInvite.mode = function()
	{
		return myMode;
	}
	
	if(BrowserDetect.browser == 'Explorer')
	  Event.observe(window,'load',mySetup);
	else
	  FastInit.addOnLoad(mySetup);
	
	return BasicInvite;
}();

DFTools.console.debugLogEnabled = 0;

