﻿
/**
 * The core namespace/object for the CO2 Calculator. 
 * @global co2calc
 * @module co2calc
 * @class co2calc
 * @static
 * @requires jQuery, tbelt, json 
 * 
 * Description of loadStart
 * @event co2calc.loadStart
 * 
 */

debugMode = 1;


(function($j, $tb) {
    var window = this,
    undefined;


    window["co2calc"] = {
        /**
         * The co2calc object wrapped in a jQuery object;
         * This is defined in co2calc.init();
         * @property jI
         * @type jQuery
         * @default null
         */
		jI:null,
		/**
		 * Defines whether a user is logged in or not;
		 * Set in the Calculator.master head;
		 * @property isLoggedIn
		 * @type Boolean
		 * @default false
		 */
		isLoggedIn:false,
		/**
		 * Where the user is directed if login is required. ReturnUrl parameter is set in co2calc.init() DOM ready.
		 * @property loginUrl
		 * @default "Login.aspx?ReturnUrl="
		 */
		loginUrl:"/Login.aspx?ReturnUrl=",
		
		/**
		 * Defines the containing URL for the calculator.
		 * @property containerUrl
		 * @default document.location.href
		 */
		containerUrl:document.location.href,
		/**
		 * Defines whether the CO2 Calculator is in the EarthEra website context;
		 * Set in the Calculator.master head;
		 * @property isExternal
		 * @type Boolean
		 * @default false
		 */
		isExternal:false,
		/**
		 * Defines the theme used for this calculator instance.
		 * @property theme
		 * @type String
		 * @default "Default"
		 */
		theme:"Default",
		/**
		 * The AJAX request for co2calc. 
		 * @property ajaxReq
		 * @type XMLHttpRequest
		 * @default null
		 */
		ajaxReq: null,
		
		/**
		 * Displays a global calculator message or error;
		 * Created in theme.js;
		 * Bound to co2calc.loadStart, co2calc.loadSuccess, co2calc.error events in init() method;
		 * @property messageBox
		 * @type MessageBox
		 * @default null
		 */
		messageBox:null,
		/**
		 * Displays a list of the user's sessions using co2calc.messageBox.
		 * Created in theme.js;
		 * @property sessionsRepeater
		 * @type SessionsRepeater
		 * @default null
		 */
		sessionsRepeater:null,
		/**
		 * Initializes the CO2 Calculator;
		 * @method init
		 * @return co2calc
		 */
        init: function() {
            var I = this;
			I.jI=$j(I);
			
			//get the cookie value as it is on page load, set co2calc._zipCode
			var co2cookie = co2calc.sessionCookie();	
			if(co2cookie!=null) co2calc._zipCode = JSON.parse(co2cookie).zipCode;
			I.sessionData(co2cookie);		
			I.getDataSet(false);
			
			
			
			$j(document).ready(function(){
				//needs the timeout so that it runs after the other document readies
				setTimeout(function(){
					I.sessionData(co2cookie);
				},100);
				
				//set the login URL
				I.loginUrl = "/Login.aspx?ReturnUrl="+I.containerUrl.replace(/^(http|https)(:\/\/)(.[^\/]*)\//i,"/");

			});
			
			
			return I;
        },
		
		
		/**
		 * co2calc.share namespace
		 * @class share
		 * @namespace co2calc
		 * @static
		 */
		share:(function(){
			/**
			 * Does nothing.
			 * @constructor
			 */
			function Share(){
				
			}
			
			Share.prototype = {
				/**
				 * Sends user to Twitter to approve and post generated comment.
				 * @method toTwitter
				 */
				toTwitter:function(){
					var I=this,
					baseUrl = "http://twitter.com/home",
					co2total = I._getTotal(),
					parms = {
						status:"My carbon footprint is "+co2total+" tons per year. Calculate yours: "
					},
					shareUrl = baseUrl+"?";
					
					$j.getJSON(
				      "http://json-tinyurl.appspot.com/?&callback=?",
				      {url: window.location.href.replace(/\/calculator.aspx(.*)?$/i,"")+"/shared.aspx?u="+co2calc.containerUrl+"&co2total="+co2total},
				      function(data){
							parms.status+=data.tinyurl;
							for(var prop in parms) shareUrl+=prop+"="+encodeURIComponent(parms[prop]+"&");
							window.open(shareUrl);
						    //alert(data.tinyurl);
				      }
				    );
					
					
				},
				/**
				 * Sends user to Facebook to approve and post generated comment.
				 * @method toFacebook
				 */
				toFacebook:function(){
					var I=this,
					baseUrl = "http://www.facebook.com/sharer.php",
					co2total = I._getTotal(),
					parms = {
						u:window.location.href.replace(/\/calculator.aspx(.*)?$/i,"")+"/shared.aspx?u="+co2calc.containerUrl+"&co2total="+co2total
					},
					shareUrl = baseUrl+"?";
					
					$j.getJSON(
				      "http://json-tinyurl.appspot.com/?&callback=?",
				      {url: parms.u},
				      function(data){
							parms.u=data.tinyurl;
							for(var prop in parms) shareUrl+=prop+"="+encodeURIComponent(parms[prop]+"&");
							window.open(shareUrl);
						    //alert(data.tinyurl);
				      }
				    );
					
				},
				/**
				 * Gets the total to be shared.
				 * @method _getTotal
				 * @private
				 */
				_getTotal:function(){
					var total;
					if(co2calc.widgets["Total"])
						total= co2calc.widgets["Total"]._total;
					else{
						for(var w=0; w<co2calc.widgets.list().length; w++){
							total+=co2calc.widgets.list()[w]._total;	
						} 
					}
					if(typeof(total)=="number") total = $tb.num.roundDecimal(total, 2);
					return total;
				}
			}
			
			
			var share = new Share();
			return share;			
		})(),
		
		
		/**
		 * co2calc.util namespace
		 * @class util
		 * @namespace co2calc
		 * @static
		 */
		util:{
			/**
			 * Displays a message as an overlay.
			 * @class MessageBox
			 * @namespace co2calc.util
			 * @extends tbelt.ui.Overlay
			 */
			MessageBox:(function() {
		        /**
		        * Employs the tbelt.ui.Overlay constructor;
		        * @constructor
		        * @param {Object} opts This object's properties are copied to the MessageBox instance.
		        */
		        function MessageBox(opts) {
		            var I = this;
		            $tb.ui.Overlay.apply(I, arguments);
		
		        }
		
		        $j.extend(MessageBox.prototype, $tb.ui.Overlay.prototype, {
		            /**
					 * The name of this object's class.
					 * @property className
					 * @type String
					 */
					className:"MessageBox",
					/**
					 * The innerHTML of the MessageBox.element on initialization.
					 * @property _html
					 * @type String
					 * @private
					 * @default ""
					 */
					_html:"",
					/**
					 * The message to be displayed by this MessageBox.
					 * @property message
					 * @type String
					 * @default ""
					 */
					message:"",
					/**
					 * Determine's whether the matte covers the entire document.
					 * @property matteFullScreen
					 * @type Boolean
					 * @default false
					 */
					matteFullScreen:true,
					/**
					 * Determines the speed at which the matte is shown/hidden.
					 * @property matteSpeed
					 * @type Number
					 * @default 200
					 */
					matteSpeed:200,
					/**
					 * Determines the opacity of the matte.
					 * @property matteOpacity
					 * @type Number
					 * @default .7
					 */
					matteOpacity:.7,
					/**
					 * If true or false, matte click event triggers the MessageBox.close(matteClick). When null, matte click does nothing.
					 * @property matteClick
					 * @type Boolean
					 * @default null
					 */
					matteClick:null,					
					/**
					 * This should be an array of keyCodes that will trigger MessageBox.hide(true);
					 * @property confirmKeys
					 * @type Array
					 * @default []
					 */
					confirmKeys:[],
					/**
					 * This should be an array of keyCodes that will trigger MessageBox.hide(false);
					 * @property confirmKeys
					 * @type Array
					 * @default []
					 */
					cancelKeys:[],
					/**
					 * When true, the MessageBox position will follow the mouse.
					 * @property followMouse
					 * @type Boolean
					 * @default false
					 */
					followMouse:false,
					/**
					 * When true, the MessageBox position will be adjusted when the window is scrolled.
					 * @property followScroll
					 * @type Boolean
					 * @default true
					 */
					followScroll:true,
					/**
					 * When true, the MessageBox position will be adjusted when the window is resized.
					 * @property followResize
					 * @type Boolean
					 * @default true
					 */
					followResize:true,
					
					/**
					 * Initializes this MessageBox.
					 * @method init
					 * @uses tbelt.ui.Overlay.init()
					 */
					init:function(){
						var I = this;
						$tb.ui.Overlay.prototype.init.apply(I, arguments);

						I._html = I.element.html();	
						
					},
					
					/**
					 * Shows this MessageBox; Employs tbelt.ui.Overlay.show();
					 * Toggles <select/> elements off in IE6.
					 * @method init
					 * @param msg {String} The message to be displayed. Overrides/reassigns MessageBox.message.
					 * @uses tbelt.ui.Overlay.show()
					 * @return MessageBox This MessageBox instance.
					 */
					show:function(msg){
						var I = this;
						if (msg != null) {
							I.message = msg;
							I.element.css({height:"",width:""});
							I.element.html(I._html.replace(/\{\$message\}/, I.message));
							I.position(false);
						}
						if($j.browser.msie && $j.browser.version.indexOf('6.')==0) $j("select").css({visibility:"hidden"});
						$tb.ui.Overlay.prototype.show.apply(I, []);
						return I;
					},
					/**
					 * Builds an HTML string with the parameters and calls show() method with resulting HTML; 
					 * @method showTemplate
					 * @param {HTMLElement|String} template The root HTML element to use as your template, or a string of HTML. 
					 * @param {Object} vars Variables to be replaced in template.
					 */
					showTemplate:function(template, vars){
						var I=this,
						html="";
						if(template.nodeName) template = template.outerHTML;
						
						html = template.replace(/\{\$(.[^}]*)\}/g,function(){
							return (vars.hasOwnProperty(arguments[1])) ? vars[arguments[1]] : "";
						});
						I.show(html);
						
						return I;
					},
					
					/**
					 * Hides the MessageBox; Employs tbelt.ui.Overlay.hide();
					 * Toggles select elements back on in IE6.
					 * @method hide
					 */
					hide:function(){
						var I = this;
						if($j.browser.msie && $j.browser.version.indexOf('6.')==0) $j("select").css({visibility:""});
						$tb.ui.Overlay.prototype.hide.apply(I, []);
					}
					
		
		        });
		
		        return MessageBox;
		
		
		    })(),
			
			/**
			 * 
			 * @class SessionsRepeater
			 * @namespace co2calc.util
			 * @extends tbelt.ui.Repeater
			 */
			SessionsRepeater:(function() {
		        /**
		        * Employs the tbelt.ui.Overlay constructor;
		        * @constructor
		        * @param {Object} opts This object's properties are copied to the MessageBox instance.
		        */
		        function SessionsRepeater(opts) {
		            var I = this;
		            $tb.ui.Repeater.apply(I, arguments);
		
		        }
		
		        $j.extend(SessionsRepeater.prototype, $tb.ui.Repeater.prototype, {
		            /**
					 * The name of this object's class.
					 * @property className
					 * @type String
					 */
					className:"SessionsRepeater",
					/**
					 * Defines the container node to be used with messageBox.showTemplate when SessionsRepeater.show() is called;
					 * Can be a jQuery element, jQuery selector, HTMLElement, 
					 * @property messageContainer
					 * @type jQuery selector|jQuery element|HTMLElement
					 * @default ""
					 */
					messageContainer:"",
					
					/**
					 * Initializes this SessionsRepeater.
					 * @method init
					 * @uses tbelt.ui.Repeater.init()
					 */
					init:function(){
						var I = this;
						
						I.messageContainer = $j(I.messageContainer);
						
						
						$tb.ui.Repeater.prototype.init.apply(I, arguments);
						
						I.getSessions();
						
						
					},
					/**
					 * Makes a call to the web service GetUserEntries method;
					 * Reassigns the data property based on sessions entries received;
					 * Intended to be a background process, so it does not trigger the global load message or use co2calc.ajaxReq;
					 * @method getSessions
					 * @return {SessionsRepeater} This SessionsRepeater instance.
					 */
					getSessions:function(){
						var I = this;
						if(!co2calc.isLoggedIn)return;
						$j.ajax({
							//url: "/DesktopModules/Calculator/master/data/GetUserEntries.xml",
							url:"/DesktopModules/CalculatorWebService/CO2Calculator.asmx/GetUserEntries",
							data:"",
							dataType:"xml",
							type:"POST",
							success:function(data){
								//alert(data);
								var xml = $j(data).find("DocumentElement > Entries"),
								data=[];
								var html = "";
								for(var x=0; x<xml.length; x++){
									var node = $j(xml[x]),
									id=parseInt(node.children("ID").text()),
									obj = JSON.parse(node.children("Data").text());				
									data.push({
										ID:parseInt(node.children("ID").text()),
										date:(node.children("DateSaved").text().replace(/([0-9\-]*)T.*/, "$1")),
										total:I._getSessionTotal(obj),
										json:node.children("Data").text(),
										doRestore:function(){
											co2calc.jI.trigger("co2calc.loadStart",{message:"Restoring session..."});
											co2calc.sessionData(this.json);
											co2calc.jI.trigger("co2calc.loadSuccess");
										}
									});
									data[x].date = data[x].date.replace(/([0-9]{4})-([0-9]{2})-([0-9]{2})/,"$2/$3/$1");
								}
								I.data = data;
								I.bind();
								if(xml.length==0) html = (co2calc.isLoggedIn) ? "You have no saved results." : "You must be logged in to save and view results.";
								
							}
						})
						return I;
						
					},
					/**
					 * Wraps the repeater HTML in the element represented by the messageContainer property;
					 * @method show
					 * @return {SessionsRepeater} This SessionsRepeater instance.
					 */
					show:function(){
						var I = this;
						if(!co2calc.isLoggedIn) {
							co2calc.gotoUrl(co2calc.loginUrl);
							return;
						}
						if(I.data.length>0)
							co2calc.messageBox.show(I.messageContainer[0].outerHTML);
						else
							//co2calc.messageBox.show(html.replace("{$message}", "You have no saved results."))
							co2calc.jI.trigger("co2calc.alert", {message: "You have no saved results."});
							
							//trace(html)
						return I;
					},
					/**
					 * Loops through the Uses the active view in a widget to represent its total;
					 * @method _getWidgetTotals
					 * @param {Object} obj The session's JSON object.
					 * @private
					 */
					_getSessionTotal:function(obj){
						var I = this,
						wName, widget,
						vName, view,
						total=0.00;
						for(wName in obj){
							widget = obj[wName];
							for(vName in widget){
								view = widget[vName];
								if(view.active) total+=view.total;
							}
						}
						total = $tb.num.roundDecimal(total, 2);
						return total;
					}

					
		
		        });
		
		        return SessionsRepeater;
		
		
		    })()
			
		},
		/**
		 * co2calc.widget namespace
		 * @class widget
		 * @namespace co2calc
		 * @static
		 */
        widget: {},
		/**
		 * Handles all widget instances;
		 * @class widgets
		 * @namespace co2calc
		 * @static
		 */
        widgets: {
			/**
			 * The Widget constructor adds an instance to this global handler;
			 * @method add
			 * @param {Widget} widget A Widget.
			 * @return {widgets} The co2calc.widgets object.
			 */
			add: function(widget) {
                var I = this;
                I[widget.name] = widget;
				return this;
            },
			/**
			 * Removes a widget from this global handler;
			 * @method remove
			 * @param {String} widgetName The name of the widget you want to remove. See Widget.name.
			 * @return {widgets} The co2calc.widgets object.
			 */
            remove: function(widgetName) {
                delete this[widgetName];
				return this;
            },
			/**
			 * Calls Widget.update() on all of the Widgets in this global handler;
			 * @method update
			 * @param {String} widgetName The name of the widget you want to remove. See Widget.name.
			 * @return {widgets} The co2calc.widgets object.
			 */
            update: function(widgetName) {	
				var widgetList = co2calc.widgets.list();
				for(var w=0; w<widgetList.length;w++){						
					widgetList[w].update();	
				}
                return this;
            },
			/**
			 * Compiles an array of all of the widgets in this global handler;
			 * @method list
			 * @return {Array} List of widgets in this global handler.
			 */
			list:function(){
				var widgetList=[], propName, widget;
				for (propName in co2calc.widgets) {					
					var widget = co2calc.widgets[propName];
					if (widget && widget.views && widget.total) {
						widgetList.push(widget);
					}
				}
				//console.dir(widgetList);
				return widgetList;
			},
			/**
			 * Gathers all of the properties
			 * @method toJSON
			 * @return {Object} An object containing all of the properties needed to store a user's input.
			 */
			toJSON:function(){
				var rootObj={zipCode:co2calc.zipCode()},
				widgetList = this.list(),
				widget;
				for(var w=0; w<widgetList.length;w++){						
					widget = widgetList[w];
					rootObj[widget.name] = widget.toJSON(null, true);						
				}
				//console.dir(rootObj);
				return rootObj;
			},
			/**
			 * Determines what this object should do with the data in co2calc.sessionData();
			 * @method fromJSON
			 * @return {widgets} The co2calc.widgets object.
			 */
			fromJSON:function(){
				var widgetList = co2calc.widgets.list(),
				viewList;
				co2calc.sessionDataFreeze=true,
				sessionData = JSON.parse(co2calc.sessionData());
				if(sessionData.zipCode && sessionData.zipCode!=co2calc.zipCode()) co2calc.zipCode(sessionData.zipCode);
				for(var w=0; w<widgetList.length; w++){						
					viewList = widgetList[w].views.list();
					for(var v=0; v<viewList.length; v++){
						viewList[v].fromJSON();
					}									
				}

				co2calc.sessionDataFreeze=false;
				co2calc.widgets.update();
				return this;
			}
        },
		/**
		 * The user's zip code.
		 * @property _zipCode
		 * @for co2calc
		 * @private
		 * @type String
		 * @default "00000"
		 */
        _zipCode: "00000",
		/**
		 * Gets or sets the user's zip code.
		 * @method zipCode
		 * @param {String} zip The user's zip code.
		 * @return {String} The _zipCode property.
		 */
        zipCode: function(zip) {
            var I = this;
            if (zip != null && zip != I._zipCode) {
                I._zipCode = zip;
                I.getDataSet();
            }
            return I._zipCode;
        },
		/**
		 * Used to display the user's sessions;
		 * Set in co2calc.init();
		 * @property sessionsRepeater
		 * @type SessionsRepeater
		 * @default null
		 */
		sessionsRepeater:null,
		/**
		 * A JSON string representing a user's input;
		 * See co2calc.sessionData();
		 * @property _sessionData
		 * @type String
		 * @private
		 * @default ""
		 */
		_sessionData:"",
		/**
		 * When true, sessionData() method will not change the _sessionData property, and will only return the current value of _sessionData;
		 * @property sessionDataFreeze
		 * @type Boolean
		 * @default false
		 */
		sessionDataFreeze:false,
		/**
		 * Gets or sets the _sessionData property, as well as the co2calc cookie;
		 * @method sessionData
		 * @param {Boolean|String} doSet When true, co2calc.widgets is converted to JSON string and stored; when it is a String, _sessionData is set directly;
		 * @return {String} The _sessionData property.
		 */
		sessionData:function(doSet){
			var I = this;
			if (!I.sessionDataFreeze && doSet) {
				if (doSet == true) {
					I._sessionData = JSON.stringify(I.widgets);					
				} else if (typeof(doSet) == "string") {
					var json=JSON.parse(doSet);
					//console.dir(json)
					I._sessionData = doSet;
					//fire the sessionData event when sessionData is set by a string
					I.jI.trigger("co2calc.sessionData", I._sessionData);
				}
				//update the session cookie
				co2calc.sessionCookie(I._sessionData);			
			}
			//trace(I._sessionData);
			var kb = I._sessionData.length/1024;			
			if(kb>4) throw new Error("co2calc.sessionData is greater than 4KB, the maximum cookie size.");
			//trace("co2calc.sessionData: "+I._sessionData.length + " length = " + kb + " KB"); //make sure the stored data is less than 4K (cookie limit)
			return I._sessionData; 
		},
		/**
		 * Gets or sets the co2calc cookie used for storing session data.
		 * @method sessionCookie
		 * @param {String} setTo The value of the cookie.
		 * @return {String} cookie
		 */
		sessionCookie:function(setTo){
			var I=this,
			cookie = $tb.util.cookie("co2calc", {path:"/DesktopModules/Calculator/instances/"});
			if (setTo != null) {
				cookie = $tb.util.cookie("co2calc", setTo, {path: "/DesktopModules/Calculator/instances/"});
			}
			
			return cookie;
		},
		/**
		 * Makes a call to the web service GetUserEntry method to receive the user data for a particular session;
		 * Dispatches co2calc.loadStart, then co2calc.loadSuccess event if AJAX request is successful, otherwise dispatches co2calc.error.
		 * Defines ajaxReq property as the current AJAX request;
		 * @method getSessionData
		 * @param {int} recordId The ID of the session you'd like to restore.
		 * @return {co2calc} The co2calc object.
		 */
		getSessionData:function(recordId){
			var I = this;

			co2calc.jI.trigger("co2calc.loadStart", "Loading session data...");
			if (I.ajaxReq != null) I.ajaxReq.abort();
			I.ajaxReq = $j.ajax({
                //url: "/DesktopModules/Calculator/master/data/GetUserEntry.xml",
				url: "/DesktopModules/CalculatorWebService/CO2Calculator.asmx/GetUserEntry",
                data: "recordToLoad="+recordId,
                dataType:"xml",
                type: "POST",
                success: function(data) {
					var xml = $j(data).find("string");
					if (!xml.text().match(/^error.*/i)) {
						co2calc.sessionData(xml.text());
						co2calc.jI.trigger("co2calc.loadSuccess");
					}else{
						this.error();
					}
                },
                error: function(xmlReq) {
                    //alert(xmlReq.responseText);
					co2calc.jI.trigger("co2calc.error",{title: "Error", message: "Unable to load session data."});
                },
                complete: function(xmlReq) {
                    co2calc.ajaxReq = null;
                }
            });

			return I;
			
		},
		/**
		 * Makes a call to the web service SaveUserEntry method to save the user data for the current session;
		 * Uses the data currently in co2calc.sessionData();
		 * Calls co2calc.getUserSessions() if successful;
		 * Dispatches co2calc.loadStart, then co2calc.alert event if AJAX request is successful, otherwise dispatches co2calc.error.
		 * Defines ajaxReq property as the current AJAX request;
		 * @method saveSessionData
		 * @return {co2calc} The co2calc object.
		 */
		saveSessionData:function(){
			var I = this;
			if(!I.isLoggedIn) co2calc.gotoUrl(co2calc.loginUrl);
			co2calc.jI.trigger("co2calc.loadStart", "Saving session data...");
			if (I.ajaxReq != null) I.ajaxReq.abort();
			I.ajaxReq = $j.ajax({
                //url: "/DesktopModules/Calculator/master/data/SaveUserEntry.xml",
				url: "/DesktopModules/CalculatorWebService/CO2Calculator.asmx/SaveUserEntry",
                data: "entry="+I.sessionData(),
                dataType:"xml",
                type: "POST",
                success: function(data) {
					//trace(xml.text())
					var xml = $j(data).find("string");
					if (xml.text() && xml.text().toLowerCase() == "true") {
						co2calc.sessionsRepeater.getSessions();
						co2calc.jI.trigger("co2calc.alert", {title: "Session saved:", message:"You can restore this session at any time by using the \"View Saved Results\" feature, or through your site profile."});
					} else 
						this.error();
                },
                error: function(xmlReq) {
                    //alert(xmlReq.responseText);
					co2calc.jI.trigger("co2calc.error",{title:"Error", message:"Unable to save session data."});
                },
                complete: function(xmlReq) {
                    co2calc.ajaxReq = null;
                }
            });

			return I;
		},
		
		/**
		 * Holds all of the Zip Code data received from the web service;
		 * See getDataSet();
		 * @property dataSet
		 * @type Object
		 * @default null
		 */
		dataSet: null,
		/**
		 * Makes a call to the web service GetDataSet method to receive the data for a given zip code;
		 * Uses zipCode() method for zip code value;
		 * Initial call to this in co2calc.init() calls
		 * Dispatches co2calc.loadStart, then co2calc.loadSuccess event if AJAX request is successful, otherwise dispatches co2calc.error.
		 * Defines ajaxReq property as the current AJAX request;
		 * @method getDataSet
		 * @param isAsync {Boolean} Determines whether the AJAX request is asynchronious or not. Default is true.
		 * @return {co2calc} The co2calc object.
		 */
        getDataSet: function(isAsync) {
            var I = this;
			if(I.messageBox && isAsync==null)isAsync=true;

			I.jI.trigger("co2calc.loadStart", {message: "Loading zip code data..."});
			
            if (I.ajaxReq != null) I.ajaxReq.abort();
			
            I.ajaxReq = $j.ajax({
                //url: "/DesktopModules/Calculator/master/data/GetDataSet.xml",
				url:"/DesktopModules/CalculatorWebService/CO2Calculator.asmx/GetDataSet",
                data: "ZipCode="+co2calc.zipCode(),
                dataType:"xml",
                type: "POST",
				async:isAsync,
                success: function(data) {
					var xml = $j(data).find("CalculatorDataSet"),
					newDS = $tb.util.XMLtoJSON(xml[0]).CalculatorDataSet;
                    if (!newDS.Error) {
						//console.dir(newDS)
						co2calc.dataSet = newDS;
						co2calc.widgets.update();
						co2calc.jI.trigger("co2calc.loadSuccess");
					} else this.error()					
							
                },
                error: function(xmlReq) {
                    //alert(xmlReq.responseText);
					co2calc.jI.trigger("co2calc.error", {title: "Error", message: "Unable to load zip code data."});
                },
                complete: function(xmlReq) {
                    co2calc.ajaxReq = null;
                }
            });
			return I;
        },
		/**
		 * Converts pounds to metric tons.
		 * @method toTons
		 * @param {float} pounds Number of pounds to convert to tons.
		 */
		
		toTons:function(pounds){
			
			return pounds / (1000/.45359237);
		},
		
		/**
		 * Resets the calculator to the default values.
		 * @method reset
		 */
		reset:function(){

			co2calc.sessionData('{"zipCode":"00000","Household":{"Quick":{"total":11.693612493698028,"average":11.693612493698028,"active":true,"zipCode":{},"homeType":{"typical":"SD"},"numRooms":{"typical":6},"numResidents":{"typical":2.7},"sqFtPerRoom":{"typical":295}},"Detailed":{"total":0,"average":0,"active":false,"acType":{"typical":1},"acDryerRefrigerator":{"user":false,"typical":false},"cflLighting":{"user":false,"typical":false},"changeFridgeFilters":{"user":false,"typical":false},"doublePanedWindows":{"user":false,"typical":false},"energyStar":{"user":false,"typical":false},"energyStarAppliances":{"user":false,"typical":false},"extraFreezer":{"user":false,"typical":false},"extraInsulation":{"user":false,"typical":false},"extraTVsComputers":{"user":false,"typical":false},"heatedPool":{"user":false,"typical":false},"heatingFuelType":{"typical":2},"homeType":{"typical":"SD"},"hotTub":{"user":false,"typical":false},"houseAge":{"typical":33.66867046333404},"lowerWaterHeaterTemp":{"user":false,"typical":false},"lowFlowShowerheads":{"user":false,"typical":false},"multipleRefrigerators":{"user":false,"typical":false},"numRooms":{"typical":6},"numAdults":{"typical":2},"numChildren":{"typical":1},"numResidents":{"typical":2.7},"progThermostat":{"user":false,"typical":false},"squareFeet":{"typical":1770},"weatherStripping":{"user":false,"typical":false},"zipCode":{}}},"Driving":{"Quick":{"total":0,"average":10.13172754980088,"active":true,"zipCode":{},"vehicles":{"user":[{"mpg":24}],"typical":[{"vehicleType":3,"annualMileage":23152.009925591763,"mpg":24}]}},"Detailed":{"total":0,"average":0,"active":false,"zipCode":{},"vehicles":{"user":[{"vehicleType":3}],"typical":[{"vehicleType":3,"annualMileage":23152.009925591763,"mpg":24}]}}},"AirTravel":{"Quick":{"total":0,"average":1.5397488288280032,"active":true,"flightHours":{"typical":17.20000000000797}}},"Total":{},"Actions":{}}');

		},
		
		/**
		 * Sends the user to a URL; If co2calc.isExternal=true, a new window is opened; otherwise the parent window is used.
		 * @method gotoUrl
		 * @property url The url the user will be sent to.
		 * @property forceNewWindow Will force a new window to open.
		 */
		gotoUrl:function(url, forceNewWindow){
			if(window.parent && !forceNewWindow){
				window.parent.location=url;
			}else{
				window.open(url)
			}
		}
		
		
    };
	
	//initialize the calculator
   co2calc.init();
	
	//when the DOM has loaded...
	$j(document).ready(function(){
		

		//!!!! FOR TESTING. ADD YOUR LOCAL HOSTNAME TO THE REGEX BELOW.
		if (window.location.hostname.match(/fpl.co2calc/)) {
			if ($tb.url.queryString("external") == "true") co2calc.isExternal = true;
			co2calc.isLoggedIn = true;
			
		}
	
	});
	
	
	
	

})(jQuery, tbelt);
