var Calculator = function(handle) {
	this.form = null;
	this.maxvalue = "10,000,000.00";
	this.flashVisible = false;
	this.firstInteraction = false;
	this.firstLoad = true;
	
	this._init(handle);
}

Calculator.prototype = {
	_init: function(handle) {
		var self = this;

		if ( typeof handle == "undefined" ) {
			return true;
		}
		handle = "#" + handle;
		self.form = $(handle);

		$(self.form)
			.data("formhandle", handle)
			.data("flashname", "flashcalculator")
			.data("apr", 0)
			.data("apy", 0);
		
		// Extract all current inputs from the form.
		//
		var inputs = $(self.form).serializeArray();
		for (var input in inputs) {
			$(self.form).data(inputs[input].name, inputs[input].value);
		}
		
		// Disabled inputs are ignored by serializeArray, so we need to add their values the first time around.
		//
		$(self.form).find(".control.disabled").find("input,select").each( function() {
			$(self.form).data( $(this).attr("name"), $(this).val() );
		});

		// Set the status of the form.
		//
		$(self.form).data("initialized", false);
		$(self.form).data("ajax-loaded", false);
		$(self.form).filter(".calculator").not(".comparerate")
			.each( function() { 
				setTimeout( function() {
					forms.loading({ form: self.form, action: "add", title: "Populating " + $(self.form).data("title") + "..." }); 
				}, 10);
			});
		
		// Get the form type.
		//
		self.setType();

		if ( $(self.form).data("form-type") == "flash") {
			//( $.browser.msie ) ? self.initGraph() : self.makeFlashLive();
			self.initGraph();
		} else {
			self.finishInit();
		}
	},
	
	initForm: function() {
		var self = this;

		$(window).load( function() { self.store(false); } )
		
		$(self.form)
			.each( function() { forms.dirty(this); })
			
			.find("[name=deposit],[name=future]").bind("change.calculator blur.calculator", function() {
				forms.checkShorthand(this);
				
				var val = parseFloat( forms.dollarsToHundreds( $(this).val() ) );
				var max = parseFloat( forms.dollarsToHundreds( self.maxvalue ));

				if (val > max || ( val == 0 && $(this).closest(".item").hasClass("gtzero") ) ) {
					$(this).val( val > max ? self.maxvalue : $(self.form).data( $(this).attr("name") ) );
					forms.shake(this, 2);
				} else {
					$(this).val(val);
				}
			}).end()
			
			.find("[name=future]").bind("change.calculator", function() {
				
				if ( parseFloat($(this).val()) == 0 ) {
					$(self.form).find("[name='futureon']").filter("[value=off]").trigger("click");
					self.setFutureContributions();
					return true;
				}

				var currval = parseFloat( forms.dollarsToHundreds( $(self.form).data( $(this).attr("name") ) ) );
				var newval  = parseFloat( forms.dollarsToHundreds( $(this).val() ) );

				if (newval == 0) {
					if (currval == 0 || isNaN(currval)) currval = $(self.form).data("oldfuture");
					$(this).val( self.formatCurrency(currval) );
					newval = currval;
					forms.shake(this, 2);
				}

				if (parseFloat(newval) > 0) {
					$(self.form).data("oldfuture", self.formatCurrency(newval) );
				}
				
			}).end()
			
			.find("[name=deposit]").bind("change.calculator", function() {
				self.store(true);
				if ($(self.form).find("[name=rate]").closest(".item").hasClass("set") 
						|| $(self.form).data("form-type") != "flash") {
					self.getRates();
				} else {
					self.getRates("deposit");
				}					
			}).end()
			
			.find("[name=rate]").bind("change.calculator", function() {
				
				var boxval = parseFloat( forms.stringToHundreds( $(this).val() ) );

				if ($(this).closest(".item").hasClass("set")) {
					
					var instruct = true;
					if (boxval == 0 || boxval == $(self.form).data("rate") ) {
						instruct = false;
						boxval = parseFloat( forms.stringToHundreds( $(self.form).data("oldrate") ) );
					}

					if ( parseFloat($(self.form).data("oldrate")) != parseFloat($(this).val()) && instruct) {
						$(this).closest(".item").removeClass("set")
							.find(".instruction").animate( { "opacity" : "1" }, 1500);
					}
					
				} else {
					boxval = parseFloat( $(self.form).data("oldrate") );

					if ( forms.stringToHundreds( $(self.form).data("apr") ) == forms.stringToHundreds( $(this).val() ) ) {
						$(this).closest(".item").addClass("set").find(".instruction").animate( { "opacity" : "0" }, 500);
						boxval = parseFloat( $(self.form).data("apr") );
					}
				}

				// Unbind the generic fixPercent so that we can call it *before* we send the data to Flash.
				//
				$(this).unbind("blur.forms");
				forms.fixPercent(self.form, this);

				self.store();

			}).each( function() {
				var rate = this;
				$(this).siblings(".instruction").bind("click.calculator", function() { 
					if (!$(this).closest(".item").hasClass("set")) {
						$(self.form).find(".hasfocus").removeClass("hasfocus");
						$(rate).val( $(self.form).data("apr") ).change();
					}
				});
			}).end()
			
			.find("[name=product]").bind("change.calculator", function() { self.store(); self.getRates(); }).end()

			.find("[name=frequency],[name=future]").bind("change.calculator", function() { self.store(); });
			
		$(self.form)
			.find("input").blur().end()
			.find(".btn_update").find("input,a").attr('hideFocus','true').bind("click.calculator", function(e) { e.preventDefault(); $(this).blur(); self.store(); }).end().end()
			.find(".btn_print").find("input,a").bind("click.calculator", function(e) { e.preventDefault(); $(this).blur(); self.print(); }).end().end()
			.find(".btn_table").find("input,a").bind("click.calculator", function(e) { e.preventDefault(); $(this).blur(); self.toggleTable(); });
		
		setTimeout( function() {
			$(self.form).find('.customselect').custombox({
				boxType: 'select',
				containerClass: 'custombox-wrapper',
				boxClass: 'custombox',
				contextMenuDisabled: true,
				openOnTab: false,
				debug: false
			});
		}, 100);
		
		forms.activateFocus(self.form);

		ALLY.global_drivers.enhanceZebraTables();
	},
	
	setType: function() {
		var self = this;
		
		$(self.form).data( "category", $(self.form).find("[name=category]").val() );
		$(self.form).data( "form-type", $.trim( $(self.form).attr("class").replace("comparerate","").replace("calculator", "").replace("calc_", "").replace("initialized", "") ) );

		// Set the form title and ajax-type based on type.
		//
		var title = "Calculator";
		var ajaxtype = "single";
		switch( $(self.form).data("form-type") ) {
			default:
				title = "Calculator";
			break;
			case "compare":
				ajaxtype = "multiple";
			case "list":
				title = "Rates";
			break;
			case "ladder":
				title = "Ladder";
			break;
		}
		$(self.form).data("title", title);
		$(self.form).data("ajax-type", ajaxtype);
		
		var product = 0;
		switch( $(self.form).data("category") ) {
			case "CD":
				if ($(self.form).data("ryr") == "true") {
					product = 24;
				} else {
					product = 12;	
				}
			break;
			case "NCD":
				product = 9;
			break;
		}
		$(self.form).data("product", product);

		return true;
	},
	
	initGraph: function() {
		var self = this;

		var $fg = $(self.form).find(".flashgraph");
		if ($fg.length == 0) return true;

		$(self.form).data("flashname", "flashcalculator");
		var ffile = $fg.find("param[name=movie]").val();

		var fwidth = 725;
		$fg.find("param[name=width]").each( function() {
			fwidth = parseInt( $(this).val() );
		});
		var fheight = 320;
		$fg.find("param[name=height]").each( function() {
			fheight = parseInt( $(this).val() );
		});
		
		var $fnote = $(self.form).find(".flashgraph .note").clone(true);
		if (!$fnote.html()) $fnote = $("<div/>").append(self.flashNote);
		$fnote.addClass("msg_info").addClass("msg_wide").addClass("msg");
		
		var fversion = "9.0.0";
		$fg.find("param[name=swfversion]").each( function() {
			fversion = $(this).val();
		});
		var fmajor = parseInt( fversion.split(".").length > -1 ? fversion.split(".")[0] : fversion );

		var params = { }
		var param_exclude = "[name=movie]";
		$fg.find("param").not(param_exclude).each( function() {
			params[ $(this).attr("name") ] = $(this).attr("value");
		}).remove();
		params.menu = "false";
		
		var attributes = { };
		attributes.id = $(self.form).data("flashname");
		attributes.name = $(self.form).data("flashname");

		var $fcnew = $("<div id='flashwrapper'/>");
		$fcnew.append($fnote);
		var fcnew_html = $fcnew.html();

		swfobject.embedSWF( ffile, "flashcalculator", fwidth, fheight, fversion, "/files/swf/expressInstall.swf", false, params, attributes, 
			function(e) {
				// If the flash isn't there, bubble up the warning (i.e. replace the form).
				//
				if( e.success ) {
					$("#flashwrapper").remove();

					setTimeout( function() {
						$("#flashcalculator").removeAttr("style");
						self.finishInit();
					}, 200);

				} else {
					$fcnew.html(fcnew_html).removeAttr("style").attr("id","calculator_disabled").css( { display: "block" });
					$(self.form).replaceWith($fcnew);
				}
			
			});
	},

	finishInit: function() {
		var self = this;

		// if ( !$(self.form).data("initialized") ) {
			self.initForm();
			
			forms.clean(self.form);
			
			// Get the current APR/APY rates via AJAX.
			//
			$(self.form).each( function() { 
				if ($(self.form).data("ajax-type") != "multiple") {
					self.getRates();
				} 
			});

			// Do page-specific initializations.
			//
			var page = $(self.form).data("category") + $(self.form).data("form-type");
			switch( page ) {
				case "OSAVflash":
				case "MMDAflash":
					$(self.form).find("[name=futureon]").bind("click.calculator", function() {
						self.setFutureContributions();
					}).filter("[value='" + $(self.form).data("futureon") + "']").click(); 
				break;
			}
			// When a user clicks "Email This Page" we immediately store their calculator values.
			//
			$("#email a").click( function() { forms.save(self.form, 0); } );

			// Disable saving prefs data for DDA
			if ($(self.form).data("category") != "DDA") { forms.setUnload(self.form); }
			$(self.form).data("initialized", true);
			
			setTimeout( function() { 
				$(self.form).find("input,select").blur();
				self.store();
			}, 500);
		// }

		// self.store();
	},
	
	setSlider: function() {
		var self = this;

		$(self.form).find("[name=duration]").each( function() {
			if ($(this).siblings(".ui-slider").length == 0) {
				$(this).selectToUISlider({ 
					labels: 7, 
					tics: true, 
					sliderOptions: { 
						range: 'min', 
						change: function() { 
							$(self.form).data("dirty", true); self.store.call(self);
						},
						start: function() {
							$(self.form).find('.hasfocus :input').trigger('blur').trigger('change');
						}
					} 
				}).hide();
			}
		});
	},
	
	store: function(manual) {
		manual = (typeof manual == "undefined" || manual) ? true : false;
		var self = this;

		switch ( $(self.form).data("category") ) {
			case "CD":
			case "NCD":
				self.updateRollover();
			break;
		}
		self.clean();
		
		var inputs = $(self.form).serializeArray(),
			input;
		for (input in inputs) {
			$(self.form).data( inputs[input].name, inputs[input].value );
		}

		if (manual) {
			if (!self.checkPublished()) {
				self.update();
			}
			if ( $(self.form).data("dirty") ) {
				// Disable saving prefs data for DDA
				if ($(self.form).data("category") != "DDA") { forms.save(self.form); }
			}
		}
	},
	update: function(manual) {
		var self = this;

		if ( !$(self.form).data("initialized") ) return true;

		switch ( $(self.form).data("form-type") ) {
			case "flash":
				self.sendToFlash().changeTable();
			break;
		}
	},
	checkPublished: function() {
		var self = this,
			already = true,
			thissend = $(self.form).data("deposit") +"-"+
				$(self.form).data("product") +"-"+
				$(self.form).data("duration") +"-"+
				$(self.form).data("rate") +"-"+
				$(self.form).data("future") +"-"+
				$(self.form).data("frequency");

		if ( $(self.form).data("lastsend") != thissend) {
			already = false;
		}

		$(self.form).data("lastsend", thissend);
		
		return already;
	},
	
	makeFlashLive: function() {
		var self = this;
	
		$("#flashcalculator").appendTo("#article").css( { "position" : "absolute", "top" : 0, "left" : 0, "width" : 1, "height" : 1 } );

		// Wait for flash to be available.
		//
		(function(){
			if (!self.testFlash()) {
				setTimeout(arguments.callee, 150);
			} else {
				self.store();
				$("#flashcalculator").appendTo(".flashgraph").removeAttr("style");
				
				setTimeout( function() { 
					self.finalizeFlash();
					self.finishInit(); 
				}, 1500);
			}
		})();

	},

	finalizeFlash: function() {
		var self = this;

		var resizeBuffer, flashNeeded, flashActive;
		$(window).bind( 'scroll resize' , function () {
			clearTimeout(resizeBuffer);
			resizeBuffer = setTimeout(function(){
				$("#flashcalculator")
					.filter(":in-viewport").each( function() { flashNeeded = true; }).end()
					.not(":in-viewport").each( function() { flashActive = false; });

				if (self.testFlash() && flashNeeded && !flashActive) {
					self.store();
					flashActive = true;
				}
			}, 150);
		});
		
		$(self.form).parents(".tabs").find("> ul.ui-tabs-nav > li")
			.filter(".ui-state-active").bind("mousedown", function() {
				setTimeout( function() { $(self.form).find("[name=deposit]").change(); }, 1000 );
			}).end()
			.not(".ui-state-active").bind("mousedown", function() { 
				flashNeeded = true;
				flashActive = false;
			});
	},
	
	getFlashHandle: function(movieName) {
		if(window[movieName]) {
			return window[movieName];
		} else {
			return document[movieName];
		}
	},
	
	testFlash: function() {
		var self = this;

		var flashfile = self.getFlashHandle( $(self.form).data("flashname") );	
		return (typeof flashfile.sendToActionscript == "function");
	},
	
	sendToFlash: function(amt,term,interest,addContribution,conFreq) {
		var self = this,
			flashfile = self.getFlashHandle( $(self.form).data("flashname") );

		(function() {
			if (self.testFlash()) {
				flashfile.sendToActionscript(
					forms.dollarsToHundreds ( $(self.form).data("deposit") ),
					$(self.form).data("product"),
					$(self.form).data("duration"),
					$(self.form).data("rate"),
					forms.dollarsToHundreds ( $(self.form).data("future") ),
					$(self.form).data("frequency")
				);
				clearTimeout(timer);
			} else {
				var timer = setTimeout( arguments.callee, 150 );
			}
		})();
		
		return self;
	},
	getFromFlash: function() {
		var self = this,
			flash = self.getFlashHandle( $(self.form).data("flashname") );
			
		if (typeof flash.getFromActionscript == "function") {
			return flash.getFromActionscript();
		} else {
			return false;
		}
	},
	
	getRates: function(context) {
		var self = this;
		var data = null, method = "", key = "";

		var category = $(self.form).data("category");
		var product  = $(self.form).data("product");
		var deposit  = forms.dollarsToHundreds( $(self.form).data("deposit") );
		var formtype = $(self.form).data("form-type");
		
		switch ( formtype ) {			
			case "list":
				// key = "rates-" + category + "-" + product + "-" + deposit;
				key = "rates-" + category;
				data = { "prodCategoryCode" : category, "depositAmount" : deposit, "term" : product };
				method = "calculatorrates";
			break;

			case "compare":
				key = "rates-" + category + "-" + product;
				data = category == "DDA" ? { "prodCategoryCode" : category, "term" : product, "state" : "CA", "dailyBalanceAmount" : deposit } : { "prodCategoryCode" : category, "term" : product, "state" : "CA" };
				method = "competitorrates";
			break;
			
			default:
				// key = "rates-" + category + "-" + product + "-" + deposit;
				key = "rates-" + category;
				data = { "prodCategoryCode" : category, "depositAmount" : deposit, "term" : product };
				method = "calculatorrates";
			break;
		}
		var rates = $(self.form).data(key);

		if (rates && !(category == "DDA" && formtype == "compare")) {
			// Use the cached version of the rates.
			//
			self.store( false );
			self.setRates(key, context);
			setTimeout( function() { self.store( $(self.form).data("initialized") ); }, 500);
		} else {
			// Throw up a properly-sized loading overlay.
			//
			if ($(self.form).data("ajax-type") != "multiple") {
				forms.loading({ form: self.form, action: "add", title: "Populating " + $(self.form).data("title") + "..." });
			}
			
			// Create a request object then handle its results.
			//
			$.ajax({
				// async: false,
				cache: false,
				url: ALLY.util.getHrefForAjax( method , category ),
				global: false,
				type: "GET",
				data: data,
				dataType: "json",
				success: function(rates){
					// Mark the form as officially loaded with ajax data.
					//
					$(self.form).data("ajax-loaded", true);
					$(self.form).addClass("loaded");
					
					$(self.form).data( key, rates );
					self.setRates(key, context);
					
					// Update the page, then let the form know its external data is available.
					//
					self.store();

					// Remove the loading overlay.
					//
					setTimeout( function() { 
						forms.loading({ form: self.form, action: "remove" }); 
						if ( $(self.form).data("form-type") == "flash" ) self.setSlider();
					}, $.browser.msie ? 250 : 0 );
				},
				error: function() {
					// Mark the form as officially loaded with ajax data.
					//
					$(self.form).data("ajax-loaded", true);

					$(self.form).data("rate", 0);
					$(self.form).data("oldrate", 0);
					$(self.form).data("apy", 0);
					$(self.form).data("apr", 0);
					
					$(self.form).find("[name=rate]").parents(".item").find(".instruction").remove();
					self.changeRate( 0, -1 );

					// Update the page, then let the form know its external data is available.
					//
					self.store();
					
					// Remove the loading overlay.
					//
					forms.loading({ form: self.form, action: "remove" });
				}
			});
		}

		return true;
	},
	
	setRates: function(key, context) {
		var self = this;
		var rates = $(self.form).data(key);

		switch ( $(self.form).data("form-type") ) {
			case "flash":
				
				// Find the current applicable rate.
				//
				var myrates = self.pickRate( rates, $(self.form).data("category"), $(self.form).data("product"), $(self.form).data("deposit") );

				var apr = parseFloat(myrates.apr).toFixed(2);
				var apy = parseFloat(myrates.apy).toFixed(2);
				var allyrate = "Ally interest rate is <strong>" + apr + "%</strong>";
				
				$(self.form).find("[name=rate]").each( function() {
					var rate = this,
						instruct = $(this).parents(".item").find(".instruction");
					
					// If this is the first data load, prepare the interest rate box.
					//
					if ( !$(self.form).data("ajax-loaded") ) {
						$(rate).closest(".item").addClass("set");
						$(instruct).html(allyrate);
					}

					$(self.form).data( "oldrate", parseFloat(apr).toFixed(2) );

					if ( context == "deposit" ) {
						
						$(self.form).data("apr", apr);
						if ( $(rate).closest(".item").hasClass("set") ) {
							$(instruct).html(allyrate);
						} else {
							if ($(instruct).html() != allyrate) {
								$(instruct).animate( { "opacity" : "0" }, 250, function() {
									if ( $(self.form).data("rate") != apr) {
										$(this).html(allyrate).animate( { "opacity" : "1" }, 500);
									} else {
										$(instruct).html(allyrate);
										$(this).closest(".item").addClass("set");
									}
								});
							}
						}
						return true;
					}

					$(instruct).animate( { "opacity" : "0" }, 500);

					$(self.form).data("apy", apy );
					$(self.form).data("apr", apr );
					
					if ($(self.form).data("rate") != apr && $(self.form).data("ajax-loaded") ) {
						$(instruct).html(allyrate);
						
						var rcolor = "#505050";
						self.changeRate( apr, $(self.form).data("rate") );
					}
				});
				
				if (typeof rates.effdate != "undefined") {
					$(self.form).find("p.valid").remove().end()
						.find(".flashgraph").before("<p class='valid'>Ally interest rate as of " + rates.effdate + "</p>");
				}

			break;
			
			case "list":
				
				$tbl = $(self.form).find(".tblcompare");
				$tbl.find("tr").addClass("unset");
				
				var deposit = parseFloat( forms.dollarsToHundreds( $(self.form).data("deposit") ) );

				for (list in rates.product_rates) {
					var term = 12;
					if ($(self.form).data("category") == "CD" && $(self.form).data("ryr") == "true") {
						term = 24;
					}
					switch ( $(self.form).data("category") ) {
						case "NCD":
						case "CD":	
							term = parseInt( rates.product_rates[list].term.replace("M", "") );
						break;
					}

					var max = rates.product_rates[list].max;
					var min = rates.product_rates[list].min;

					var rowclass = rates.product_rates[list].productCode;

					$tbl.find("tr." + rowclass).each( function() {
						if (deposit >= min && deposit <= max) {
							var apr = rates.product_rates[list].rate;
							var apy = rates.product_rates[list].APY;

							var earned = 0;

							switch ( $(self.form).data("category") ) {
								case "MMDA":
								case "OSAV":
								case "DDA":
									var AIR = (1 / Math.pow( (apr/100/365)+1, -365)) - 1;
									var PIR = Math.pow( (1 + AIR), (1 / $(self.form).data("frequency"))) - 1;
									earned = deposit / Math.pow( (1 + PIR), -1) - deposit;
								break;
								default:
									earned = deposit * Math.pow((1+(apr/100/365)),(365*term/12)) - deposit;
								break;
							}

							earned = $("<div>" + earned + "</div>").formatCurrency().text();
							$(this).removeClass("unset")
								.find("td.rate").fadeFieldandChange( { newValue: apr.toFixed(2) + "%" } ).end()
								.find("td.apy").fadeFieldandChange( { newValue: apy.toFixed(2) + "%" } ).end()
								.find("td.earnings").fadeFieldandChange( { newValue : earned } );
							if ($(self.form).data("category") == "DDA") { $(this).find("td.deposit").fadeFieldandChange( { newValue: $("<div>" + $(self.form).data("deposit") + "</div>").formatCurrency().text() } ) }
						}
					});
				}

				// If values were not yet set, make them blank (rates weren't available for this range).
				$tbl.find("tr.unset").each( function() {
					earned = $("<div>0</div>").formatCurrency().text();

					$(this).removeClass("unset")
						.find("td.rate").fadeFieldandChange( { newValue: "N/A" } ).end()
						.find("td.apy").fadeFieldandChange( { newValue: "N/A" } ).end()
						.find("td.earnings").fadeFieldandChange( { newValue : earned } );
				});
				
				// Set the rate/apy paragraph.
				//
				$(self.form).find("p.valid").html("Ally rate (APR) as of " + rates.effdate + ".");
				$tbl.addClass("rates_set");
				
			break;
			
			case "compare":
				$(self.form).find(".tblcompare").each( function() {
					var $tblcompare = $(this);
					
					$(this).find("tbody").each( function() {
						$(this).find("tr").remove();
						$(this).addClass("zipped");

						var national = "0.00";

						var arr_rates = Array();
						for (list in rates.rates) {
							var bank = rates.rates[list].bankname;
							var apy  = rates.rates[list].APY.toFixed(2);
							
							if (bank == "National Average") {
								national = apy;
								continue;
							}
							
							var banksort = "";
							for (var i = 0; i < bank.length; i++) {
								banksort += self.alphaInvert( bank.substr(i,1) );
							}
							var apysort = $.trim(apy + " ").replace(/\./g,"_") + banksort;

							arr_rates.push( Array(apysort, { "bank" : bank, "apy" : apy + "%" } ));
						}
						arr_rates.sort();

						if (rates.errorcode) {
							var error = rates.errorcode.replace("0","");
							if (error != "") {
								arr_rates.push( Array( "", { "bank" : "Sorry, rates are currently unavailable.", "apy": "" } ));
							}
						}
						
						for (var i = arr_rates.length - 1; i >=0; i--) {
							bank = arr_rates[i][1].bank;
							apy = arr_rates[i][1].apy;
							$("<tr class='" + bank.toLowerCase().replace(/ /g,"") + "'><td><div>" + bank + "</div></td>" +
								"<td><div>" + apy + "</div></td></tr>").appendTo($(this));
						}

						$(this)
							.find("td div").slideDown(500).animate( { "opacity" : "1" }, function() {
								$(this).closest("td").html($(this).html())
									.closest("tbody").removeClass("zipped");
							});
							
							// Add the national average.
							//
							if ( parseFloat( national ) > 0 ) {
								var $national = $tblcompare.siblings(".tblnational");
								$national.find(".apy").each( function() {
									var html = $(this).html();
									$(this).empty().append("<div></div>").find("div").html(html).fadeOut(400);
								});
	
								if ($national.length == 0) {
									$national = $("<table cellpadding='0' cellspacing='0' class='stdtable tblnational'>" +
										"<thead><tr><th class='co'>National Average</th><th class='apy'> <div></div> </th></tr></thead></table>");
									
									$national.insertAfter($tblcompare).wrap("<div id='tblslide' style='height: 0;'></div>");
									
									$("#tblslide").animate( { height : 0 }, 700).animate( { height: $national.height() + "px" }, 500, function() { $("#tblslide").replaceWith($national); } );
								}
								$national.find(".apy div").each( function() {
									$(this).fadeOut(200, function() { 
										$(this).html( national + "%" )	.fadeIn(200, function() { 
											$(this).closest("td").html($(this).html());
										}); 
									}); 
								});
							}
							
							// self.addCompareNote(rates);
					});
				});
				ALLY.global_drivers.enhanceZebraTables();

			break;
		}
		return true;
	},
	
	pickRate: function(rates, category, product, deposit) {
		var myrate = { apr: 0, apy: 0, effdate: "06/30/2009" }
		var mydeposit = parseInt( forms.dollarsToHundreds( deposit ) );
		
		var myprod = product + "M" + category;
		if (category == "OSAV" || category == "MMDA" || category == "DDA") myprod = category;
		
		var line, ratemin, ratemax;
		for (line in rates.product_rates) {
			if (myprod == rates.product_rates[line].productCode) {
				ratemin = rates.product_rates[line].min;
				ratemax = rates.product_rates[line].max;

				if (mydeposit >= ratemin && mydeposit <= ratemax) {
					if (typeof rates.effdate != "undefined") {
						myrate = { apr: rates.product_rates[line].rate, apy: rates.product_rates[line].APY, effdate: rates.effdate }
					}
				}
			}
		}
		
		return myrate;
	},
	
	changeRate: function(newr, oldr) {
		$(self.form).find("[name=rate]")
			.fadeFieldandChange( { newValue: forms.stringToHundreds(newr), currentValue: forms.stringToHundreds(oldr), onComplete: function() {
				$(self.form).find("[name=rate]").change();
				$(self.form).data("rate", newr );
			}} ).end()
			.closest(".item").addClass("set");
	},
	
	setFutureContributions: function() {
		var self = this;

		$(self.form).data("futureon", $(self.form).find("[name='futureon']:checked").val() );

		// The "oldfuture" data bucket holds the previous value of the future contributions, 
		// allowing the display to show/hide this value as the user toggles yes/no on future contributions.
		//
		if ( !$(self.form).data("initialized") ) {
			$(self.form).data("oldfuture", $(self.form).data("future") );
		}

		var fo = $(self.form).find(".item_futureoptions");

		if ( $(self.form).data("futureon") == "on" ) {
		
			$(fo).find("label,.control").removeClass("disabled").end()
				.find(".control input").val( $(self.form).data("oldfuture") ).removeAttr("disabled");

		} else {
			$(fo).find("label,.control").addClass("disabled").end()
				.find(".control input").attr("disabled","disabled");
			$(self.form).find("[name=future]").each( function() {
				if ( parseFloat( $(this).val() ) > 0) {
					$(self.form).data( "oldfuture", $(this).formatCurrency({"symbol":""}).val() ).data( "future", "0.00" );
				}
				$(this).val("0.00");
			});
		}

		self.store();

		return true;
	},
	
	formatCurrency: function(val) {
		return $("<div></div>").text( val ).formatCurrency( { "symbol" : "" } ).text();
	},
	
	clean: function() {
		var self = this;

		if (forms && self.form) {
			$(self.form).data("lastsend","");
			// $(self.form).find("input,select").blur();
		}
		return this;
	},
	
	print: function() {
		this.makeTable();

		// Call the global print function.
		//
		$("#print a").click();
	},
	
	getFlashPrint: function(form) {
		var fp = $(form).siblings(".flashprint");
		if (fp.length == 0) {
			fp = $("<div class='flashprint'><h2>Tabular view of possible savings:</h2></div>").insertAfter(form);
		}
		
		return fp;
	},
	changeTable: function() {
		var self = this;
		var fp = self.getFlashPrint(self.form);

		if (!self.checkTable()) {
			var tbl = $(fp).find("table");
			if (tbl.length == 0) {
				 self.makeTable();
			} else {
				$(tbl).animate( {opacity : 0} , 500, function() { self.makeTable(); });
			}
		}
	},
	checkTable: function() {
		var self = this;
		
		var data = self.getFromFlash();
		$(self.form).data("tabledata", data);
		
		var sum = 0;
		for (var i = 0; i < data.length; i++) sum += data[i];
		
		if ( sum == $(self.form).data("tablesum") ) {
			return true;
		} else {
			$(self.form).data("tablesum", sum);
			return false;
		}
	},
	
	makeTable: function() {
		var self = this,
			data = $(self.form).data("tabledata");
		
		// Added for tracking
		if (!self.firstLoad && !self.firstInteraction) {
			if ($(self.form).data("category") == "CD") {
				if ($(self.form).data("np") == "true") {
					s=s_gi(s_account);
					s.prop12=s.pageName;
					s.linkTrackVars='eVar24,eVar29,prop12,prop24,events';
					s.linkTrackEvents='event11';
					s.tl(this,'o','NP GIC Calculator');
				} else {
					s=s_gi(s_account);
					s.linkTrackVars='eVar24,eVar29,prop12,prop24,events';
					s.linkTrackEvents='event11';
					s.prop12=s.pageName;
					s.tl(this,'o','GIC Calculator');
				}
			} else {
				s=s_gi(s_account);
				s.prop12=s.pageName;
				s.linkTrackVars='eVar24,eVar29,prop12,prop24,events';
				s.linkTrackEvents='event11';
				s.tl(this,'o','HIS Calculator');
			}
			self.firstInteraction = true;
		}

		if (!data) return true;
		
		var category = $(self.form).data("category");

		var term = $(self.form).data("product");
		var unit = "rollover";
		var first = "First term";

		var variables = {
			"product" : { "label" : "Product", "value" : ( term > 18 ? term / 12 + " year" : term  + " month") + " GIC" }, 
			"rate" : { "label" : "Interest Rate", "value" : parseFloat( $(self.form).data("rate") ).toFixed(2) + "%" },
			"deposit" : { "label" : "Opening Deposit", "value" : $("<div>" + $(self.form).data("deposit") + "</div>").formatCurrency().text() }
		}
		
		if ( category == "OSAV" || category == "MMDA") {
			if ($(self.form).data("futureon") == "on") {
				var future = $("<div>" + $(self.form).data("future") + "</div>").formatCurrency().text();
				var freq = "";
				switch( parseInt( $(self.form).data("frequency") ) ) {
					case 12: freq = "Monthly"; break;
					case 4: freq = "Quarterly"; break;
					case 1: freq = "Annual"; break;
				}
				variables.future = { "label" : freq + " Contribution", "value" : future };
			}
			
			term = $(self.form).data("duration");
			unit = "year";
			first = "1 year";
			
			switch (category) {
				case "OSAV":
					variables.product.value = "High Interest Savings Account";
				break;
				
			}
		} else {
			if ($(self.form).data("np") == "true" || $(self.form).data("product") == "24") {
				variables.product.value = $(self.form).data("productName");
			}
		}
		
		var fp = self.getFlashPrint(self.form);
		$(fp).find("table").addClass("oldtbl").css( { visibility: "hidden" } );
		
		var summary = "We're showing you how much you'd potentially save, based on the amount invested, selected interest rate, and the length of time you choose to grow your savings.";

		$(fp).append("<table class='newtbl stdtable' cellpadding='0' cellspacing='0'><thead></thead><tbody></tbody></table>")
			.find(".newtbl").attr("summary", summary);

		// Format the deposit and savings as currency.
		//
		var deposit = $("<div>" + $(self.form).data("deposit") + "</div>").formatCurrency().text();
		// var potential = $("<div>" + data[ data.length - 1 ] + "</div>").formatCurrency().text();

		// Append the form's field data.
		//
		for (var variable in variables) {
			$(fp).find(".newtbl tbody")
				.append("<tr class='" + variable + "'><td class='label'>" + variables[variable].label + ":</td>" +
					"<td class='value'>" + variables[variable].value + "</td></tr>")
		}
		
		// Append the detailed rows.
		//
		for (var i = 0; i < data.length; i++) {
			var cls = "detail";
			var lbl = ( category == "OSAV" || category == "MMDA" || category == "DDA" ? i + 1 : i );
			
			lbl += (lbl != 1) ? "s" : " ";
			lbl = lbl.substr(0, lbl.length-1) + " " + unit + lbl.substr(lbl.length-1);

			if (i == 0) { 
				lbl = first; 
				cls = "detail first"; }
			if (i == data.length - 1) { cls = "detail last"; }
			
			var moola = $("<div>" + (Math.round(data[i]*100) / 100) + "</div>").formatCurrency().text();

			var duration = self.convertMosYrs( ( i + 1 ) * term );
			if (category != "OSAV" && category != "MMDA" && category != "DDA") {
				duration = (duration != "" ? " <span>(" + duration + ")</span>" : "");
			} else {
				duration = "";
			}
				
			$(fp).find(".newtbl tbody").append("<tr class='" + cls + "'>" +
				"<td class='label'>" + lbl + duration + "</td><td class='value'>" + moola + "</td></tr>");
		}
		
		// Reset the flashprint div & table.
		//
		var newheight = $(fp).find(".newtbl").height() + 50;

		$(fp).find("table").not(".newtbl").addClass("oldtbl");
		
		$(fp).animate( { "height" : newheight + "px" }, 400, function() {
			$(this).find(".oldtbl").fadeOut(400, function() { $(this).remove(); }).end()
				.find(".newtbl").css({ "position":"relative", "top":"0", "left":"0", "visibility":"hidden" })
					.fadeIn(400, function() { $(this).removeAttr("style").removeClass("newtbl"); });
		});
		self.firstLoad = false;
		return this;
	},
	
	toggleTable: function(e) {

		var self = this;
		var $fp = $(self.form).siblings(".flashprint");
		var wastoggled = $fp.filter(".toggled").length;
		
		$fp.filter(".toggled").each( function() {
			$(this).slideUp( 500, function() {
				$(this).removeAttr("style").removeClass("toggled");
			});
		}).end()
			.not(".toggled").each( function() {
				if (!wastoggled) {
					$fp.css( { "height" : "0", "position" : "relative", "left" : "0", "top" : "0" })
						.each( function() { height = $(this).find("table").height() + 70; })
						.animate( { "height" : height+"px" }, 400, function() { $(this).addClass("toggled"); }); 
				}
		});
		
		$(self.form).find(".btn_table").find("input,a").val( (wastoggled ? "view" : "hide") + " table" );
	},
	

	updateRollover: function() {
		var self = this,
			times = parseInt( $(self.form).find("[name=duration]").val() ),
			term = parseInt( $(self.form).find("[name=product]").val() ),
			months = term * (times + 1),
			duration = self.convertMosYrs(months),
			msg = "The total duration of this GIC will be " + duration + ".";
		$(".item_duration .control .rollover").html(msg);
		
		return this;
	},
	convertMosYrs: function(months) {
		var duration = "";

		if (months > 12) {
			 var years = Math.floor(months / 12);
			 months = months - (years * 12);
			 duration = years + " year" + (years != 1 ? "s" : "");
			 if (months > 0) { duration += ", "; }
		}
		if (months > 0) {
			duration += months + " month" + (months != 1 ? "s" : "");
		}
		
		return duration;
	},
	alphaInvert: function(letter) {
		if (letter == " ") return true;
		
		var anumber = ("A").charCodeAt(0),
			number = letter.toUpperCase().charCodeAt(0),
			diff = 26 - number + anumber + 96;

		return String.fromCharCode(diff);
	},
	
	addCompareNote: function(rates) {

		// Add the date from the AJAX data.
		//
		var self = this,
			ally_date = ""
			competitor_date = "",
			national_date = "";
		
		if (rates.effdate) {
			ally_date = rates.effdate.Ally ? rates.effdate.Ally : "";
			competitor_date = rates.effdate.competitor ? rates.effdate.competitor : "";
			national_date = rates.effdate.national ? rates.effdate.national : "";
		}
		
		competitor_date = competitor_date ? "<p class='note'>Competitor APY's as of " + competitor_date +
		", provided by <a href='http://mybanktracker.com/' rel='external' target='_blank'>mybanktracker.com</a>.</p>" : "";
		
		national_date = national_date ? "<p class='note'>National average APY's as of " + national_date + 
				", provided by <a href='http://bankrate.com/' rel='external' target='_blank'>bankrate.com</a>.</p>" : "";
		
		$(self.form).find("p.note").remove().end()
			.find(".inner:first").append(national_date).append(competitor_date);
	},
	
	flashNote: "<h2>\n" +
			  "<strong><img alt='Please note: ' src='" + contextPath + "/docroot/ally-storefront/images/box-icon-info.png' class='icon'/></strong>\n" +
			  "Content on this page requires a newer version of Adobe Flash Player.\n" +
		  "</h2>\n" +
		  "<p><a rel='external' target='_blank' href='http://www.adobe.com/go/getflashplayer'><img \n" +
				"src='" + contextPath + "/docroot/ally-storefront/images/get_flash.gif' alt='Get Adobe Flash player' /></a></p>"
}

jQuery.fn.fadeFieldandChange = function(options) {
	var defaults = {
			currentValue: "",
			newValue: "",
			currentColor: $(this).css("color"),
			currentTiming: 450,
			newTiming: 600,
			onComplete: function() {} 
		},
		options = $.extend(defaults, options),
		valtxt = typeof $(this).attr("value") == "undefined" ? "text" : "value";
	
	// If no current value is set, use the value that's already there.
	//
	if (defaults.currentValue == "") {
		defaults.currentValue = valtxt == "text" ? $(this).text() : $(this).val();
	}
	
	// If the value starts at zero (i.e. a value the user cannot enter, 
	//   so this would be at load time), don't do a fade out.
	//
	if ( parseFloat(defaults.currentValue) > 0 ) {
		defaults.timing = 0;
	}

	if (defaults.currentValue != defaults.newValue) {
		
		$(this).animate( { "color" : "#FFFFF" }, defaults.currentTiming, function() {
			$(this).each( function() {
					if (valtxt == "text") {
						$(this).text(defaults.newValue);
					} else {
						$(this).val(defaults.newValue);
					}
				})
				.animate( { "color" : defaults.currentColor }, defaults.newTiming, function() {
					$(this).removeAttr("style");
					(defaults.onComplete)(0);
			});
		});
	}
	
	return this;
}

