var FortumProductConfigurationDisplay = (function(){
	var SWF_VERSION = 4; // increment when swf is updated to avoid caching
	var swfSerial = 0;
	var swfFile = "FortumForm.swf";
	forceRef = Offering.forceRef;
	function imgBase(){ return forceRef("link[rel=offering-components-img]").attr("href") + "/"; }
	function toggleBody(table){
		table.toggleClass("expanded");
		table.toggleClass("collapsed");				
	}
	function tickerDelta(current, target){
		if (current == target) return 0;
		var sgn = target > current ? 1 : -1;
		var max = Math.max(target, current), min = Math.min(target, current);
		var diff = max - min;
		var delta = (diff < 4) ? 1 : Math.floor(diff / 2);
		return delta * sgn;
	}
	function delayForDelta(delta){
		var SLOW = 200, MEDIUM = 150, FAST = 100, THRESHOLD_FAST = 25, THRESHOLD_SLOW = 10;
		var deltaAbs = Math.abs(delta);
		if (deltaAbs >= THRESHOLD_FAST) return FAST; // big step; fast
		else if (deltaAbs <= THRESHOLD_SLOW) return SLOW; // small step; slow
		else return MEDIUM; // medium step + speed
	}
	return {
		items: {},
		init: function(params){
			// assert "displayId" in params && "monthPriceLabel" in params 
			// && "annualPriceLabel" in params && "flashId" in params 
			// && "maxStep" in params
			if (params.displayId in this.items)
				throw new Error("Tried to re-initialize display: " + params.displayId);
			function monthlyPriceLabel(){ return $("#" + params.monthPriceLabel); }
			function annualPriceLabel(){ return $("#" + params.annualPriceLabel); }
			function self(){ return forceRef("#" + params.displayId); }
			function swf(){ return forceRef("#" + params.flashId); }
			
			self().find("thead").live("click", function(){
				toggleBody($(this.parentNode));
			});
			
			self().find(".submit .go-finish").click(function(){
				var submitId = this.getAttribute("id");
				Offering.showLoading(submitId);
				Offering.onPopupClose(function(){
					Offering.hideLoading(submitId);
				});
			});
			
			// Setup monthly vs annual price estimate display
			/*function bindPeriodToggler(from, period){
				from.parent().find(".price-period-toggler").click(function(){
					Offering.estimatePeriod(period);
				});
			}*/
			//bindPeriodToggler(monthlyPriceLabel, "annual");
			//bindPeriodToggler(annualPriceLabel, "monthly");

			$(".mon").parent().find(".price-period-toggler").click(function() {
				Offering.estimatePeriod("annual");
			});
			$(".yea").parent().find(".price-period-toggler").click(function() {
				Offering.estimatePeriod("monthly");
			});

			var swfHasLoaded = false;
			var swfLoadCallbacks = [];
			var swfSize = {width: 234, height: 175};
			var swfLoadCallbackName = "__FortumProductConfigurationDisplay_fire_onload_callback_" + swfSerial++;
			var attemptedCalls = 0;
			window[swfLoadCallbackName] = function(){
				if (swfHasLoaded) throw new Error("SWF onload callback invoked more than once");
				// SWF functions registered by ExternalInterface will throw if 
				// we call them directly, for some reason. Just let this callback
				// return and it goes away.
				setTimeout(function(){
					swfHasLoaded = true;
					while (swfLoadCallbacks.length) {
						try {
							swfLoadCallbacks[0]();
							attemptedCalls = 0;
							swfLoadCallbacks.shift();
						} catch (e) {
							// Wait some more if it wasn't enough to exit the 
							// callback from flash.
							if (++attemptedCalls == 10) throw e;
							else setTimeout(arguments.callee, 100);
						}
					}
					swfLoadCallbacks = null;
				}, 0);
			}
			window.setTimeout(function(){ // give clients a chance to call swfFile() before creating swf
				swfobject.embedSWF(
					imgBase() + swfFile + "?version=" + SWF_VERSION, 
					params.flashId, 
					swfSize.width, 
					swfSize.height, 
					"9",       // flash version 
					undefined, // Adobe express install URL
					{ functionsRegisteredCallback: swfLoadCallbackName },  // flashvars
					{ wmode: "transparent" }, // params  
					undefined, // attributes
					undefined  // onload callback 
				);
			}, 0);
			
			var annualFee = 0, kWhPrice = 0, consumption = 0;
			function annualCost(){ return annualFee + consumption * kWhPrice; }
			function priceUpdater(targetCalc, elmtLookup){
				return function (deltaCalc) { 
					var targetPrice = targetCalc();
					var elmt = elmtLookup();
					var currentPrice = parseInt(elmt.text()) || 0;
					var delta = deltaCalc(currentPrice, targetPrice);
					var newPrice = delta + currentPrice;
					elmt.text(newPrice);
					return newPrice == targetPrice; 
				};
			}
			function priceTickerStarter(updater){
				var tickerRunning = false;
				return function () {
					if (!tickerRunning){
						tickerRunning = true;
						setTimeout(function(){
							tickerRunning = false; // in case of exceptions
							var delta;
							if (!updater(function (c, t) { return delta = tickerDelta(c, t); })) {
								// ticker isn't finished
								priceTickerRunning = true;
								setTimeout(arguments.callee, delayForDelta(delta));
							}
						}, 0); 	
					} 
				};
			}
			
			var updateMonthCost = priceUpdater(function(){ 
				return Math.round(annualCost() / 12); 
			}, monthlyPriceLabel);		
			var monthCostStarter = priceTickerStarter(updateMonthCost);
			
			var updateAnnualCost = priceUpdater(function (){
				return Math.round(annualCost()); 
			}, annualPriceLabel);		
			var annualCostStarter = priceTickerStarter(updateAnnualCost);
			
			function runPriceTickers(){
				monthCostStarter();
				annualCostStarter();
			}
			function tickerUpdater(fn) { 
				return function () {
					fn.apply(this, arguments); 
					runPriceTickers(); 
					return this;
				};
			}
			function swfInvocation(funcName, argMap){
				return function(arg){
					if (!swfHasLoaded){
						var self = arguments.callee;					
						swfLoadCallbacks.push(function(){ 
							self(arg);
						});
					} else {
						var elmt = swf().get(0);
						if (!argMap.hasOwnProperty(arg))
							throw new Error("Argument can't be mapped: " + arg);
						elmt[funcName](argMap[arg]);
					}
					return this;
				};
			}
			var defaultConsumptionDisplaySet = false;
			var applyHousing = swfInvocation("sendTypeToFlash", { HOUSE: 1, APARTMENT: 2 });
			var item = this.items[params.displayId] = {
				swfFile : function (file) { swfFile = file; return this; },
				consumption: tickerUpdater(function(newConsumption) { consumption = newConsumption; }),
				kWhPrice: tickerUpdater(function(newPrice){ kWhPrice = newPrice; }),
				annualFee: tickerUpdater(function(newFee){ annualFee = newFee; }),
				environment: swfInvocation("sendStepToFlash", { GOOD: 1, BETTER: 2, BEST: 3 }),
				housing: function(houseType){
					applyHousing(houseType);
					if (!defaultConsumptionDisplaySet){
						var clazz = (houseType == "HOUSE") ? "monthly" : "annual";
						var c = Offering.getCookie();
						if(c){
							clazz = (c == "annual") ? "monthly" : "annual";
						}
						var sel = "div." + clazz + "-cost.cost-estimate span.price-period-toggler";
						self().find(sel).click();
						defaultConsumptionDisplaySet = true;
						this.finish();
					}
				},
				finish: function(){ 
					function diff(current, target){ return target - current; }
					updateMonthCost(diff);
					updateAnnualCost(diff);
					return this; 
				},
				step: function(n){
					if (n >= params.maxStep || n < 0) throw new Error("Bad step value: " + n);
					function pageImg(step){
						var file = "icon_form_page" + (step + 1) + (step == n ? "_active.gif" : ".gif");
						if (step == n)
						{
							if ((step + 1) == 1)
							{
								$("a.one").addClass("selected");
								$("a.two").removeClass("selected");
								$("a.three").removeClass("selected");
							}
							if ((step + 1) == 2)
							{
								$("a.two").addClass("selected");
								$("a.one").removeClass("selected");
								$("a.three").removeClass("selected");
							}
							if ((step + 1) == 3)
							{
								$("a.three").addClass("selected");
								$("a.one").removeClass("selected");
								$("a.two").removeClass("selected");
							}
						}
						return "<img src='" + imgBase() + file + "' alt='" + (step + 1) + "' " +
									"width='28' height='22' />\n";
					}				
					var imgs = [];
					for (var i = 0; i < params.maxStep; ++i)
						imgs.push(pageImg(i));
					self().find(".paging").html(imgs.join(""));
					function toggle(elmt, show){ // jQuery toggle(boolean) is broken (rly!)
						if (show) elmt.show();
						else elmt.hide();
					}
					var isFirst = n == 0, isLast = n == params.maxStep - 1;
					toggle(self().find(".submit .go-cancel"), isFirst);
					toggle(self().find(".submit .go-back"), !isFirst);
					toggle(self().find(".submit .go-next"), !isLast);
					toggle(self().find(".submit .go-finish"), isLast);
				}
			};
			return item;
		},
		flashItem: function (id) {
			forceRef("#" + id).effect("highlight", {}, 3000);
		}
	};
})();
