var chkOutDebugEl = $('<div id="debuggger" style="display: none; overflow: auto; height: 300px; width: 317px; border: solid 3px blue; padding: 10px;"></div>');
$(document).ready(function() {
	chkOutDebugEl.insertAfter($('#checkoutCartInfo'));
});
function chkOutDebugger( debugMsg ) {
	chkOutDebugEl.prepend('<div style="border-top: solid 1px #000;">' + debugMsg + '</div>');
}
function debugErrors( responseErrs ) {
	var hasErrors = false;
	if (!!responseErrs) {
		$.each(responseErrs, function( key, errs ) {
			var debugStr = '<pre>::: ' + key + ' :::\n';
			if ((typeof errs != 'string') && !!errs.length) {  // Clean up logic... actually, clean up this whole function
				hasErrors = true;
				$.each(errs, function( i, err ) {
					debugStr += '++ ' + i + '\n';
					$.each(err, function( j, msg ) {
						debugStr += '\t++ ' + j + ': ' + msg + '\n';
					});
				});
			} else {
				debugStr += '\t++ ' + errs + '\n';
			}
			debugStr += '</pre>';
			chkOutDebugger(debugStr);
		});
	}
	return hasErrors;
}

////////////// REMOVE/CLEAN ABOVE

function ShippingAddress() {
	var model = new GenericModel([
		'addressHTML',
		'vgcHTML',
		'methodsHTML',
		'completeHTML',
		'cityStateHTML',
		'address1Field',
		'address2Field',
		'stateField',
		'countryTypeField'
	]);
	model.implement(DOMassociator);
	model.implement(FieldsBackup);
	
	var dumpSet = [
		{
			dataKey: 'completeHTML',
			dumps: ['#shippingFormComplete']
		},
		{
			dataKey: 'vgcHTML',
			dumps: ['#shippingVGC']
		},
		{
			dataKey: 'addressHTML',
			dumps: ['#shippingAddressFields']
		},
		{
			dataKey: 'methodsHTML',
			dumps: ['#shippingMethodsFields']
		},
		{
			dataKey: 'cityStateHTML',
			dumps: ['#cityStateShipAddFieldHolder']
		},
		{
			dataKey: 'address1Field',
			sniffs: ['#address1ShipAddField']
		},
		{
			dataKey: 'address2Field',
			sniffs: ['#address2ShipAddField']
		},
		{
			dataKey: 'stateField',
			sniffs: ['#stateShipAddField']
		},
		{
			dataKey: 'countryTypeField',
			sniffs: ['#countryTypeShipAddField']
		}
	];
	
	model.addDOMassociations(dumpSet);
	model.addBackupAssociations(dumpSet);

	model.postprocess('setAddressHTML', function( processor ) {
		this.addDOMsniff('countryTypeField', '#countryTypeShipAddField');
		this.addDOMsniff('address1Field', '#address1ShipAddField');
		this.addDOMsniff('address2Field', '#address2ShipAddField');
		this.addDOMsniff('stateField', '#stateShipAddField');
	});
	
	model.postprocess('setCityStateHTML', function( processor ) {
		this.addDOMsniff('stateField', '#stateShipAddField');
	});
	
	return model;
}

function BillingAddress() {
	var model = new GenericModel([
		'addressHTML',
		'giftCardHTML',
		'completeHTML',
		'paymentTypeHTML',
		'contactInfoHTML',
		'aapHTML',
		'aeAccountHTML',
		'placeOrderHTML',
		'cityStateHTML',
		'countryTypeField',
		'paymentTypeField'
	]);
	model.implement(DOMassociator);
	model.implement(FieldsBackup);
	
	var dumpSet = [
		{
			dataKey: 'addressHTML',
			dumps: ['#billingAddressFields']
		},
		{
			dataKey: 'giftCardHTML',
			dumps: ['#billingGiftCards']
		},
		{
			dataKey: 'paymentTypeHTML',
			dumps: ['#paymentInfoBlock']
		},
		{
			dataKey: 'completeHTML',
			dumps: ['#billingFormComplete']
		},
		{
			dataKey: 'contactInfoHTML',
			dumps: ['#contactInfoFields']
		},
		{
			dataKey: 'aapHTML',
			dumps: ['#aapFields']
		},
		{
			dataKey: 'aeAccountHTML',
			dumps: ['#acAccountFields']
		},
		{
			dataKey: 'placeOrderHTML',
			dumps: ['#placeOrder']
		},
		{
			dataKey: 'cityStateHTML',
			dumps: ['#cityStateBillAddFieldHolder']
		},
		{
			dataKey: 'countryTypeField',
			sniffs: ['#countryTypeBillAddField']
		},
		{
			dataKey: 'paymentTypeField',
			sniffs: ['#checkoutPaymentType']
		}
	];
	
	model.addDOMassociations(dumpSet);
	model.addBackupAssociations(dumpSet);

	model.postprocess('setAddressHTML', function( processor ) {
		this.addDOMsniff('countryTypeField', '#countryTypeBillAddField');
		this.addDOMsniff('paymentTypeField', '#checkoutPaymentType');
	});
	
	return model;
}


function CartInfo() {
	var model = new GenericModel([
		'itemsHTML',
		'orderTotalsHTML'
	]);
	model.implement(DOMassociator);
	model.implement(FieldsBackup);
	
	var dumpSet = [
		{
			dataKey: 'itemsHTML',
			dumps: ['#checkoutCartItems']
		},
		{
			dataKey: 'orderTotalsHTML',
			dumps: ['#checkoutCartInfo']
		}
	];
	
	model.addDOMassociations(dumpSet);
	model.addBackupAssociations(dumpSet);
	
	return model;
}

function OrderHandler() {
	var infoSets = {
		shippingAddress: new ShippingAddress(),
		billingAddress: new BillingAddress(),
		cart: new CartInfo()
	};
	
	infoSets.shippingAddress.postprocess('setCountryTypeField', function( processor ) {
		$.ajax({
			url: 'checkout_htmljax.jsp',
			type: 'post',
			dataType: 'json',
			data: {
				requestedData: 'shippingAddress.cityStateHTML;shippingAddress.methodsHTML',
				clearFields: true,
				countryTypeVal: processor.args[0]
			},
			success: function( response, status ) {
				if (!!response && !!response.data) {
					updateInfo(response.data);
					
					var hasErrors = debugErrors(response.errors);
					if (!hasErrors) {
						chkOutDebugger('POST OK: (city/state update)');
					}
					chkOutDebugger('<div style="border-top: solid 2px red;"></div>');
				}
			},
			error: function() { window.location.href = '/' + jsContextRoot + '/checkout/cart.jsp'; }
		});
	});
	
	infoSets.shippingAddress.postprocess('setStateField', function( processor ) {
		var stateInput = $('#stateShipAddField');
		if (!!stateInput.length && stateInput.is('select,input.pseudoSelect')) {
			$.ajax({
				url: 'checkout_htmljax.jsp',
				type: 'post',
				dataType: 'json',
				data: {
					requestedData: 'shippingAddress.methodsHTML',
					countryTypeVal: this.getCountryTypeField(),
					address1Val: this.getAddress1Field(),
					address2Val: this.getAddress2Field(),
					stateVal: processor.args[0]
				},
				success: function( response, status ) {
					if (!!response && !!response.data) {
						updateInfo(response.data);
						
						var hasErrors = debugErrors(response.errors);
						if (!hasErrors) {
							chkOutDebugger('POST OK: (ship methods update)');
						}
						chkOutDebugger('<div style="border-top: solid 2px red;"></div>');
					}
				},
				error: function() { window.location.href = '/' + jsContextRoot + '/checkout/cart.jsp'; }
			});
		}
	});
	
	function addAddress1BlurSniff() {
		var address1Input = $('#address1ShipAddField');
		if (!!address1Input.length) {
			address1Input.unbind('blur.blurSniffer').bind('blur.blurSniffer', function() {
				$.ajax({
					url: 'checkout_htmljax.jsp',
					type: 'post',
					dataType: 'json',
					data: {
						requestedData: 'shippingAddress.methodsHTML',
						countryTypeVal: infoSets.shippingAddress.getCountryTypeField(),
						address1Val: infoSets.shippingAddress.getAddress1Field(),
						address2Val: infoSets.shippingAddress.getAddress2Field(),
						stateVal: infoSets.shippingAddress.getStateField()
					},
					success: function( response, status ) {
						if (!!response && !!response.data) {
							updateInfo(response.data);
							
							var hasErrors = debugErrors(response.errors);
							if (!hasErrors) {
								chkOutDebugger('POST OK: (ship methods update)');
							}
							chkOutDebugger('<div style="border-top: solid 2px red;"></div>');
						}
					},
					error: function() { window.location.href = '/' + jsContextRoot + '/checkout/cart.jsp'; }
				});
			});
		}
	}
	$(document).ready(addAddress1BlurSniff);
	infoSets.shippingAddress.postprocess('setAddressHTML', addAddress1BlurSniff);
	
	
	infoSets.billingAddress.postprocess('setCountryTypeField', function( processor ) {
		$.ajax({
			url: 'checkout_htmljax.jsp',
			type: 'post',
			dataType: 'json',
			data: {
				requestedData: 'billingAddress.giftCardHTML;billingAddress.paymentTypeHTML;billingAddress.cityStateHTML',
				checkoutPaymentType: this.getPaymentTypeField(),
				countryTypeVal: processor.args[0],
				clearFields: true
			},
			success: function( response, status ) {
				if (!!response && !!response.data) {
					updateInfo(response.data);
					
					var hasErrors = debugErrors(response.errors);
					if (!hasErrors) {
						chkOutDebugger('POST OK: (billing city/state update)');
					}
					chkOutDebugger('<div style="border-top: solid 2px red;"></div>');
				}
			},
			error: function() { window.location.href = '/' + jsContextRoot + '/checkout/cart.jsp'; }
		});
	});	
	
	function updateInfo( infoSelector, infoVal ) {  /// Clean this up!!
		switch (typeof infoSelector) {
			case 'string':
				var path = infoSelector.split('.');
				switch (path.length) {
					case 1:
					case 0:
						throw('Invalid info selector.');
						break;
					case 2:
						if (!!infoSets[path[0]]) {
							infoSets[path[0]].set(path[1], infoVal);
						}
						break;
					default:
						if (!!infoSets[path[0]]) {
							infoSets[path[0]].set(path[1], infoVal);
						}
				}
				break;
			case 'object':
				$.each(infoSelector, function( key, val ) {
					updateInfo(key, val);
				});
				break;
		}
	}
	this.updateInfo = updateInfo;
}

function AjaxFormAccordion( stepSet ) {
	var stepIdMap = {},
	currentOpen = stepSet.initial || 0,
	EVT_NAMESPACE = '.ajaxAccordion',
	STEP_TITLE_SELECTOR = 'h2',
	STEP_BODY_SELECTOR = 'div.stepBody',
	STEP_TRIGGER_SELECTOR = 'form.accordionTrigger',
	COMPLETE_SELECTOR = 'div.stepComplete',
	EDIT_LINK_SELECTOR = 'a.stepEdit',
	STEP_OPEN_CLASS = 'accordionOpen',
	STEP_COMPLETE_CLASS = 'accordionComplete',
	STEP_INCOMPLETE_CLASS = 'accordionIncomplete',
	SLIDE_SPEED = 'slow',
	RESET_CSS = {
		height: 'auto',
		overflow: 'visible',
		display: 'block'
	},
	PRE_CSS = {
		overflow: 'hidden',
		display: 'block'
	};
	
	function swapStepClass( obj, newClass ) {
		$.each([
			STEP_OPEN_CLASS,
			STEP_COMPLETE_CLASS,
			STEP_INCOMPLETE_CLASS
		], function( key, val ) {
			if (val == newClass) {
				obj.addClass(val);
			} else {
				obj.removeClass(val);
			}
		});
	}
	
	function updateEditLinks( indexVal ) {
		stepSet.steps[indexVal].obj.find(EDIT_LINK_SELECTOR).each(function( j, editLink ) {
			$(editLink).bind('click' + EVT_NAMESPACE, function( evt ) {
				evt.preventDefault();
				
				$.each(stepSet.steps, function() {
					this.obj.find(EDIT_LINK_SELECTOR).hide().unbind('click' + EVT_NAMESPACE);
				});
				
				var dataVals = parseQueryString(this.href) || {};
				dataVals['requestedData'] = '';
				
				$.ajax({
					url: 'checkout_htmljax.jsp',
					type: 'post',
					dataType: 'json',
					data: dataVals,
					success: function() {},
					error: function() {}
				});
				
				try {
					allTooltips.close();
				} catch (err) {}
				
				openSqueeze(indexVal);
			});
		});
	}
	
	$.each(stepSet.steps, function( i, stepInfo ) {
		if (!!stepInfo.obj.attr('id')) {
			stepIdMap[stepInfo.obj.attr('id')] = i;
			stepInfo.i = i;
		}
		
		var stepTrigger = stepInfo.obj.find(STEP_TRIGGER_SELECTOR);
		if (i < (stepSet.steps.length - 1)) {
			stepTrigger.useAjax({
				url: 'checkout_htmljax.jsp',
				type: 'post',
				dataType: 'json',
				useOverlay: true,
				success: handleSuccess,
				error: function() {
					window.location.href = '/' + jsContextRoot + '/checkout/cart.jsp';
				}
			});
		} else {
			stepTrigger.unbind('submit' + EVT_NAMESPACE).bind('submit' + EVT_NAMESPACE, function() {
				setTimeout(function() {
					$('#ajaxIconOverlay').show().centerObj();
					$('#ajaxOverlay').show().stretchObj();
				}, 0);
			});
		}
		
		if (stepInfo.done) {
			swapStepClass(stepInfo.obj, STEP_COMPLETE_CLASS);
			stepInfo.obj.find(STEP_BODY_SELECTOR).hide();
			stepInfo.obj.find(COMPLETE_SELECTOR).show();
		} else {
			if (i === currentOpen) {
				swapStepClass(stepInfo.obj, STEP_OPEN_CLASS);
				stepInfo.obj.find(STEP_BODY_SELECTOR).show();
				stepInfo.obj.find(COMPLETE_SELECTOR).hide();
				if (typeof stepInfo.openCb == 'function') {
					setTimeout(function() {
						stepInfo.openCb.call(stepInfo);
					}, 0);
				}
			} else {
				swapStepClass(stepInfo.obj, STEP_INCOMPLETE_CLASS);
				stepInfo.obj.find(STEP_BODY_SELECTOR).hide();
				stepInfo.obj.find(COMPLETE_SELECTOR).hide();
			}
		}
		
		updateEditLinks(i);
	});
	
	function updateSteps() {
		var nextIndex = 0;
		for (var i = 0, j = stepSet.steps.length; i < j; i++) {
			if (stepSet.steps[i].done) {
				if (i == nextIndex && (i < (j - 1))) {
					nextIndex++;
				}
				
				swapStepClass(stepSet.steps[i].obj, STEP_COMPLETE_CLASS);
			} else if (i != nextIndex) {
				swapStepClass(stepSet.steps[i].obj, STEP_INCOMPLETE_CLASS);
			}
			
			updateEditLinks(i);
		}
		openSqueeze(nextIndex);
	}
	
	function handleSuccess( response ) {
		if (!!response && !!response.stepStates) {
			checkoutObj.updateInfo(response.data);
			
			var hasErrors = debugErrors(response.errors);	
			
			accordionValidator.report(response.errors);
			
			if (!hasErrors) {
				chkOutDebugger('POST OK: (accordion update)');
			}
			chkOutDebugger('<div style="border-top: solid 2px red;"></div>');
			
			for (var i = 0, j = response.stepStates.length; i < j; i++) {
				stepSet.steps[i].done = (typeof response.stepStates[i].done == 'string') ? (response.stepStates[i].done.toLowerCase() == 'true') : !!response.stepStates[i].done;
			}
			updateSteps();
		} else {
			chkOutDebugger('NOT OK!!!: MALFORMED RESPONSE');
			chkOutDebugger('<div style="border-top: solid 2px red;"></div>');  /*
				TODO clean this up!!!
			*/
		}
	}
	this.handleSuccess = handleSuccess;
	
	function openSqueeze( stepIndex, closeCb, openCb ) {
		if (stepIndex != currentOpen) {
			var oldStep = stepSet.steps[currentOpen],
			oldStepContent = oldStep.obj.find(STEP_BODY_SELECTOR),
			oldStepComplete = oldStep.obj.find(COMPLETE_SELECTOR),
			newStep = stepSet.steps[stepIndex],
			newStepContent = newStep.obj.find(STEP_BODY_SELECTOR),
			newStepComplete = newStep.obj.find(COMPLETE_SELECTOR);
			
			currentOpen = stepIndex;
			
			setTimeout(function() {
				$('html, body').scrollTop(stepSet.steps[0].obj.offset().top);
				
				///////////// PREP ANIMATIONS
				
				oldStepContent.css(RESET_CSS);
				var oldStepContentOpenCSS = {
					height: oldStepContent.height()
				};
				oldStepContent.css(PRE_CSS);
				oldStepContent.css(oldStepContentOpenCSS);
				
				newStepComplete.css(RESET_CSS);
				var newStepCompleteOpenCSS = {
					height: newStepComplete.height()
				};
				newStepComplete.css(PRE_CSS);
				newStepComplete.css(newStepCompleteOpenCSS);
				
				newStepContent.css(RESET_CSS);
				var newStepContentOpenCSS = {
					height: newStepContent.height()
				};
				newStepContent.css($.extend({height: 0}, PRE_CSS));
				
				oldStepComplete.css(RESET_CSS);
				var oldStepCompleteOpenCSS = {
					height: oldStepComplete.height()
				};
				oldStepComplete.css($.extend({height: 0}, PRE_CSS));
				
				///////////// START ANIMATIONS
				
				oldStepContent.animate({height: 0}, SLIDE_SPEED, function() {					
					oldStepContent.css($.extend({height: 0}, PRE_CSS));
					
					if (typeof oldStep.closeCb == 'function') {
						oldStep.closeCb.call(oldStep);
					}
					if (typeof closeCb == 'function') {
						closeCb.call(oldStep);
					}
				});
				
				newStepComplete.animate({height: 0}, SLIDE_SPEED, function() {
					newStepComplete.css($.extend({height: 0}, PRE_CSS));
				});
				
				newStepContent.animate(newStepContentOpenCSS, SLIDE_SPEED, function() {
					newStepContent.css(RESET_CSS);
					swapStepClass(newStep.obj, STEP_OPEN_CLASS);
					
					if (typeof newStep.openCb == 'function') {
						newStep.openCb.call(newStep);
					}
					if (typeof openCb == 'function') {
						openCb.call(newStep);
					}
				});
				
				if (oldStep.done) {
					oldStepComplete.animate(oldStepCompleteOpenCSS, SLIDE_SPEED, function () {
						oldStepComplete.css(RESET_CSS);
						swapStepClass(oldStep.obj, STEP_COMPLETE_CLASS);
					});
				} else {
					swapStepClass(oldStep.obj, STEP_INCOMPLETE_CLASS);
				}
			}, 0);
		}
	}
	
	this.open = function( stepInstance, openCb ) {
		switch (typeof stepInstance) {
			case 'number':
				break;
			case 'string':
				if (/^[\d]+$/.test(stepInstance)) {
					stepInstance = parseInt(stepInstance);
				} else {
					stepInstance = stepIdMap[stepInstance.replace('/^\#/', '')];  /*
						TODO // failure???
					*/
				}
				break;
			default:
				stepInstance = currentOpen;
				break;
		}
		
		openSqueeze(stepInstance, null, openCb);
	};
}
