window.WNT || (function($, _, undefined) {

	WNT = {
		equalSpacing: function (nodes){
			var parentWidth = $(nodes[0].parentNode).width();

			var nodesWidth = 0;
			$(nodes).each(function (i, node){
				 nodesWidth += $(node).css('marginRight', 0).css('marginLeft', 0).outerWidth();
			});

			var margin = Math.floor((parentWidth - nodesWidth) / (nodes.length - 1));
			var extraPixels = (parentWidth - nodesWidth) - (nodes.length - 1) * margin;

			$(nodes).each(function (i, node){
				 if (i > 0){
					  var myMargin = extraPixels > 0 ? margin+1: margin;
					  extraPixels--;
					  $(node).css('marginLeft', myMargin);
				 }
			});
		},

		navEqualSpacing: function (){
			var navNodes = $('.wntNavBar');
			$(navNodes).each(function (i, navNode){
				WNT.equalSpacing($('.wntNavBarItem', $(navNode)));
			});
		},

		bind: function (targetNode, bindings, selectedIndex){
			var nodeCollection = $(targetNode.children);
			for (var i in bindings){
				$(bindings[i].sourceNode).bind('change', function(){
					_filter();
				});
			}
			var startVal = $(targetNode).val();
			_filter();
			$(targetNode).val(startVal);

			function _filter(){
				var filteredNodes = nodeCollection;
				for (var i in bindings){
					var filterKey = 'data-wnt-bind-' + bindings[i].key;
					var filterValue = $(bindings[i].sourceNode).val();
					var formatedValue = "|"+filterValue+"|";
					if (filterValue != ""){
						filteredNodes = filteredNodes.filter(function(){
							if ($(this).attr(filterKey) === undefined){
								return true;
							}
							return $(this).attr(filterKey).indexOf(formatedValue) >= 0;
						});
					}
				}
				nodeCollection.remove();
				$(targetNode).append(filteredNodes).attr('selectedIndex', selectedIndex).trigger('change').trigger('bindupdate');
			}
		},

		addRemoveList: function (baseNode) {
			var self = {};

			//*************************************************************
			// TODO: 
			// jQuery doesn't filter correctly on namespaced attributes
			// So we have to do it manually 
			//*************************************************************

			var listNode = $('select[data-wnt-addremovelist=list]', baseNode)[0];
			$(listNode).bind('dblclick', function(){self.addItem();});
			var selectedNode = $('select[data-wnt-addremovelist=selected]', baseNode)[0];
			$(selectedNode).bind('dblclick', function(){self.removeItem();});
			var fieldNode = $('input[data-wnt-addremovelist=field]', baseNode)[0];
			var maxSelected = $(fieldNode).attr('data-wnt-addremovelist-maxitems');
			var addNodes = $('span[data-wnt-addremovelist=add]', baseNode).click(function(){self.addItem();});
			var removeNodes = $('span[data-wnt-addremovelist=remove]', baseNode).click(function(){self.removeItem();});

			var selectedNodes = $([]);

			_load();

			self.addItem = function() {
				$('option:selected', listNode).each(function(){
					var listItemNode = this;
					if (selectedNodes.size() < maxSelected){
						if (typeof(listItemNode) != "undefined"){
							var matched = selectedNodes.filter(function(){
								return this.listNode === listItemNode;
							});
							if (matched.size() == 0){
								var newNode = $(listItemNode).clone();
								$(listItemNode).attr('disabled', 'disabled');
								$(selectedNode).append(newNode);
								$(listNode).attr('selectedIndex', -1);
								$(selectedNode).attr('selectedIndex', -1);
								selectedNodes.push({listNode: listItemNode, selectedNode: newNode[0]});
								_generateValue();
							}
						}
					}
				});
			}

			self.removeItem = function() {
				$('option:selected', selectedNode).each(function(){
					var selectedItemNode = this;
					if (typeof(selectedItemNode) != "undefined"){
						selectedNodes = selectedNodes.filter(function(){
							if (this.selectedNode === selectedItemNode){
								$(this.listNode).attr('disabled', false);
								return false;
							} else {
								return true;
							}
						});
						$(selectedItemNode).remove();
						_generateValue();
					}
				});
			}

			self.removeAll = function() {
				$('option', selectedNode).attr("selected","selected");
				self.removeItem();
			}

			function _load() {
				$(selectedNode.children).each(function(){
					var listItemNode = $('[value='+this.value+']', listNode)[0];
					if (typeof(listItemNode) == "undefined"){
						$(this).remove();
					} else {
						selectedNodes.push({listNode: listItemNode, selectedNode: this});
					}
				});

				_generateValue();
			}

			function _generateValue() {
				$(fieldNode).val($(selectedNode.children).map(function () {
					return this.value;
				}).toArray().join(","));
				$(fieldNode).change();
			}

			return self;
		},

		slideShow: function (slideShowId, images, params) {
			var self = {};

			var baseNode = document.getElementById(slideShowId);
			var numberOfImgToDisplay = (params['numberOfImgToDisplay'] === undefined) ? 5 : params['numberOfImgToDisplay'];
			var outterImgWidth = (params['outterImgWidth'] === undefined) ? 106 : params['outterImgWidth'];
			var selectedImg = (params['selectedImg'] === undefined) ? 0 : params['selectedImg'];

			var thumbsBar = $(".wntThumbsBar", $(baseNode));
			var thumbs = $(".wntThumbsThumb", $(baseNode));
			$.each(thumbs, function (i, thumb){
				$(thumb).click(function() {
					self.selectThumb(i);
				});
			});

			var thumbsSlider = $(".wntThumbsSlider", $(baseNode));
			var selected = 0;
			var index = 0;
			var slideLength = 400;
			var bounceLength = 300;
			var bounceDistance = 10;
			var animating = false;
			var queueSlideLeft = 0;
			var queueSlideRight = 0;

			var showingLightBox = false;

			var imgNode = $(".wntSlideShowImage", $(baseNode))[0];
			var leftButton = $(".wntThumbsLeft", $(baseNode));
			leftButton.click(function() {
				self.slideRight();
			});

			var rightButton = $(".wntThumbsRight", $(baseNode));
			
			rightButton.click(function() {
				self.slideLeft();
			});

			var slideShowExpandLink = $(".wntSlideShowExpandLink", $(baseNode));
			slideShowExpandLink.click(function() { self.showLightbox(); });

			var lightboxBGNode = $(".wntLightboxBG", $(baseNode));

			var lightboxOverlayNode = $(".wntLightboxOverlay", $(baseNode));
			$(lightboxOverlayNode).click(function(){ self.hideLightbox(); });

			var lightboxContainerNode = $(".wntLightboxContainer", $(baseNode));
			$(lightboxContainerNode).click(function(event){
				if(event.stopPropagation){
					event.stopPropagation(); //For 'Good' browsers
				} else { 
					event.cancelBubble = true;  //For IE
				}
			});

			var lightboxImgNode = $(".wntLightboxImage", $(baseNode))[0];
			var lightboxThumbsNode = $(thumbsBar).clone(true);
			var lightboxThumbsWrapper = $(".wntLightboxThumbsWrapper", $(baseNode));
			var lightboxThumbs = $(".wntThumbsThumb", $(lightboxThumbsNode));
			var lightboxThumbsSlider = $(".wntThumbsSlider", $(lightboxThumbsNode));
			var lightboxRightButton = $('.wntThumbsRight', $(lightboxThumbsNode));
			var lightboxLeftButton = $('.wntThumbsLeft', $(lightboxThumbsNode));
			var lightboxLeft = $(".wntLightboxLeft", $(baseNode));
			$(lightboxLeft).bind("click dblclick", function(event) { 
				self.prevPicture(); 
				event.preventDefault(); 
				if(event.stopPropagation){
					event.stopPropagation(); //For 'Good' browsers
				} else { 
					event.cancelBubble = true;  //For IE
				}
			});

			var lightboxRight = $(".wntLightboxRight", $(baseNode));
			$(lightboxRight).click(function() { self.nextPicture(); });

			var lightboxCloseNode = $(".wntLightboxClose", $(baseNode));
			$(lightboxCloseNode).click(function() { self.hideLightbox(); });

			var lightboxCloseLink = $(".wntLightboxCloseLink", $(baseNode));
			$(lightboxCloseLink).click(function() { self.hideLightbox(); });

			$(lightboxThumbsWrapper).append(lightboxThumbsNode);

			// Move these out to the body to fix an IE7 bug
			$(baseNode).append(lightboxBGNode);
			$(baseNode).append(lightboxOverlayNode);


			// Prevent image from being selected
			$('.wntLightboxContainer')[0].onmousedown = function() {return false;};
			$('.wntLightboxContainer')[0].onselectstart = function() {return false;};

			// Set change max height to fit window height
			$(window).resize(_setLightboxImgDimentions);
			_setLightboxImgDimentions();

			// Set default states
			_setSelected(selected);
			_setIndex(index);
			
			self.showLightbox = function () {
				$(lightboxBGNode).show();
				$(lightboxOverlayNode).show();
				showingLightBox = true;
			}

			self.hideLightbox = function () {
				$(lightboxBGNode).hide();
				$(lightboxOverlayNode).hide();
				showingLightBox = false;
				self.selectThumb(selected);
				thumbsSlider.css('left', lightboxThumbsSlider.css('left'));
				_setIndex(index);
			}

			self.slideLeft = function () {
				if (index+numberOfImgToDisplay < thumbs.length){
					if (animating){
						queueSlideLeft++;
					} else {
						animating = true;
						_setIndex((index + 2*numberOfImgToDisplay >= thumbs.length)?thumbs.length-numberOfImgToDisplay:index+numberOfImgToDisplay);
						_slide("left");
					}
				}
			}

			self.slideRight = function () {
				if (index > 0){
					if (animating){
						queueSlideRight++;
					} else {
						animating = true;
						_setIndex((index - numberOfImgToDisplay < 0)?0:index-numberOfImgToDisplay);
						_slide("right");
					}
				}
			}

			self.nextPicture = function(){
				self.selectThumb(selected + 1);
			}

			self.prevPicture = function(){
				self.selectThumb(selected - 1);
			}

			self.selectThumb = function (i) {
				if (i >= 0 && i < thumbs.length){
					if (!showingLightBox){
						imgNode.src = images[i];
					}
					lightboxImgNode.src = images[i];
					$(thumbs[selected]).addClass("wntThumbsThumbSeen").removeClass("wntThumbsThumbSelected");
					$(thumbs[i]).addClass("wntThumbsThumbSelected");
					$(lightboxThumbs[selected]).addClass("wntThumbsThumbSeen").removeClass("wntThumbsThumbSelected");
					$(lightboxThumbs[i]).addClass("wntThumbsThumbSelected");
					_setSelected(i);
				}
			}

			function _setLightboxImgDimentions() {
				$(lightboxImgNode).css('max-height', $(window).height() - 160).css('max-width', $(window).width() - 130);
			}

			function _setIndex(newIndex){
				index = newIndex;
				if (index == 0){
					if (!showingLightBox){
						$(leftButton).addClass('wntDisabled');
					}
					$(lightboxLeftButton).addClass('wntDisabled');
				} else {
					if (!showingLightBox){
						$(leftButton).removeClass('wntDisabled');
					}
					$(lightboxLeftButton).removeClass('wntDisabled');
				}
				if (index + numberOfImgToDisplay >= thumbs.length){
					if (!showingLightBox){
						$(rightButton).addClass('wntDisabled');
					}
					$(lightboxRightButton).addClass('wntDisabled');
				} else {
					if (!showingLightBox){
						$(rightButton).removeClass('wntDisabled');
					}
					$(lightboxRightButton).removeClass('wntDisabled');
				}
			}

			function _setSelected(newSelection){
				selected = newSelection;
				if (selected == 0) {
					$(lightboxLeft).addClass('wntDisabled');
				} else {
					$(lightboxLeft).removeClass('wntDisabled');
				}
				if (selected == thumbs.length-1 || thumbs.length == 0) {
					$(lightboxRight).addClass('wntDisabled');
				} else {
					$(lightboxRight).removeClass('wntDisabled');
				}
			}

			function _slide(direction) {
				var leftPos = index * outterImgWidth * -1;
				var firstBounce = (direction == "left")?leftPos + bounceDistance : leftPos - bounceDistance;
				var secondBounce = (direction == "left")?leftPos - bounceDistance : leftPos + bounceDistance;

				if (!showingLightBox){
					thumbsSlider.animate({left: firstBounce}, slideLength);
				}
				lightboxThumbsSlider.animate({left: firstBounce}, slideLength, function (){
					if (!_checkQueue()){
						if (!showingLightBox){
							thumbsSlider.animate({left: secondBounce}, bounceLength);
						}
						lightboxThumbsSlider.animate({left: secondBounce}, bounceLength, function(){
							if (!_checkQueue()){
								if (!showingLightBox){
									thumbsSlider.animate({left: leftPos}, bounceLength);
								}
								lightboxThumbsSlider.animate({left: leftPos}, bounceLength, function(){
									animating = false;
									_checkQueue();
								});
							}
						});
					}
				});
			}

			function _checkQueue() {
				if (queueSlideRight > queueSlideLeft){
					animating = false;
					queueSlideRight = 0;
					queueSlideLeft = 0;
					self.slideRight();
					return true;

				} else if (queueSlideLeft > queueSlideRight) {
					animating = false;
					queueSlideRight = 0;
					queueSlideLeft = 0;
					self.slideLeft();
					return true;

				} else {
					return false;
				}
			}

			return self;
		},


		tab: function (nodeId){
			var self = {};
			var tabNode = document.getElementById(nodeId);
			var tabs = $('.wntTabTab', $(tabNode));
			var divs = $('.wntTabContent', $(tabNode));

			$.each(tabs, function(index, tab){
				var tabLink = $("a", tab);
				var href = tabLink.attr('href');

				// If the href starts with a '#' we link it to the proper div, otherwise we leave the link alone
				// We also make clicking the tab behave the same as clicking the link
				if (href.substring(0, 1) == "#"){
					tabLink.click(function (event){
						event.preventDefault();
						self.switchTab(index);
					});
					$(tab).click(function (){
						self.switchTab(index);
					});
				} else {
					$(tab).click(function (){
						window.location = href;
					});
				}
			});

			self.switchTab = function (selectedTab){
				$.each(tabs, function(index, tab){
					if (index == selectedTab){
						$(tab).addClass('wntTabTabSelected');
						$(divs[index]).addClass('wntTabContentSelected');
					} else {
						$(tab).removeClass('wntTabTabSelected');
						$(divs[index]).removeClass('wntTabContentSelected');
					}
				});
			}

			return self;
		},


		/*
		 * MapTracks
		 */

		MAP_ID: 0,
		CONTROL_ID: 0,

		map: function (baseNode, params){
			var self = {baseNode: baseNode};

			var mapId = WNT.MAP_ID++;

			// Save node and params
			var width = $(baseNode).width();
			var height = $(baseNode).height();
			var mapZoomLevel = (params['mapZoomLevel'] === undefined) ? 8 : params['mapZoomLevel'];
			var houseViewZoomLevel = (params['houseViewZoomLevel'] === undefined) ? 1 : params['houseViewZoomLevel'];
			var centerLat = (params['centerLat'] === undefined) ? 44.970104 : params['centerLat'];
			var centerLng = (params['centerLng'] === undefined) ? -93.256915 : params['centerLng'];
			var hasStreetView = (params['hasStreetView'] === undefined) ? false : params['hasStreetView'];
			var isMoveable = (params['isMoveable'] === undefined) ? true : params['isMoveable'];
			var hasMiniMap = (params['hasMiniMap'] === undefined) ? false : params['hasMiniMap'];
			var showScales = (params['showScales'] === undefined) ? true : params['showScales'];
			var provider = (params['provider'] === undefined) ? "bing" : params['provider'];

			// Save starting values for reset
			var startMapZoomLevel = mapZoomLevel;
			var startCenterLat = centerLat;
			var startCenterLng = centerLng;

			// Mapquest pans based on a %. So only one pan is needed
			var mapquestPan = (params['mapquestPan'] === undefined) ? 25 : params['mapquestPan'];
			var mapquestMaxZoom = (params['mapquestMaxZoom'] === undefined) ? 16 : params['mapquestMaxZoom'];
			var mapquestMinZoom = (params['mapquestMinZoom'] === undefined) ? 4 : params['mapquestMinZoom'];

			// Bing pans based on pixels. So we need separate vertical and horizontal pan amounts
			var bingVerticalPan = (params['bingVerticalPan'] === undefined) ? 75 : params['bingVerticalPan'];
			var bingHorizontalPan = (params['bingHorizontalPan'] === undefined) ? 100 : params['bingHorizontalPan'];

			// IE6 has several bugs with birdseye view in bing maps
			// So we will disable that option on IE6
			var hasHouseView = (params['hasHouseView'] === undefined) ? false : params['hasHouseView'];
			if ($.browser.msie && $.browser.version.substring(0,1) == 6){
				hasHouseView = false;
			}

			var currentView = "";

			// Add child divs to place maps in
			// Since google street view is flash, we don't need a div for it
			var bingMapNode = document.createElement('div');
			$(bingMapNode).attr('id', 'wntMtBing' + mapId).css('width', width).css('height', height).css('position', 'relative').hide();
			$(baseNode).append(bingMapNode);

			var mapquestNode = document.createElement('div');
			$(mapquestNode).attr('id', 'wntMtMapquest' + mapId).css('width', width).css('height', height).hide();
			$(baseNode).append(mapquestNode);


			// Create maps
			
			// Map Quest
			
			var mapquestMap = null;
			var bingHouseView = null;
			if (provider === "mapquest"){
				mapquestMap = new MQA.TileMap(mapquestNode, mapZoomLevel, new MQA.LatLng(centerLat, centerLng));
				mapquestMap.setLogoPlacement(MQA.MapLogo.MAPQUEST, new MQA.MapCornerPlacement(MQA.MapCorner.BOTTOM_LEFT, new MQA.Size(0,5)));
				if (showScales){
					mapquestMap.setLogoPlacement(MQA.MapLogo.SCALES, new MQA.MapCornerPlacement(MQA.MapCorner.TOP_RIGHT, new MQA.Size(0,5)));
				} else {
					mapquestMap.setLogoPlacement(MQA.MapLogo.SCALES, new MQA.MapCornerPlacement(MQA.MapCorner.TOP_LEFT, new MQA.Size(0,5000)));
				}

				if (hasMiniMap){
					
					// NOTE: You have to load this control in the function attached to MQA.withModule
					MQA.withModule('overviewmapcontrol', function(){
						mapquestMap.addControl(new MQA.OverviewMapControl(), new MQA.MapCornerPlacement(MQA.MapCorner.BOTTOM_RIGHT, new MQA.Size(0,0)));
					});
				}

				if (!isMoveable){
					mapquestMap._unwireDOMEvents();
				}

				// Add mapquest event listeners
				MQA.EventManager.addListener(mapquestMap, "zoomend", _zoomEnd, self);
				MQA.EventManager.addListener(mapquestMap, "moveend", _moveEnd, self);
				MQA.EventManager.addListener(mapquestMap, "movestart", _moveStart, self);

				// TODO: reenable after we get ie fix from mapquest
				/*
				var zoomControl = new MQA.RectangleZoomControl( new MQA.MapCornerPlacement(MQA.MapCorner.start_LEFT, new MQA.Size(0,0)));
				mapquestMap.addControl(zoomControl);
				*/
				MQA.withModule('mousewheel', function() {
					mapquestMap.enableMouseWheelZoom();
				});
				if (hasHouseView){
					$(bingMapNode).show();
					bingHouseView = new VEMap(bingMapNode.id);
					bingHouseView.LoadMap(new VELatLong(centerLat, centerLng), houseViewZoomLevel, VEMapStyle.Birdseye);
					bingHouseView.HideDashboard();

					// The following line gets the hidden map closer to where it should be
					// so when we do show it the first time, the map doesn't slide as much
					bingHouseView.SetCenter(new VELatLong(centerLat, centerLng));

					// Remove key events except for arrows
					bingHouseView.AttachEvent("onkeydown", function(e){
						if (e.keyCode > 40 || e.keyCode < 37){
							return true;
						}
						return false;
					});
					bingHouseView.AttachEvent("onkeyup", function(e){
						if (e.keyCode > 40 || e.keyCode < 37){
							return true;
						}
						return false;
					});
					bingHouseView.AttachEvent("onkeypress", function(e){
						if (e.keyCode > 40 || e.keyCode < 37){
							return true;
						}
						return false;
					});

					bingHouseView.AttachEvent("onendzoom", function(){_zoomEnd()});
					bingHouseView.AttachEvent("onobliquechange", function(){_orientationChanged()});


					// Since we don't know when the IsBirdseyeAvalable() is actually returning the correct result
					// we poll it every 500ms
					window.setInterval(function(){_houseViewClientHandler();}, 500);

					// Fix bug with bing maps in firefox 3.5
					 if (navigator.userAgent.indexOf("Firefox/3.5") != -1){
						bingMapNode.addEventListener('DOMMouseScroll', function (e){
							e.stopPropagation();
							e.preventDefault();
							e.cancelBubble=false;
							return false;		
						}, false);
					 }
					$(bingMapNode).hide();
					
				}
			} 

			// Google
			
			// We need to create and destroy the street view flash app
			// to get it to work in all browsers
			var googleStreetView = null;
			var isStreetViewAvailable = false;
			var googleStreetViewClient = null;

			if (hasStreetView){
				googleStreetViewClient = new GStreetviewClient();
				googleStreetViewClient.getNearestPanoramaLatLng(new GLatLng(centerLat, centerLng), function (latLng) {_streetViewClientHandler(latLng);})
			}

			// Bing

			var isHouseViewAvailable = false;
			if (provider === "bing"){
				$(bingMapNode).show();
				bingHouseView = new VEMap(bingMapNode.id);
				bingHouseView.LoadMap(new VELatLong(centerLat, centerLng), mapZoomLevel, VEMapStyle.Road);
				bingHouseView.HideDashboard();
				bingHouseView.SetMouseWheelZoomToCenter(false);

				if (hasMiniMap){
					bingHouseView.ShowMiniMap(0, 275);
				}

				if (!showScales){
					bingHouseView.HideScalebar();
				}

				if (isMoveable){
					// Remove key events except for arrows
					bingHouseView.AttachEvent("onkeydown", function(e){
						if (e.keyCode > 40 || e.keyCode < 37){
							return true;
						}
						return false;
					});
					bingHouseView.AttachEvent("onkeyup", function(e){
						if (e.keyCode > 40 || e.keyCode < 37){
							return true;
						}
						return false;
					});
					bingHouseView.AttachEvent("onkeypress", function(e){
						if (e.keyCode > 40 || e.keyCode < 37){
							return true;
						}
						return false;
					});
				} else {
					bingHouseView.AttachEvent("onkeydown", function(e){return true;});
					bingHouseView.AttachEvent("onkeyup", function(e){return true;});
					bingHouseView.AttachEvent("onkeypress", function(e){return true;});

					// Hack to get poi map toggle working in IE.
					bingHouseView.AttachEvent("onclick", function(e){$('#poiMap').toggle(); return true;});
					bingHouseView.AttachEvent("ondoubleclick", function(e){return true;});
					bingHouseView.AttachEvent("onmousemove", function(e){return true;});
					bingHouseView.AttachEvent("onmousedown", function(e){return true;});
					bingHouseView.AttachEvent("onmouseup", function(e){return true;});
					bingHouseView.AttachEvent("onmouseover", function(e){return true;});
					bingHouseView.AttachEvent("onmouseout", function(e){return true;});
					bingHouseView.AttachEvent("onmousewheel", function(e){return true;});
					var disableMapNode = document.createElement('div');
					$(disableMapNode).css('position', 'absolute').css('top', 0).css('bottom', 0).css('left', 0).css('right', 0).css('z-index', 1000);
					$(baseNode).append(disableMapNode);

				}

				bingHouseView.AttachEvent("onstartpan", function(){_moveStart()});
				bingHouseView.AttachEvent("onendpan", function(){_moveEnd()});
				bingHouseView.AttachEvent("onendzoom", function(){_zoomEnd()});
				bingHouseView.AttachEvent("onobliquechange", function(){_orientationChanged()});


				if (hasHouseView){
					// Since we don't know when the IsBirdseyeAvalable() is actually returning the correct result
					// we poll it every 500ms
					window.setInterval(function(){_houseViewClientHandler();}, 500);
				}

				// Fix bug with bing maps in firefox 3.5
				 if (navigator.userAgent.indexOf("Firefox/3.5") != -1){
					bingMapNode.addEventListener('DOMMouseScroll', function (e){
						e.stopPropagation();
						e.preventDefault();
						e.cancelBubble=false;
						return false;		
					}, false);
				 }
				$(bingMapNode).hide();
			}
			
			self.reset = function(){
				self.setCenter(startCenterLat, startCenterLng, startMapZoomLevel);
			}

			self.setMapView = function(){
				if (googleStreetView != null){
					googleStreetView.remove();
					googleStreetView = null;
				}
				if (provider === "mapquest"){
					$(bingMapNode).hide();
					$(mapquestNode).show();
					mapquestMap.setMapType('map');
				} else if (provider === "bing"){
					$(bingMapNode).show();
					bingHouseView.SetMapStyle(VEMapStyle.Road);
				}

				_doMapSync('map');
			}

			// TODO allow default view to be configured?
			self.setMapView();

			self.setSatView = function(){
				if (googleStreetView != null){
					googleStreetView.remove();
					googleStreetView = null;
				}
				if (provider === "mapquest"){
					$(bingMapNode).hide();
					$(mapquestNode).show();
					mapquestMap.setMapType('sat');
				} else if (provider === "bing"){
					$(bingMapNode).show();
					bingHouseView.SetMapStyle(VEMapStyle.Aerial);
				}

				_doMapSync('sat');
			}

			self.setHybridView = function(){
				if (googleStreetView != null){
					googleStreetView.remove();
					googleStreetView = null;
				}
				if (provider === "mapquest"){
					$(bingMapNode).hide();
					$(mapquestNode).show();
					mapquestMap.setMapType('hyb');
				} else if (provider === "bing"){
					$(bingMapNode).show();
					bingHouseView.SetMapStyle(VEMapStyle.Hybrid);
				}
				_doMapSync('hyb');
			}

			self.setStreetView = function(){
				if (hasStreetView && isStreetViewAvailable){
					$(bingMapNode).hide();
					$(mapquestNode).hide();
					if (googleStreetView == null){
						googleStreetView = new GStreetviewPanorama(baseNode);
						googleStreetView.setLocationAndPOV(new GLatLng(centerLat, centerLng));
					}
					googleStreetView.setLocationAndPOV(new GLatLng(centerLat, centerLng));
					_doMapSync('street');
				}
			}

			self.setHouseView = function(){
				if (hasHouseView && isHouseViewAvailable){
					$(mapquestNode).hide();
					if (googleStreetView != null){
						googleStreetView.remove();
						googleStreetView = null;
					}
					$(bingMapNode).show();
					if (provider === "bing"){
						bingHouseView.SetMapStyle(VEMapStyle.Birdseye);
					}

					_doMapSync('house');
				}
			}

			self.getCurrentView = function(){
				return currentView;
			}

			self.getMapOrientation = function(){
				return mapOrientation;
			}

			self.isHouseViewAvailable = function(){
				return isHouseViewAvailable;
			}

			self.isStreetViewAvailable = function(){
				return isStreetViewAvailable;
			}

			self.hasStreetView = function(){
				return hasStreetView;
			}

			self.hasHouseView = function(){
				return hasHouseView;
			}

			self.setCenter = function(lat, lng, zoom){
				if (provider === "mapquest"){
					if (currentView == 'house'){
						// TODO not implemented
					} else if (currentView != 'street'){
						mapquestMap.setCenter({
							lat: lat,
							lng: lng
						});
						mapquestMap.setZoomLevel(zoom);
					}
				} else if (provider === "bing"){
					bingHouseView.SetCenterAndZoom(new VELatLong(lat, lng), zoom);
				}
			}

			self.getCenter = function(){
				if (provider === "mapquest"){
					if (currentView == 'house'){
						var centerLatLng = bingHouseView.GetCenter();
						return {lat: centerLatLng.Latitude, lng: centerLatLng.Longitude};
					} else if (currentView != 'street'){
						return mapquestMap.getCenter();
					}
				} else if (provider === "bing"){
					var centerLatLng = bingHouseView.GetCenter();
					return {lat: centerLatLng.Latitude, lng: centerLatLng.Longitude};
				}
			}

			self.getBounds = function(){
				if (provider === "mapquest"){
					if (currentView == 'house'){
						var view = bingHouseView.GetMapView();
						return {ul: {lat: view.TopLeftLatLong.Latitude, lng: view.TopLeftLatLong.Longitude }, lr: {lat: view.BottomRightLatLong.Latitude, lng: view.BottomRightLatLong.Longitude}};
					} else if (currentView != 'street'){
						return mapquestMap.getBounds();
					}
				} else if (provider === "bing"){
					var view = bingHouseView.GetMapView();
					return {ul: {lat: view.TopLeftLatLong.Latitude, lng: view.TopLeftLatLong.Longitude }, lr: {lat: view.BottomRightLatLong.Latitude, lng: view.BottomRightLatLong.Longitude}};
				}
			}

			self.getMapquestMaxZoom = function(){
				return mapquestMaxZoom;
			}

			self.getMapquestMinZoom = function(){
				return mapquestMinZoom;
			}

			// Pan/Zoom/Rotate functions
			// We can't control street view, so we have to use the street view controls
			// Pan/Zoom controls are available on map/sat/hybrid/house view modes
			// Rotate is only available on house view mode

			self.panUp = function(){
				if (currentView == 'house'){
					bingHouseView.Pan(0, -bingVerticalPan);
				} else if (currentView != 'street'){
					mapquestMap.panNorth(mapquestPan);
				}
			}

			self.panDown = function(){
				if (currentView == 'house'){
					bingHouseView.Pan(0, bingVerticalPan);
				} else if (currentView != 'street'){
					mapquestMap.panSouth(mapquestPan);
				}
			}

			self.panRight = function(){
				if (currentView == 'house'){
					bingHouseView.Pan(bingHorizontalPan, 0);
				} else if (currentView != 'street'){
					mapquestMap.panEast(mapquestPan);
				}
			}

			self.panLeft = function(){
				if (currentView == 'house'){
					bingHouseView.Pan(-bingHorizontalPan, 0);
				} else if (currentView != 'street'){
					mapquestMap.panWest(mapquestPan);
				}
			}

			self.zoomIn = function(){
				if (currentView == 'house'){
					bingHouseView.ZoomIn();
				} else if (currentView != 'street'){
					if (provider === 'mapquest'){
						mapquestMap.setZoomLevel(mapquestMap.getZoomLevel()+1);
					} else if (provider === 'bing'){
						bingHouseView.ZoomIn();
					}
				}
			}

			self.zoomOut = function(){
				if (currentView == 'house'){
					bingHouseView.ZoomOut();
				} else if (currentView != 'street'){
					if (provider === 'mapquest'){
						mapquestMap.setZoomLevel(mapquestMap.getZoomLevel()-1);
					} else if (provider === 'bing'){
						bingHouseView.ZoomOut();
					}
				}
			}

			self.zoomTo = function(zoomLevel){
				if (currentView != 'house' && currentView != 'street'){
					if (provider === 'mapquest'){
						mapquestMap.setZoomLevel(zoomLevel);
					} else if (provider === 'bing'){
						bingHouseView.SetZoomLevel(zoomLevel);
					}
				}
			}

			self.getZoomLevel = function(){
				if (currentView != 'house' && currentView != 'street'){
					if (provider === 'mapquest'){
						return mapquestMap.getZoomLevel();
					} else if (provider === 'bing'){
						return bingHouseView.GetZoomLevel();
					}
				} else {
					return 1;
				}
			}

			self.rotateCW = function(){
				if (currentView == 'house'){
					var orientation = bingHouseView.GetBirdseyeScene().GetOrientation();
					if (orientation == 'North'){
						bingHouseView.SetBirdseyeOrientation(VEOrientation.East);
					} else if (orientation == 'South'){
						bingHouseView.SetBirdseyeOrientation(VEOrientation.West);
					} else if (orientation == 'West'){
						bingHouseView.SetBirdseyeOrientation(VEOrientation.North);
					} else if (orientation == 'East'){
						bingHouseView.SetBirdseyeOrientation(VEOrientation.South);
					}
				}
			}

			self.rotateCCW = function(){
				if (currentView == 'house'){
					var orientation = bingHouseView.GetBirdseyeScene().GetOrientation();
					if (orientation == 'North'){
						bingHouseView.SetBirdseyeOrientation(VEOrientation.West);
					} else if (orientation == 'South'){
						bingHouseView.SetBirdseyeOrientation(VEOrientation.East);
					} else if (orientation == 'West'){
						bingHouseView.SetBirdseyeOrientation(VEOrientation.South);
					} else if (orientation == 'East'){
						bingHouseView.SetBirdseyeOrientation(VEOrientation.North);
					}
				}
			}

			// Add poi methods allow us to add pois to mapquest or bing maps
			//
			// !!!!!!!!!!!! WARNING !!!!!!!!!!!!
			// We cannot put POI data obtained from one map provider onto another map provider's map
			// House data from search is fine as that's our own geocode info.

			// Add poi to both mapquest and bing
			self.addPoi = function(poi){
				self.addMapPoi(poi);
				self.addHouseViewPoi(poi);
			}

			// Remove poi from both mapquest and bing
			self.removePoi = function(poi){
				self.removeMapPoi(poi);
				self.removeHouseViewPoi(poi);
			}

			self.addMapPoi = function(poi){
				if (provider === 'mapquest'){
					mapquestMap.addShape(poi.getMapquestPoi());
				} else if (provider === 'bing'){
					self.addHouseViewPoi(poi);
				}
			}

			self.removeMapPoi = function(poi){
				if (provider === 'mapquest'){
					mapquestMap.removeShape(poi.getMapquestPoi());

					// This is a hack to work around a bug in mapquest where the info box doesn't show up 
					// if you readd a poi
					poi.mapquestPoi = null;
				} else if (provider === 'bing'){
					self.removeHouseViewPoi(poi);
				}
				
			}

			self.addHouseViewPoi = function(poi){
				if (hasHouseView || provider === 'bing'){
					// Bing throws an error if this poi has already been added
					// So we just catch it and ignore it
					try {
						bingHouseView.AddShape(poi.getBingPoi());
					} catch (e){}
					poi.getBingPoi().Show();
				}
			}

			// There's a bug in the bing birds eye where you can't remove a shape you've added to the map
			// So we'll just hide it and then do a show if it's re-added
			self.removeHouseViewPoi = function(poi){
				if (hasHouseView || provider === 'bing'){
					poi.getBingPoi().Hide();
				}
			}

			// Resize the map
			self.setSize = function(w, h){
				width = w;
				height = h;
				$(baseNode).css('width', width).css('height', height);
				$(bingMapNode).css('width', width).css('height', height);
				$(mapquestNode).css('width', width).css('height', height);
				if (hasStreetView && googleStreetView != null){
					googleStreetView.checkResize();
				}
				if (hasHouseView || provider == 'bing'){
					bingHouseView.Resize(width, height);
				}
				if (provider == 'mapquest'){
					mapquestMap.setSize(new MQA.Size(width, height));
				}
			}

			self.getSize = function(){
				return {width: width, height: height};
			}

			self.show = function(){
				$(baseNode).show();
			}

			self.hide = function(){
				$(baseNode).hide();
			}

			self.bingFind = function(what, callback){
				if (provider === 'bing'){
					bingHouseView.Find(what, null, VEFindType.Businesses, null, 0, 10, false, false, false, false, callback);
				}
			}

			self.canZoomIn = function(){
				if (currentView == 'house'){
					if (bingHouseView.GetZoomLevel() >= 2){
						return false;
					} else {
						return true;
					}
				} else if (currentView != 'street'){
					if (provider === 'mapquest'){
						if (mapquestMap.getZoomLevel() >= mapquestMaxZoom){
							return false;
						} else {
							return true;
						}
					} else if (provider === 'bing'){
						if (bingHouseView.GetZoomLevel() >= mapquestMaxZoom){
							return false;
						} else {
							return true;
						}
					}
				}
			}

			self.canZoomOut = function(){
				if (currentView == 'house'){
					if (bingHouseView.GetZoomLevel() <= 1){
						return false;
					} else {
						return true;
					}
				} else if (currentView != 'street'){
					if (provider === 'mapquest'){
						if (mapquestMap.getZoomLevel() <= mapquestMinZoom){
							return false;
						} else {
							return true;
						}
					} else if (provider === 'bing'){
						if (bingHouseView.GetZoomLevel() <= mapquestMinZoom){
							return false;
						} else {
							return true;
						}
					}
				}
			}

			self.zoomToRect = function(tlLat, tlLng, brLat, brLng){
				if (provider === 'mapquest'){
					mapquestMap.zoomToRect({
						ul: new MQA.LatLng(tlLat, tlLng),
						lr: new MQA.LatLng(brLat, brLng)
					}, false, 4, 16)
				} else if (provider === 'bing'){
					bingHouseView.SetMapView([new VELatLong(tlLat, tlLng), new VELatLong(brLat, brLng)]);
				}
			}

			function _doMapSync(view){
				currentView = view;
				$(self).trigger('currentView', [view]);		
				_orientationChanged();
			}

			function _houseViewClientHandler(){
				if (bingHouseView.IsBirdseyeAvailable() != isHouseViewAvailable){
					isHouseViewAvailable = bingHouseView.IsBirdseyeAvailable();
					$(self).trigger('isHouseViewAvailable', [bingHouseView.IsBirdseyeAvailable()]);
				}
			}

			function _streetViewClientHandler(latLng){
				if (latLng == null) {
					isStreetViewAvailable = false;
					$(self).trigger('isStreetViewAvailable', [false]);
				} else {
					isStreetViewAvailable = true;
					$(self).trigger('isStreetViewAvailable', [true]);
				}
			}

			function _zoomEnd(evt){
				$(self).trigger('zoomEnd');
			}

			function _moveEnd(evt){
				$(self).trigger('moveEnd');
			}

			function _moveStart(evt){
				$(self).trigger('moveStart');
			}

			function _orientationChanged(evt){
				if (currentView == 'house') {
					var orientation = bingHouseView.GetBirdseyeScene().GetOrientation();
					if (orientation == VEOrientation.North){ 
						mapOrientation = 'n';
					} else if (orientation == VEOrientation.South){ 
						mapOrientation = 's';
					} else if (orientation == VEOrientation.West){ 
						mapOrientation = 'w';
					} else if (orientation == VEOrientation.East){ 
						mapOrientation = 'e';
					}
				} else {
					mapOrientation = 'n';
				}

				$(self).trigger('mapOrientation', [mapOrientation]);
			}
			return self;
		},

		mapIcon: function (img, width, height){
			var self = {};
			var mapquestIcon = null;
			var bingIcon = null;

			self.getMapquestIcon = _createMapquestIcon;
			self.getBingIcon = _createBingIcon;

			function _createMapquestIcon(){
				mapquestIcon = new MQA.Icon(img, width, height);
				self.getMapquestIcon = _getMapquestIcon;
				return mapquestIcon;
			}

			function _getMapquestIcon(){
				return mapquestIcon;
			}

			function _createBingIcon(){
				bingIcon = "<img src='" + img + "'/>";
				self.getBingIcon = _getBingIcon;
				return bingIcon;
			}

			function _getBingIcon(){
				return bingIcon;
			}
			return self;
		},

		poi: function (lat, lng, icon, content){
			var self = {};
			var mapquestPoi = null;
			var bingPoi = null;

			// Public Methods
			self.getMapquestPoi = _createMapquestPoi;
			self.getBingPoi = _createBingPoi;

			// Private Methods
			function _createMapquestPoi(){
				mapquestPoi = new MQA.Poi({lat: lat, lng: lng});
				if (icon !== undefined && icon != null){
					mapquestPoi.setIcon(icon.getMapquestIcon());
				}
				if (content !== undefined && content != null){
					mapquestPoi.setRolloverContent(content);
				}

				self.getMapquestPoi = _getMapquestPoi;

				return mapquestPoi;
			}

			function _getMapquestPoi(){
				return mapquestPoi;
			}

			function _createBingPoi(){
				bingPoi = new VEShape(VEShapeType.Pushpin, new VELatLong(lat, lng));
				if (icon !== undefined && icon != null){
					bingPoi.SetCustomIcon(icon.getBingIcon());
				}
				if (content !== undefined && content != null){
					bingPoi.SetDescription(content);
				}

				self.getBingPoi = _getBingPoi;

				return bingPoi;
			}

			function _getBingPoi(){
				return bingPoi;
			}
			return self;
		},

		controlContainer: function (baseNode, map){
			var self = {};
			var controlId = WNT.CONTROL_ID++;
			var baseAnimateTime = 800;
			var expandAnimateTime = 400;

			// TODO: add expand node
			var expandNode = document.createElement('div');
			$(expandNode).addClass('wntControlExpand').click(function () {$(map).trigger('showControls');});
			$(baseNode).parent().append(expandNode);
			
			$(map).bind('hideControls', function(){
				$(baseNode).animate({left: -400}, baseAnimateTime, function() {$(expandNode).animate({left: 0}, expandAnimateTime);});
			});

			$(map).bind('showControls', function(){
				$(expandNode).animate({left: -71}, expandAnimateTime, function() {$(baseNode).animate({left: 0}, baseAnimateTime);});
			});
			
		},

		navMapControl: function (baseNode, map){
			var self = {};
			var controlId = WNT.CONTROL_ID++;

			var closeNode = document.createElement('div');
			$(closeNode).addClass('wntStreetCloseButton').click(function () {map.setMapView();}).hide();
			$(baseNode.parentNode).append(closeNode);

			var navBackgroundNode = document.createElement('span');
			$(navBackgroundNode).attr('id', 'wntNavBackground' + controlId).addClass('wntNavBackground');
			$(baseNode).append(navBackgroundNode);

			var navStartNode = document.createElement('span');

			$(navStartNode).attr('id', 'wntNavStart' + controlId).addClass('wntNavStart');
			$(baseNode).append(navStartNode);

			var mapViewNode = document.createElement('span');
			$(mapViewNode).attr('id', 'wntNavMapView' + controlId).addClass('wntNavMenuItem').html('Map').click(function () {map.setMapView();});
			$(baseNode).append(mapViewNode);

			var hybridViewNode = document.createElement('span');
			$(hybridViewNode).attr('id', 'wntNavHybridView' + controlId).addClass('wntNavMenuItem').html('Hybrid').click(function () {map.setHybridView();});
			$(baseNode).append(hybridViewNode);

			var satViewNode = document.createElement('span');
			$(satViewNode).attr('id', 'wntNavSatView' + controlId).addClass('wntNavMenuItem').html('Aerial').click(function () {map.setSatView();});
			$(baseNode).append(satViewNode);

			if (map.hasHouseView()){
				var houseViewNode = document.createElement('span');
				$(houseViewNode).attr('id', 'wntNavHouseView' + controlId).addClass('wntNavMenuItem').html('House View').click(function () {map.setHouseView();});
				$(baseNode).append(houseViewNode);
			}

			if (map.hasStreetView()){
				var streetViewNode = document.createElement('span');
				$(streetViewNode).attr('id', 'wntNavStreetView' + controlId).addClass('wntNavMenuItem').html('Street View').click(function () {map.setStreetView();});
				$(baseNode).append(streetViewNode);
			}

			var navEndNode = document.createElement('span');
			$(navEndNode).attr('id', 'wntNavEnd' + controlId).addClass('wntNavEnd').click(function () {$(map).trigger('hideControls');});
			$(baseNode).append(navEndNode);

			// Manually trigger events to set initial values
			_currentView(map.getCurrentView());
			_isStreetViewAvailable(map.isStreetViewAvailable());
			_isHouseViewAvailable(map.isHouseViewAvailable());

			$(map).bind('isStreetViewAvailable', function(e, available){_isStreetViewAvailable(available);});		
			$(map).bind('isHouseViewAvailable', function(e, available){_isHouseViewAvailable(available);});		
			$(map).bind('currentView', function(e, view){_currentView(view);});		

			function _isStreetViewAvailable(available){
				if (available) {
					$(streetViewNode).removeClass('notAvailable');
				} else {
					$(streetViewNode).addClass('notAvailable');
				}
			}

			function _isHouseViewAvailable(available){
				if (available) {
					$(houseViewNode).removeClass('notAvailable');
				} else {
					$(houseViewNode).addClass('notAvailable');
				}

			}

			function _currentView(view){
				if (view == 'house'){
					$(houseViewNode).addClass('selected');
				} else {
					$(houseViewNode).removeClass('selected');
				}
				if (view == 'street'){
					$(closeNode).show();
					$(baseNode).hide();
				} else {
					$(closeNode).hide();
					$(baseNode).show();
				}
				if (view == 'map'){
					$(mapViewNode).addClass('selected');
				} else {
					$(mapViewNode).removeClass('selected');
				}
				if (view == 'sat'){
					$(satViewNode).addClass('selected');
				} else {
					$(satViewNode).removeClass('selected');
				}
				if (view == 'hyb'){
					$(hybridViewNode).addClass('selected');
				} else {
					$(hybridViewNode).removeClass('selected');
				}
			}
			return self;
		},

		panZoomMapControl: function (baseNode, map, params){
			var self = {};

			var expandedZoom = (params['expandedZoom'] === undefined) ? false : params['expandedZoom'];

			var controlId = WNT.CONTROL_ID++;

			var panBackgroundNode = document.createElement('div');
			$(panBackgroundNode).attr('id', 'wntPanBackground' + controlId).addClass('wntPanBackground').addClass('wntNorth');
			$(baseNode).append(panBackgroundNode);

			var panUpNode = document.createElement('div');
			$(panUpNode).attr('id', 'wntPanUp' + controlId).addClass('wntPanUp').click(function() {map.panUp();});
			$(panBackgroundNode).append(panUpNode);

			var panDownNode = document.createElement('div');
			$(panDownNode).attr('id', 'wntPanDown' + controlId).addClass('wntPanDown').click(function() {map.panDown();});
			$(panBackgroundNode).append(panDownNode);

			var panLeftNode = document.createElement('div');
			$(panLeftNode).attr('id', 'wntPanLeft' + controlId).addClass('wntPanLeft').click(function() {map.panLeft();});
			$(panBackgroundNode).append(panLeftNode);

			var panRightNode = document.createElement('div');
			$(panRightNode).attr('id', 'wntPanRight' + controlId).addClass('wntPanRight').click(function() {map.panRight();});
			$(panBackgroundNode).append(panRightNode);


			// Create Zoom & Rotate container
			var zrContainerNode = document.createElement('div');
			$(zrContainerNode).attr('id', 'wntZRContainer' + controlId).addClass('wntZRContainer');
			$(baseNode).append(zrContainerNode);

			var zrBackgroundNode = document.createElement('div');
			$(zrBackgroundNode).attr('id', 'wntZRBackground' + controlId).addClass('wntZRBackground');
			$(zrContainerNode).append(zrBackgroundNode);

			var zrTopNode = document.createElement('div');
			$(zrTopNode).attr('id', 'wntZRTop' + controlId).addClass('wntZRTop');
			$(zrContainerNode).append(zrTopNode);
			
			var zoomContainerNode = document.createElement('div');
			$(zoomContainerNode).attr('id', 'wntZoomContainer' + controlId).addClass('wntZoomContainer');
			$(zrContainerNode).append(zoomContainerNode);

			var rotateContainerNode = document.createElement('div');
			$(rotateContainerNode).attr('id', 'wntRotateContainer' + controlId).addClass('wntRotateContainer');
			$(zrContainerNode).append(rotateContainerNode);

			var zoomRotateBottom = document.createElement('div');
			$(zoomRotateBottom).attr('id', 'wntZoomRotateBottom' + controlId).addClass('wntZoomRotateBottom');
			$(zrContainerNode).append(zoomRotateBottom);
			
			// Create Zoom controls and attach click events
			var zoomInNode = document.createElement('div');
			$(zoomInNode).attr('id', 'wntZoomIn' + controlId).addClass('wntZoomIn').click(function() {map.zoomIn();});
			$(zoomContainerNode).append(zoomInNode);

			var zoomBarNode = document.createElement('div');
			$(zoomBarNode).attr('id', 'wntZoomBar' + controlId).addClass('wntZoomBar');
			if (expandedZoom){
				$(zoomBarNode).show();
				for (var x = map.getMapquestMaxZoom(); x >= map.getMapquestMinZoom(); x--){
					var zoomButtonNode = document.createElement('div');
					$(zoomButtonNode).addClass('wntZoomButton').addClass('wntZoomButton_' + x).click(_zoomButtonClick(x));
					$(zoomBarNode).append(zoomButtonNode);
				}
			} else {
				$(zoomBarNode).hide();
			}
			$(zoomContainerNode).append(zoomBarNode);


			var zoomOutNode = document.createElement('div');
			$(zoomOutNode).attr('id', 'wntZoomOut' + controlId).addClass('wntZoomOut').click(function() {map.zoomOut();});
			$(zoomContainerNode).append(zoomOutNode);


			// TODO add if to display correct controls

			var rotateCWNode = document.createElement('div');
			$(rotateCWNode).attr('id', 'wntRotateCW' + controlId).addClass('wntRotateCW').click(function() {map.rotateCW();});
			$(rotateContainerNode).append(rotateCWNode);

			var rotateCCWNode = document.createElement('div');
			$(rotateCCWNode).attr('id', 'wntRotateCCW' + controlId).addClass('wntRotateCCW').click(function() {map.rotateCCW();});
			$(rotateContainerNode).append(rotateCCWNode);

			// Manually call events to init controls
			_currentView(map.getCurrentView());
			_mapOrientation(map.getMapOrientation());

			$(map).bind('currentView', function(e, view){_currentView(view);});		
			$(map).bind('mapOrientation', function(e, orientation){_mapOrientation(orientation);});		
			$(map).bind('zoomEnd', function(e){_mapZoomEnd();});		

			function _zoomButtonClick(zoomLevel){
				return function() {
					map.zoomTo(zoomLevel);
				};
			}

			function _currentView(view){
				
				if (view == "street"){
					$(baseNode).hide();
				} else if (view == "house"){
					$(baseNode).show();
					$(zoomContainerNode).show();
					$(zoomBarNode).hide();
					$(rotateContainerNode).show();
				} else {
					$(zoomContainerNode).show();
					if (expandedZoom){
						$(zoomBarNode).show();
					} else {
						$(zoomBarNode).hide();
					}

					$(baseNode).show();
					$(rotateContainerNode).hide();
				}

				_mapZoomEnd();
			}

			function _mapOrientation(orientation){
				if (orientation == "n"){
					$(panBackgroundNode).addClass('wntNorth').removeClass('wntSouth').removeClass('wntWest').removeClass('wntEast');
				} else if (orientation == "s"){
					$(panBackgroundNode).removeClass('wntNorth').addClass('wntSouth').removeClass('wntWest').removeClass('wntEast');
				} else if (orientation == "w"){
					$(panBackgroundNode).removeClass('wntNorth').removeClass('wntSouth').addClass('wntWest').removeClass('wntEast');
				} else if (orientation == "e"){
					$(panBackgroundNode).removeClass('wntNorth').removeClass('wntSouth').removeClass('wntWest').addClass('wntEast');
				}
			}

			function _mapZoomEnd(){
				if (map.canZoomIn()){
					$(zoomInNode).removeClass('disabled');
				} else {
					$(zoomInNode).addClass('disabled');
				}
				if (map.canZoomOut()){
					$(zoomOutNode).removeClass('disabled');
				} else {
					$(zoomOutNode).addClass('disabled');
				}

				for (var x = map.getMapquestMaxZoom(); x >= map.getMapquestMinZoom(); x--){
					$(zoomBarNode).removeClass('wntZoomLevel_' + x);
				}
				$(zoomBarNode).addClass('wntZoomLevel_' + map.getZoomLevel());
			}
			return self;
		},

		// Used for Bing
		bingFind: function (map, params){

			return WNT.find(map, findFunc);

			function findFunc(value, callback){
				map.bingFind(value, _bingResults);
				
				function _bingResults(shapeLayer, findResults){
					var results = [];
					$(findResults).each(function(){
						results.push({
							name: this.Name,
							lat: this.LatLong.Latitude,
							lng: this.LatLong.Longitude
						});
					});

					callback(results);
				}
			}

		},

		mapquestFind: function (map, searchUrl, params){

			return WNT.find(map, findFunc);

			function findFunc (value, callback){
				if (value === ''){
					_mapquestResults("", callback);
				} else {
					var xml = '<?xml version="1.0" encoding="ISO-8859-1"?><Search Version="0"><RadiusSearchCriteria><MaxMatches>10</MaxMatches><Radius>0.6595012271388594</Radius><CenterLatLng><Lat>' + map.getCenter().lat + '</Lat><Lng>' + map.getCenter().lng + '</Lng></CenterLatLng></RadiusSearchCriteria>\n<CoverageName></CoverageName><DBLayerQueryCollection Count="1"><DBLayerQuery><LayerName>MQA.NTPois</LayerName><ExtraCriteria>facility = ' + value + '</ExtraCriteria></DBLayerQuery></DBLayerQueryCollection><FeatureCollection Version="0" Count="0"></FeatureCollection><DTCollection Count="0"></DTCollection><Authentication Version="2"><TransactionInfo></TransactionInfo></Authentication></Search>'

					$.post(searchUrl, xml, function(response) {_mapquestResults(response, callback);}, "xml");
				}
			}

			function _mapquestResults(xml, callback){
				var results = [];
				$(xml).find('SearchResponse').find('FeatureCollection').find('PointFeature').each(function() {
						results.push({
							name: $(this).find('Name').text(),
							lat: $(this).find('CenterLatLng').find('Lat').text(),
							lng: $(this).find('CenterLatLng').find('Lng').text()
						});
				});
				callback(results);
			}
		},


		find: function (map, findFunc, params){
			var self = {};

			var findQueue = [];
			var searching = false;
			var findCache = {};

			self.add = function(value, icon){
				if (searching){
					findQueue.push({action: 'add', value: value, icon: icon});
				} else {
					_doAdd(value, icon);
				}
			};

			self.remove = function(value){
				if (searching){
					findQueue.push({action: 'remove', value: value});
				} else {
					_doRemove(value);
				}
			}

			function _doAdd(value, icon){
				searching = true;


				findFunc(value, function(findResults){
					var mapIcon = WNT.mapIcon(icon, 22, 24);
					findCache[value] = [];
					$(findResults).each(function(){
						var poi = WNT.poi(this.lat, this.lng, mapIcon, this.name);
						map.addPoi(poi);
						findCache[value].push(poi);
					});
					_queueNext();
				});
			}

			function _doRemove(value){
				$(findCache[value]).each(function(){
					map.removePoi(this);
				});
				_queueNext();
			}

			function _queueNext(){
				if (findQueue.length > 0){
					var request = findQueue.shift();
					if (request.action === 'add'){
						_doAdd(request.value, request.icon);
					} else {
						_doRemove(request.value);
					}
				} else {
					searching = false;
				}
			}

			return self;
		},

		quickSearch: function (baseNode){
			
			var addressField = $("input[name=address]", baseNode);
			var propertyIdField = $("input[name=property_id]", baseNode);
			var cityField = $("input[name=city]", baseNode);
			var zipCodeField = $("input[name=zip_code]", baseNode);
			var searchSelect = $("select", baseNode);
			var textField = $("input[type=text]", baseNode);
			var goButton = $(".wntFormMainButton", baseNode);

			textField.css('color', '#888888');
			textField.focus(function(){
				if (textField.val() == "Quick Search"){
					textField.val("").css('color', '#000000');
				}
			}).blur(function(){
				if (textField.val() == ""){
					textField.val("Quick Search").css('color', '#888888');
				}
			});
			goButton.click(function(){
				$(baseNode).submit();
			});
			$(baseNode).submit(function(){
				if (textField.val() != "" && textField.val() != "Quick Search"){
					if(searchSelect.val() == "Listing Number"){
						addressField.val("");	
						propertyIdField.val(textField.val());	
						cityField.val("");	
						zipCodeField.val("");	
					} else if(searchSelect.val() == "City"){
						addressField.val("");	
						propertyIdField.val("");	
						cityField.val(textField.val());	
						zipCodeField.val("");	
					} else if(searchSelect.val() == "Zip Code"){
						addressField.val("");	
						propertyIdField.val("");	
						cityField.val("");	
						zipCodeField.val(textField.val());	
					} else {
						addressField.val(textField.val());	
						propertyIdField.val("");	
						cityField.val("");	
						zipCodeField.val("");	
					}
					baseNode.submit();
				}
			});
			
		},

		liveUpdate: function (baseNode, updateUrl, mapMoveUrl, params){
			var self = {};

			// This is used to speed up how quickly we get the results after we do a sendMapMove
			// But stopping the request the map moves will trigger, we can get rid of the delay those fields have
			var suspendSendRequest = false;

			var urlParams = (params['urlParams'] === undefined) ? "" : params['urlParams'];
			var hasMap = (params['hasMap'] === undefined) ? true : params['hasMap'];

			var updateDelay = 0;
			var requestCounter = 0;
			// Create a fake request object that we can abort the first time
			var lastRequest = {abort: function(){}};

			// NOTE: Due to a bug in the selector, you need to have the "=" at the end for it to match
			$('[data-wnt-liveupdate=]', baseNode).change(function(){
				self.sendRequest($(this).attr('data-wnt-liveupdate-delay') || updateDelay);
			});
			$('[data-wnt-mapmove=]', baseNode).change(function(){
				self.sendMapMove();
			});

			self.sendMapMove = function(){
				if (hasMap){
					var requestNumber = ++requestCounter;
					lastRequest.abort();
					$(self).trigger('sendingRequest');
					var formData = $(baseNode).serialize() + urlParams;
					lastRequest = $.ajax({
						type: "POST",
						url: mapMoveUrl,
						data: formData,
						success: function(msg){
							if (requestNumber == requestCounter){
								suspendSendRequest = true;
								$(self).trigger('mapMoveReceived', [msg]);
								suspendSendRequest = false;
								self.sendRequest(0);
							}
						},
						failure: function(err) {
							if (requestNumber == requestCounter){
								$(self).trigger('errorReceived', [err]);
							}
						}
					});
				} else {
					self.sendRequest(0);
				}
			};

			self.cancelRequest = function(){
				requestCounter++;
			};

			self.sendRequest = function(delay){
				if (suspendSendRequest){
					return;
				}
				var requestNumber = ++requestCounter;

				lastRequest.abort();

				window.setTimeout(function(){
					if (requestNumber == requestCounter){
						$(self).trigger('sendingRequest');
						var formData = $(baseNode).serialize() + urlParams;

						lastRequest.abort();
						lastRequest = $.ajax({
							type: "POST",
							url: updateUrl,
							data: formData,
							success: function(msg){
								if (requestNumber == requestCounter){
									$(self).trigger('responceReceived', [msg]);
								}
							},
							failure: function(err) {
								if (requestNumber == requestCounter){
									$(self).trigger('errorReceived', [err]);
								}
							}
						});
					}
				}, delay);
			}

			self.submit = function(){
				// TODO: BUG: the baseNode form dom node doesn't have the submit function due to a jQuery bug
				// So I'm hard coding the only use of the liveupdate for now.
				// This needs to be fixed once jQuery is working.
				var f = document.forms.searchForm;
				f.submit();
			}

			return self;
		},

		houseOverClick: function (propertyId){
			$(window).trigger('houseOverClick', [propertyId]);
	  },
		
		togglesiteowner: function (thevalue){
			var f = document.email_form;
			f.siteowner.value = thevalue;
			var o=document.getElementById('siteownerreq');
			if (o)
			{
				if (thevalue == 'Y')
					o.style.display = "none";
				else
					o.style.display = "block";
			}
		},
		
		toggleSection: function (link, key) {
			$("#link_"+key).toggleClass("wntCollapsed").toggleClass("wntExpanded");
			var content = $("#content_"+key);
			if (content.css('display') === "none"){
				content.slideDown("medium");
			} else {
				content.slideUp("medium");
			}
		},
		
		showPopup: function(popupId) {
			$('[data-wnt-popup=' + popupId + ']').show();
			$('[data-wnt-popup-cover=' + popupId + ']').show();
		},

		hidePopup: function(popupId) {
			$('[data-wnt-popup=' + popupId + ']').hide();
			$('[data-wnt-popup-cover=' + popupId + ']').hide();
	  },
		
		openVowTerms: function(scriptName) {
			var n=open(scriptName + '?action=vowterms','HTML','width=500,height=400,status=no,menubar=no,scrollbars=yes,resizable=yes');
			var viewedTerms = true;
		},
		
		togglePoiMap: function(){
			var poiMap = $('#poiMap');
			var listingSummary = $('.wntListingHeaderWrapper');
			poiMap.slideToggle('slow', function(){
				if (poiMap.css('display') != "none"){
					var top = listingSummary.offset().top;
					$('html,body').animate({scrollTop: top}, 'slow');
				}
			});
	  },

		userSignup: function() {
			var f=document.forms.frm_bridge_signup;
			f.submit();
		},

		toggleAgencyAgreement: function(flag){
			var agency = $(".wntAgentAgreement");
			if (flag){
				agency.addClass("wntExpanded");
				agency.removeClass("wntCollapsed");
			} else {
				agency.removeClass("wntExpanded");
				agency.addClass("wntCollapsed");
			}	
		},

		toggleContainer: function(baseNode){
			$('[data-wnt-toggle-action=]', baseNode).click(function(){
				$(baseNode).toggleClass("wntExpanded wntCollapsed");
			});
		},

		hoverToggleContainer: function(baseNode){
			$(baseNode).hover(function(){
				$(baseNode).css('zIndex', 100000).toggleClass("wntExpanded wntCollapsed");
				// IE7 Hack
				$(baseNode).parent().css('zIndex', 200000);
				$(baseNode).parent().parent().css('zIndex', 300000);
			},
			function() {
				$(baseNode).css('zIndex', 'auto').toggleClass("wntExpanded wntCollapsed");
				// IE7 Hack
				$(baseNode).parent().css('zIndex', 'auto');
				$(baseNode).parent().parent().css('zIndex', 'auto');
			});
		},

		mortgageCalculator: function(baseNode){
			var listPriceNode = $('input[name=mc_lp]', baseNode);
			var downPaymentNode = $('input[name=mc_dp]', baseNode);
			var loanTermNode = $('input[name=mc_lt]', baseNode);
			var interestRateNode = $('input[name=mc_ir]', baseNode);
			var annualPropertyTaxNode = $('input[name=mc_pt]', baseNode);
			var annualPropertyInsuranceNode = $('input[name=mc_pi]', baseNode);
			var calculateButton = $('input[name=mc_cal]', baseNode);
			var monthlyPrincipalInterestNode = $('input[name=mc_mpi]', baseNode);
			var monthlyTaxNode = $('input[name=mc_mt]', baseNode);
			var monthlyInsuranceNode = $('input[name=mc_mi]', baseNode);
			var estimatedMonthlyPaymentNode = $('input[name=mc_emp]', baseNode);
			var estimatedMortgageInsuranceNode = $('input[name=mc_emi]', baseNode);
			var estimatedTotalPaymentNode = $('input[name=mc_etp]', baseNode);

			calculateButton.click(function(){
				var listPrice = parseFloatNaN(listPriceNode.val());
				var downPayment = parseFloatNaN($('input[name=mc_dp]:checked').val());
				var loanTerm = parseFloatNaN(loanTermNode.val())*12;
				var monthlyInterestRate = parseFloatNaN(interestRateNode.val()) / 1200;
				var monthlyTax = parseFloatNaN(annualPropertyTaxNode.val()) / 12;
				var monthlyInsurance = parseFloatNaN(annualPropertyInsuranceNode.val()) / 12;

				var actualLoanAmount = listPrice - listPrice*downPayment;
				var monthlyPrincipalInterest = (actualLoanAmount * monthlyInterestRate * Math.pow(1+monthlyInterestRate, loanTerm)) / (Math.pow(1+monthlyInterestRate, loanTerm)-1);

				var monthlyPayment = monthlyPrincipalInterest + monthlyTax + monthlyInsurance;

				var mortgageInsurance = 0;
				if (downPayment === 0){
					mortgageInsurance = 0.0114*listPrice/12;
				} else if (downPayment === 0.03){
					mortgageInsurance = 0.0092*listPrice/12;
				} else if (downPayment === 0.05){
					mortgageInsurance = 0.0078*listPrice/12;
				} else if (downPayment === 0.10){
					mortgageInsurance = 0.0052*listPrice/12;
				}

				var totalMonthlyPayment = monthlyPayment + mortgageInsurance;

				monthlyPrincipalInterestNode.val(monthlyPrincipalInterest.toFixed(2));
				monthlyTaxNode.val(monthlyTax.toFixed(2));
				monthlyInsuranceNode.val(monthlyInsurance.toFixed(2));
				estimatedMonthlyPaymentNode.val(monthlyPayment.toFixed(2));
				estimatedMortgageInsuranceNode.val(mortgageInsurance.toFixed(2));
				estimatedTotalPaymentNode.val(totalMonthlyPayment.toFixed(2));
			});

			function parseFloatNaN(value){
				value = parseFloat(value);
				if (isNaN(value)){
					return 0;
				} else {
					return value;
				}
			}
		},

		fixVOWTowerAd: function(){
			var towerContent = $('div.wntVOWTowerBody > .wntFormatedDivContent');
			if (towerContent.size() > 0){
				var propertyDetails = $('div.wntListingHeader > .wntFormatedDivContent');
				if (towerContent.height() > propertyDetails.height()){
					propertyDetails.height(towerContent.height());
				} else {
					towerContent.height(propertyDetails.height());
				}
			}
		},

		fixSearchStyleHeight: function(){
			var style = $('#style');										 
			var amenities = $('.wntPropertyFeaturesAmenitiesField');
			if (style.size() > 0 && amenities.size() > 0){
				style.height(amenities.height());
			}
		},

		fixDetailsPhotoHeight: function(){
      if(!$('.wntPrinterFriendly').length) {
			  var listingTools = $('.wntListingTools');
			  var mainPhoto = $('.wntSlideshowMainPhoto');
			  var mainPhotoFD = $('.wntSlideshowMainPhoto > .wntFormatedDivContent');
			  if (listingTools.size() > 0 && mainPhoto.size() > 0 && mainPhotoFD.size() > 0){
				  var heightDiff = listingTools.outerHeight() - mainPhoto.outerHeight();
				  if (heightDiff > 0){
					  mainPhotoFD.height(mainPhotoFD.height() + heightDiff);
				  }
			  }
      }
		},

		fixDetailsNoPhoto: function(){
			var image = $('.wntSlideShowImage');
			if (image.size() > 0 && image.attr('src').indexOf('photo_not_available.jpg') >= 0){
				var wrapper = image.parent();
				var topMargin = Math.floor((wrapper.parent().height() - wrapper.height()) / 2);
				wrapper.css('marginTop', topMargin);
			}
		},

		fixBannersIE8: function() {
			var image = $('.wntSlideShowImage');
			if (image.size() > 0){
				var wrapper = image.parent();
				wrapper.css('display', 'block');

				var banners = wrapper.children('span');
				banners.hide();
			}
		},

		// Email Search to Friend
		es2fOwnerToggle: function(){
			if($('input[name=send_to_owner]:checked').val() === 'Y'){
				$("#wntSiteownerreq").hide();
				$("#wntSiteownerreq2").hide();
				$("input[name=friend_name]").attr('data-wnt-validation', 'none');
				$("input[name=friend_email]").attr('data-wnt-validation', 'none');
			} else {
				$("#wntSiteownerreq").show();
				$("#wntSiteownerreq2").show();
				$("input[name=friend_name").attr('data-wnt-validation', 'basic');
				$("input[name=friend_email]").attr('data-wnt-validation', 'email');
			}
		}
	};

	// Form Validation
	WNT.validation = function(formNode){
		var isValid = true
		var errorMessages = [];
		$('[data-wnt-validation]', formNode).each(function(){
			try {
				var retValue = WNT.validation.validators[$(this).attr('data-wnt-validation')](this, formNode);
				if (!retValue.isValid){
					errorMessages.push(retValue.errorMessage);
					isValid=false;
				}
			} catch (e){
				_('Validator not found for: ' + $(this).attr('data-wnt-validation'));
			}
		});
		if (isValid){
			return true;
		} else {
			alert(errorMessages.join('\n'));
			return false;
		}
	};
	// message: '%f' will be replaced with the field's label or tag
	WNT.validation.getErrorMessage = function(message, fieldNode){
		if ($(fieldNode).attr('data-wnt-validation-errMsg')){
			return $(fieldNode).attr('data-wnt-validation-errMsg');
		}else if ($(fieldNode).attr('data-wnt-validation-label')){
			return message.replace('%f',  $(fieldNode).attr('data-wnt-validation-label'));
		} else {
			return message.replace('%f',  $(fieldNode).attr('name'));
		}

	};
	WNT.validation.validators = {
		///////////////////////////////////
		// Put new validators here
		///////////////////////////////////
		none: function(fieldNode, formNode){
			return {isValid: true, errorMessage: ""};
		},
		basic: function(fieldNode, formNode){
			if ($(fieldNode).val() == ""){
				return {isValid: false, errorMessage: WNT.validation.getErrorMessage("Please complete the %f field.", fieldNode)};
			}
			return {isValid: true, errorMessage: ""};
		},
		email: function(fieldNode, formNode){
			if (!$(fieldNode).val().match(/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)){
				return {isValid: false, errorMessage: WNT.validation.getErrorMessage("Please complete the %f field. A valid email address is required.", fieldNode)};
			}
			return {isValid: true, errorMessage: ""};
		},
		fax: function(fieldNode, formNode){
			if ($(fieldNode).val().replace(/\D/g, "").length < 10){
				return {isValid: false, errorMessage: WNT.validation.getErrorMessage("Please complete the %f field. A 10-digit fax number is required.", fieldNode)};
			}
			return {isValid: true, errorMessage: ""};
		},
		phone: function(fieldNode, formNode){
			if ($(fieldNode).val().replace(/\D/g, "").length < 10){
				return {isValid: false, errorMessage: WNT.validation.getErrorMessage("Please complete the %f field. A 10-digit phone number is required.", fieldNode)};
			}
			return {isValid: true, errorMessage: ""};
		},
		confirm_email: function(fieldNode, formNode){
			if($(fieldNode).val() == $(formNode.email_address).val() && $(fieldNode).val() != ""){
				return {isValid: true, errorMessage: ""};
			}
			return {isValid: false, errorMessage: "Please complete the Confirm Email Address field. The email must match the email entered in the Your Email Address field."};
		},
		password: function(fieldNode, formNode){
			if ($(fieldNode).val() == ""){
				return {isValid: false, errorMessage: WNT.validation.getErrorMessage("Please complete the %f field. The password must match the password entered in the Confirm Password field.", fieldNode)};
			}
			return {isValid: true, errorMessage: ""};
		},
		password_again: function(fieldNode, formNode){
			if(($(fieldNode).val() == $(formNode.password).val() && $(fieldNode).val() != "") || $(formNode.password).val() == ""){
				return {isValid: true, errorMessage: ""};
			}
			return {isValid: false, errorMessage: "Please complete the Confirm Password field. The password must match the password entered in the Choose Password field."};
		},
		agent_name: function(fieldNode, formNode){
			if ($('input[name=agentYN]:checked',formNode).val() == "Yes"){
				return WNT.validation.validators.basic(fieldNode, formNode);
			}
			return {isValid: true, errorMessage: ""};
		},
		vowToU: function(fieldNode, formNode){
			if ($(fieldNode).attr('checked')){
				return {isValid: true, errorMessage: ""};
			} else {
				return {isValid: false, errorMessage: "Please read and agree to the Terms of Use."};
			}
		}
	}
	
	// INIT
	// Use the window load event when you need to depend on the image size
	$(window).load(function () {
		WNT.fixVOWTowerAd();

		WNT.fixSearchStyleHeight();

		WNT.fixDetailsPhotoHeight();

		WNT.fixDetailsNoPhoto();
		//
		// This gets IE8 most of the time.
		if ($.browser.msie && navigator.userAgent.indexOf('Trident')!==-1){
			WNT.fixBannersIE8();
		}
	});

	// Use the document ready event when working with maps, or you don't need an image's size
	$(document).ready(function() {


		$('div[data-wnt-popup] .wntPopupContent').click(function(event){
			event.stopPropagation();
		});

		$('div[data-wnt-popup]').each(function(){
			var popupId = $(this).attr('data-wnt-popup');
			$(this).click(function(event){
				WNT.hidePopup(popupId);
			});
		});

		$('div[data-wnt-popup-close]').each(function(){
			var popupId = $(this).attr('data-wnt-popup-close');
			$(this).click(function(event){
				WNT.hidePopup(popupId);
			});
		});

		$('div[data-wnt-mortCalc=]').each(function(){
			WNT.mortgageCalculator(this);
		});

		$('span[data-wnt-submitFormLink=]').each(function(){
			var parentForm = $(this).parents('form:eq(0)');
			$(this).click(function(){
				$(parentForm).submit();
			});
		});

		$('span[data-wnt-resetFormLink=]').each(function(){
			var parentForm = $(this).parents('form:eq(0)');
			$(this).click(function(){
				parentForm[0].reset();
			});
		});

		$('span[data-wnt-addremovelist=container]').each(function () {
			$(this).data("addremovelist", WNT.addRemoveList(this));	
		});

		$('[data-wnt-countycity-bind]').each(function () {
			var cities = $($(this).attr('data-wnt-countycity-bind'))[0];
			var state = $($(this).attr('data-wnt-countycity-bind-state'))[0];
			var county = $($(this).attr('data-wnt-countycity-bind-county'))[0];
			var cityAddRemoveList = $('span[data-wnt-addremovelist=container]', this)[0];
			var cityAddRemoveObject = $(cityAddRemoveList).data('addremovelist');
			if (state != undefined){
				WNT.bind(county, [
					 {key: 'state', sourceNode: state}
				], 0);
				WNT.bind(cities, [
					 {key: 'state', sourceNode: state},
					 {key: 'county', sourceNode: county}
				], -1);

				$(state).bind('change', function(){

					cityAddRemoveObject.removeAll();
				});
			} else {
				WNT.bind(cities, [
					 {key: 'county', sourceNode: county}
				], -1);
			}
		});

		$('[data-wnt-results-countycity-bind]').each(function () {
			var cities = $($(this).attr('data-wnt-results-countycity-bind'))[0];
			var state = $($(this).attr('data-wnt-countycity-bind-state'))[0];
			var county = $($(this).attr('data-wnt-countycity-bind-county'))[0];
			WNT.bind(county, [
				 {key: 'state', sourceNode: state}
			], 0);
			WNT.bind(cities, [
				 {key: 'state', sourceNode: state},
				 {key: 'county', sourceNode: county}
			], 0);
		});

		$('[data-wnt-schooldistrict-bind]').each(function () {
			var state = $($(this).attr('data-wnt-schooldistrict-bind'))[0];
			var sd = $($(this).attr('data-wnt-schooldistrict-bind-sdn'))[0];
			WNT.bind(sd, [
				 {key: 'state', sourceNode: state}
			], 0);
		});

		$('[data-wnt-termsOfUse=]').click(function () {
			$('#agreeToVowTerms').attr('disabled', '');
			WNT.showPopup("VOWToU");
		});

		$('[data-wnt-toggle-container=]').each(function () {
			$(this).data("toggleContainer", WNT.toggleContainer(this));	
		});

		$('[data-wnt-hover-toggle-container=]').each(function () {
			$(this).data("hoverToggleContainer", WNT.hoverToggleContainer(this));	
		});

		$('[data-wnt-quicksearch=]').each(function(){
			WNT.quickSearch(this);
		});

		$('[data-wnt-map=]').each(function(){
				_createMap(this);
			});

			$('form[data-wnt-liveupdate-form=]').each(function(){
				_createLiveUpdate(this);
			});

			$('input[data-wnt-date]').each(function(){
				$(this).datepicker({minDate: $(this).attr('data-wnt-date')});
			});

			$('input[data-wnt-reload-value=]').each(function(){
				$(this).val($(this).attr('data-wnt-reload-value'));
			});

			$('input[data-wnt-emailSearch2Friend-ownerToggle=]').each(function(){
				$(this).click(function(){
					WNT.es2fOwnerToggle();
				});
			});

			$('form').each(function(){
				var validationForm = this;
				$(validationForm).submit(function(){
					return WNT.validation(validationForm);
				});
			});

			function _createLiveUpdate(formNode){
				var liveUpdate = WNT.liveUpdate(formNode, $(formNode).attr('data-wnt-liveupdate-url'), $(formNode).attr('data-wnt-mapmove-url'),{
					urlParams: $(formNode).attr('data-wnt-liveupdate-urlparams'),
					hasMap: $(formNode).attr('data-wnt-liveupdate-hasMap') == "true"
				});
				$(formNode).data("liveupdate", liveUpdate);
				// NOTE: Due to a bug in jQuery 1.4.2, we can't bind through an each loop
				// So we'll only bind the first map
				// There's also a bug with using scoped params, so we'll search the whole page
				// instead of just in the form like we should
				// TODO: Refactor loading as widget
				var maps = $('[data-wnt-map=]');
				if (maps.size()){
					var map = $(maps[0]).data('map');
					$(map).bind('moveStart zoomStart', function(){
						liveUpdate.cancelRequest();	
					});

					var houseOverPois = [];
					var houseOverIcons = {};
					$(liveUpdate).bind('sendingRequest', function(){
						$('#mainLoading').show();
						$(houseOverPois).each(function(){
							map.removePoi(this);
						});
						houseOverPois = [];
					});
					$(liveUpdate).bind('responceReceived', function(evt, data){
						$(data.listings).each(function(){
							if (houseOverIcons[this.icon] == undefined){
								houseOverIcons[this.icon] = WNT.mapIcon(this.icon, 21, 23);
							}
							var poi = WNT.poi(this.lat, this.lng, houseOverIcons[this.icon], this.html);
							map.addPoi(poi);
							houseOverPois.push(poi);
						});
						$('#mainLoading').hide();
						$('#showingCount').html(data.records);
					});
					// Handle houseover clicks
					$(window).bind('houseOverClick', function (evt, propertyId){
						$('[name=property_id]').val(propertyId);
						liveUpdate.submit();
					});
				}

				$(liveUpdate).bind('responceReceived', function(evt, data){
					$('#matchCount').html(data.matches);
					$('#openHouseCount').html(data.open);
				});

				$(liveUpdate).bind('mapMoveReceived', function(evt, data){
					if (data.TL_Lat == -90 && data.TL_Lng == 180 && data.BR_Lat == 90 && data.BR_Lng == -180) {
						map.setCenter($(map.baseNode).attr('data-wnt-map-centerlat'), $(map.baseNode).attr('data-wnt-map-centerlng'), $(map.baseNode).attr('data-wnt-map-mapzoomlevel'));
					} else {
						map.zoomToRect(data.TL_Lat, data.TL_Lng, data.BR_Lat, data.BR_Lng);
					}
				});
				liveUpdate.sendRequest(0);

			}

			function _createMap(mapNode){
				var map = WNT.map(mapNode, {
					centerLat: $(mapNode).attr('data-wnt-map-centerlat'),
					centerLng: $(mapNode).attr('data-wnt-map-centerlng'),
					mapZoomLevel: $(mapNode).attr('data-wnt-map-mapzoomlevel'),
					hasHouseView: $(mapNode).attr('data-wnt-map-hasHouseView') === "true",
					hasStreetView: $(mapNode).attr('data-wnt-map-hasStreetView') === "true",
					hasMiniMap: $(mapNode).attr('data-wnt-map-hasminimap') === "true",
					showScales: $(mapNode).attr('data-wnt-map-showScales') === "true",
					isMoveable: $(mapNode).attr('data-wnt-map-isMoveable') === "true",
					provider: $(mapNode).attr('data-wnt-map-provider')
				});
				$(mapNode).data('map', map);

				// Move map to fit rectangle
				if ($(mapNode).attr('data-wnt-map-brLat')){
					map.zoomToRect($(mapNode).attr('data-wnt-map-tlLat'), $(mapNode).attr('data-wnt-map-tlLng'), $(mapNode).attr('data-wnt-map-brLat'), $(mapNode).attr('data-wnt-map-brLng'));
					window.setTimeout(function(){map.zoomIn();}, 2000);
				}

				// Set default view
				if ($(mapNode).attr('data-wnt-map-view') === 'hyb'){
					map.setHybridView();
				} else if  ($(mapNode).attr('data-wnt-map-view') === 'sat'){
					map.setSatView();
				} else if  ($(mapNode).attr('data-wnt-map-view') === 'house'){
					window.setTimeout(function(){map.setHouseView();}, 2000);
				} else if  ($(mapNode).attr('data-wnt-map-view') === 'street'){
					window.setTimeout(function(){map.setStreetView();}, 2000);
				}

				if ($(mapNode).attr('data-wnt-map-poi-icon')){
					var icon = WNT.mapIcon($(mapNode).attr('data-wnt-map-poi-icon'), 21, 23);
					var poi = WNT.poi($(mapNode).attr('data-wnt-map-poi-lat'), $(mapNode).attr('data-wnt-map-poi-lng'), icon);
					map.addPoi(poi);
				}

				var mapName = $(mapNode).attr('data-wnt-map-name');
				if (mapName !== undefined){
					$('[data-wnt-controlContainer=][data-wnt-map-name='+mapName+']').each(function(){
						$(this).data('controlContainer', WNT.controlContainer(this, map, {}));
					});

					$('[data-wnt-nav=][data-wnt-map-name='+mapName+']').each(function(){
						$(this).data('nav', WNT.navMapControl(this, map, {}));
					});

					$('[data-wnt-pan=][data-wnt-map-name='+mapName+']').each(function(){
						$(this).data('pan', WNT.panZoomMapControl(this, map, {
							expandedZoom: $(this).attr('data-wnt-pan-expandedzoom') === "true"
						}));
					});
					$('[data-wnt-poi][data-wnt-map-name='+mapName+']').each(function(){
						var poi = this;
						if ($(this).attr('data-wnt-poi') === 'mapquest'){
							var find = WNT.mapquestFind(map, 'jsreqhandler.cfm?sname=spatial.access.mapquest.com&spath=mq&sport=80');
						} else {
							var find = WNT.bingFind(map);
						}

						$(poi).data('poi', find);
						$('[data-wnt-poi-checkbox=]', poi).each(function(){
							var checkbox = this;
							var icon = $(this).attr('data-wnt-poi-icon');
							var value = $(this).val();
							$(checkbox).click(function(){
								if ($(checkbox).attr('checked')){
									find.add(value, icon);
								} else {
									find.remove(value);
								}
							});
						});

						$('[data-wnt-poi-textbox=]', poi).each(function(){
							var textbox = this;
							var icon = $(this).attr('data-wnt-poi-icon');
							var oldValue = $(this).val();

							$(textbox).change(function(){
								find.remove(oldValue);
								oldValue = $(textbox).val();
								find.add(oldValue, icon);
							});
						});

						$('[data-wnt-poi-select=]', poi).each(function(){
							var select = this;
							var icon = $(this).attr('data-wnt-poi-icon');
							var oldValue = $(this).val();

							$(select).change(function(){
								find.remove(oldValue);
								oldValue = $(select).val();
								find.add(oldValue, icon);
							});
						});

						var mapHeight = map.getSize().height;
						var mapWidth = map.getSize().width;
						$('[data-wnt-poi-expand=]', poi).click(function(){
							map.setSize(mapWidth, mapHeight*2);
						});
						$('[data-wnt-poi-collapse=]', poi).click(function(){
							map.setSize(mapWidth, mapHeight);
						});

					});

					var centerLat = $('[data-wnt-map-bind=centerLat][data-wnt-map-name='+mapName+']');
					var centerLng = $('[data-wnt-map-bind=centerLng][data-wnt-map-name='+mapName+']');
					var mapType = $('[data-wnt-map-bind=mapType][data-wnt-map-name='+mapName+']');
					var lrLat = $('[data-wnt-map-bind=lrLat][data-wnt-map-name='+mapName+']');
					var lrLng = $('[data-wnt-map-bind=lrLng][data-wnt-map-name='+mapName+']');
					var ulLat = $('[data-wnt-map-bind=ulLat][data-wnt-map-name='+mapName+']');
					var ulLng = $('[data-wnt-map-bind=ulLng][data-wnt-map-name='+mapName+']');
					var zoom = $('[data-wnt-map-bind=zoom][data-wnt-map-name='+mapName+']');

					var _setMapBindings = function(){
						centerLat.val(map.getCenter().lat);
						centerLng.val(map.getCenter().lng);
						mapType.val(map.getCurrentView());
						lrLat.val(map.getBounds().lr.lat);
						lrLng.val(map.getBounds().lr.lng);
						ulLat.val(map.getBounds().ul.lat);
						ulLng.val(map.getBounds().ul.lng);
						zoom.val(map.getZoomLevel());

						centerLat.change();
						centerLng.change();
						mapType.change();
						lrLat.change();
						lrLng.change();
						ulLat.change();
						ulLng.change();
						zoom.change();
					};

					_setMapBindings();
					$(map).bind('moveEnd zoomEnd', _setMapBindings);
				}
				$('[data-wnt-resetMap=]').click(function(){
					map.reset();
				});

				// track map usage
				var mapTrigger = 0;
				var mapTrack = function(){
					var myMapTrigger = ++mapTrigger;

					window.setTimeout(function(){
						if (myMapTrigger == mapTrigger){
							$.post('gateway.cfm?action=dbtrack', {
								page_type: "search",
								map_type: map.getCurrentView(),
								mt_version: 3
							});
						}
					}, 50);

				};

				$(map).bind('moveEnd zoomEnd', mapTrack);
				mapTrack();
			}
		});

	})(jQuery, function (msg) {
		if(window.console){
			console.log(msg);
		}
});
