/**
 * MLS Search Engine Plugin
 *	overview: This plugin provides all functions associated with the MLS Search Engine
 *
 *	usage: used for the MLS Search Engine
 *	dependencies: jQuery, ELabel, jquery.ListingDetails.js
 */
(function() {

	var searchAjaxActivity = null;
	var statsAjaxActivity = null;
	var config = null;
	var statisticsMessage = '<div style="padding:5px;">Loading Statistics, please wait (takes up to 15 seconds)...</div>';
	
	var searchType_residential = 0;
	var searchType_land = 1;
	var searchType_rental = 2;
	var searchType_commercialSale = 3;
	var searchType_commercialLease = 4;
	var searchType_mlsNumber = 5;
	var searchRequested = null;	// timeout indicating whether a search has been requested or not
	var searchTimeout = 500; // time to wait before running a search
	var selectedQZItem = ""; // storage for the selected non-layer quick zoom area id
	var mapLoaded = false;
	
	var listTabLabel = "<img src=\"/t/resources/rpm3.0/images/icons/searchEngine/viewOnList.gif\"/> View on List";
	var statsTabLabel = "<img src=\"/t/resources/rpm3.0/images/icons/searchEngine/marketStats.gif\"/> Market Statistics";
	var loadingLabel = "<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\" style=\"margin-top:-1px;\" /> Loading...";
		
	$.mlsSearchEngineMarketStats = function(initLoad){
		var opts = this;
		// fetch the statistics data from the server		
		if(self.statsAjaxActivity != null)
			self.statsAjaxActivity.abort();
			
		self.statsAjaxActivity = $.vIPAjax({
			type: "GET",
			url: this.config.absUrl,
			beforeSend: function(){
				if(initLoad){
					$("#statsView").html(loadingLabel);
				}else{
					$("#statisticsPanelLoadingOverlay").block({message: "<div style='font-size:2em;font-weight:bold;'>Loading...</div><img src='t/resources/rpm3.0/images/search_engine/map-ajax-loader.gif' />"});
				}
			},
			data: "pathway=48&mkt=true&envPropType="+this.config.mlsSearchType+"&"+$.generateSerializedRPMFields(this.config.searchFields)+"&latitude="+this.config.map.getSouthwestBounds().lat()+"&latitude="+this.config.map.getNortheastBounds().lat()+"&longitude="+this.config.map.getSouthwestBounds().lng()+"&longitude="+this.config.map.getNortheastBounds().lng(),
			dataType: "html",
			async: true,
			error: function(data, error){
				alert("Error: mlsSearchEngineMarketStats(): " + error + " " + data);
			},
			success: function(data){
				if(initLoad){
					opts.config.currentSearchView = opts.config.searchViews.stats;
					$("#searchEngineMapContainer > div").css("display", "none");
				}
				$("#statisticsPanelModule").html(data);
			},
			complete: function(xmlhttprequest, successtype){
				if($.browser.msie && $.browser.version == "6.0"){
					$("#mapListingsSort").hide(); //for IE6
					$("#mapType").hide(); //for IE6
				}
				
				if(initLoad){
					$("#searchEngineMapContainer > div").css("display", "none");
					$("#statisticsPanel").css("display", "inline-block");
					$("#searchEngineViews li").removeClass("select");
					$("#statsView").parent("li").addClass("select");
					$("#statsView").html(statsTabLabel);
				}else{
					$("#statisticsPanelLoadingOverlay").unblock();
				}
				
				$(function(){
					$.graphListedVersusSold(listedVersusSold.MLSStatsListedVersusSold, $("#listedVersusSold"));
					$.graphDaysOnMarket(daysOnMarket.MLSStatsDOMs, $("#daysOnMarket"));
				});
				opts.statsAjaxActivity = null;
				$("#listingsPanelModule").html("");
			}, 
			failComplete: function(xmlhttprequest, successtype){
				window.scrollTo(0,0);
				if(initLoad){
					$("#statsView").html(statsTabLabel);
				}else{
					$("#statisticsPanelLoadingOverlay").unblock();
					opts.config.refactorMap = true;
					$("#mapView").click();
				}
				opts.statsAjaxActivity = null;
			}
		});
		
	};

	/** shows the blocking overlay on the left column
	  *
	  * @param type of loading overlay to display: listingDetails - listing details, mlsSearchType - changing mlsSearchType
	  */
	$.mLSSearchEngineShowBusyOverlay = function(busyType){
		//alert ("Show busy overlay called...");

		if(busyType == 'listingDetails'){ //Locks out search options and listings table.
			$('#searchEngineLeftColumnBusyOverlay, #searchEngineLeftColumnBusyCloseListingDetails').fadeIn();
			//$('#searchEngineListingsResultsSelect').hide(); // hide select for IE6 As it will always appear over the overlay otherwise.
		} else if(busyType == 'listDateRestriction'){ //Locks out search options but NOT listings table.
			$('#searchEngineLeftColumnBusyOverlayListDateRestriction, #searchEngineLeftColumnBusyCloseListDateRestriction').fadeIn();

			/* Shrink the overlay by the size of the listings results table, so as to not hide it. */
			//Get the height of the table and the current height of the overlay.
			var tableHeaderHeight = $('#searchEngineSelectContainer').outerHeight(true); //The header above the table.
			var tableHeight = $('#searchEngineResultsTableContainer').outerHeight(true); //The table itself.
			var overlayHeight = $('#searchEngineLeftColumnBusyOverlay').outerHeight(true); //Our current overlay.

			//Reset the height of the overlay so it don't block the table.
			$('#searchEngineLeftColumnBusyOverlayListDateRestriction').css('height', overlayHeight - tableHeight - tableHeaderHeight);

		} else{ //Locks out search options and listings table.
			$('#searchEngineLeftColumnBusyOverlay, #searchEngineLeftColumnBusyLoadingMessage').fadeIn();
			//$('#searchEngineListingsResultsSelect').hide(); // hide select for IE6 As it will always appear over the overlay otherwise.
		}
		
		// hide all select elements for IE6 As it will always appear over the overlay otherwise.
		if($.browser.msie && $.browser.version == "6.0"){
			$("#searchTypes").hide();
			$("#searchEngineSearchOptions").find(".right").each(function(){
				$(this).hide();
			});

			if(this.config.currentSearchView == this.config.searchViews.map){
				$("#mapListingsSort").hide(); //for IE6
				$("#mapType").hide(); //for IE6
				
			}else if(this.config.currentSearchView == this.config.searchViews.list){
				$("#listingsSort").hide();
			}
		}
	}

	/** hides the blocking overlay on the left column
	  *
	  */
	$.mLSSearchEngineHideBusyOverlay = function(busyType){
		if(busyType == 'listingDetails'){ 
			$('#searchEngineLeftColumnBusyOverlay, #searchEngineLeftColumnBusyCloseListingDetails').fadeOut();
			//$('#searchEngineListingsResultsSelect').show();	// for IE6
		} else if(busyType == 'listDateRestriction'){ //Locks out search options but NOT listings table.
			$('#searchEngineLeftColumnBusyOverlayListDateRestriction, #searchEngineLeftColumnBusyCloseListDateRestriction').fadeOut();
		} else{ //Locks out search options and listings table.
			$('#searchEngineLeftColumnBusyOverlay, #searchEngineLeftColumnBusyLoadingMessage').fadeOut();
			//$('#searchEngineListingsResultsSelect').show();	// for IE6
		}
		
		// show previously hidden select elements for IE6
		if($.browser.msie && $.browser.version == "6.0"){	
			$("#searchTypes").show();
			$("#searchEngineSearchOptions").find(".right").each(function(){
				$(this).show();
			});
			
			if(this.config.currentSearchView == this.config.searchViews.map){
				$("#mapListingsSort").show(); //for IE6
				$("#mapType").show(); //for IE6
				
			}else if(this.config.currentSearchView == this.config.searchViews.list){
				$("#listingsSort").show();
			}
		}
	}

	/** shows the listing details in an overlay
	  *
	  * @param listnum the listing number for the listing to be displayed
	  */
	$.mLSSearchEngineShowListingDetails = function(listnum){
		$.ajax({
			type: "GET",
			url: "listings",
			data: "pathway=6&type=mls&envPropType="+this.config.mlsSearchType+"&listingNumber="+listnum+"&viewType=mls",
			async: true,
			dataType: "html",
			beforeSend: function(){
				$.mLSSearchEngineShowBusyOverlay('listingDetails');
				$('#searchEngineLeftColumnBusyCloseListingDetails').click(function(){
					return $.mLSSearchEngineHideListingDetails();
				});
			},
			error: function(data, error){
				alert("Error: showListingDetails(): " + error + " " + data.toString());
			},
			success: function(data){
				// load the listing into the right panel
				$("#seListingContainer").children().html(data);
				
				// hide the map and show the listing
				//$('#searchEngineMapContainer').hide();
				$('#searchEngineResultContainer').fadeIn();
				
				$(document).ready(function(){
					$.initListingDetailsSlideshow($("#listing_otherStatus").val());
				});
				
			}
		});
		return false;
	}

	/**
	 * hides the listing details in an overlay 
	 * 
	 */
	$.mLSSearchEngineHideListingDetails = function(){
		// hide the map and show the listing
		$('#searchEngineResultContainer').fadeOut();
		$.mLSSearchEngineHideBusyOverlay("listingDetails");
		$("#seListingContainer").children().empty();
		
		return false;
	}

	/**
	 *
	 */
	$.mLSSearchEngine = function(options){
		var self = this;
		
		/** ListingIcon
		  *
		  * @param iconFile name of the icon file to be used for this icon
		  */
		function ListingIcon(iconFile){
			var icon = new GIcon();
			icon.image = "/t/resources/rpm3.0/images/icons/searchEngine/" + iconFile;
			icon.shadow = "/t/resources/rpm3.0/images/icons/searchEngine/shadow.png";
			//icon.transparent = "http://" + window.location.host + "/t/resources/rpm3.0/images/icons/transparent.png";
			icon.iconSize = new GSize(18, 29);
			icon.shadowSize = new GSize(28, 38);
			icon.iconAnchor = new GPoint(9, 29);
			icon.infoWindowAnchor = new GPoint(9, 15);
			icon.infoShadowAnchor = new GPoint(0, 0);
			return icon;
		}
		
		/** Listing
		  *
		  * @param listNum unique listing number for this listing
		  * @param mlsnum unique MLS Number for this listing
		  * @param propType the type of property this is
		  * @param lat the lattitude for this Listing
		  * @param lng the longitude for this Listing
		  * @param stat the status for this Listing
		  * @param mCol the color of the marker
		  * @param addr the address for this Listing
		  * @param sqft the area of this Listing in square feet
		  * @param sqft the area of this Listing
		  * @param bdrm the number of bedrooms 
		  * @param btrm the number of bathrooms
		  * @param price the price
		  */
		function Listing(listnum, mlsnum, propType, lat, lng, stat, mCol, addr, sqft, bdrm, btrm, price){
			this.listnum = listnum;
			this.mlsnum = mlsnum;
			this.propType = propType;
			this.lat = lat;
			this.lng = lng;
			this.st = stat;
			this.mCol = mCol;
			this.addr = addr;
			this.sqft = sqft;
			this.bdrm = bdrm;
			this.btrm = btrm;
			this.price = price;
			this.marker = null;
			this.handler = null;
			this.mOverHandler = null;
			this.mOutHandler = null;
			this.html = "<table border='1'><tr><td>Price:</td><td>" + this.price + "</td></tr></table>";
			this.iconIndex = this.getIconIndex();
			this.summ = "";
			this.desc = "";
			//this.polygon = null; //Testing, delete when done;
		}

		/** adds a Listing to the map
		  *
		  * @param icons a list of icons available to the map
		  */
		Listing.prototype.addToMap = function(icons){
			if(this.marker == null){
				this.marker = new GMarker(new GLatLng(this.lat, this.lng), icons[this.getIconIndex()]);
				// Testing Start
				/*
				if(this.polygon != null){
					self.config.map.removeOverlay(this.polygon);
				}
				var bounds = this.getBounds();
				var point = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(this.marker.getLatLng(), self.config.map.getMap().getZoom());
				var offset = this.marker.getIcon().iconAnchor;
				var width = this.marker.getIcon().iconSize.width;
				var height = this.marker.getIcon().iconSize.height;
				
				var listingNW = new GLatLng(bounds.getSouthWest().lat(), bounds.getNorthEast().lng());
				var listingSE = new GLatLng(bounds.getNorthEast().lat(), bounds.getSouthWest().lng());

				var points = [];
				points.push(listingNW);
				points.push(bounds.getNorthEast());
				points.push(listingSE);
				points.push(bounds.getSouthWest());
				points.push(listingNW);
				
				this.polygon = new GPolyline(points, "RED");
				
				self.config.map.addOverlay(this.polygon);
				*/
				// Testing Done
				self.config.map.addOverlay(this.marker);
				this.handler = GEvent.bindDom(this.marker, "click", this, this.openHTMLWindow);
				this.mOverHandler = GEvent.bindDom(this.marker, "mouseover", this, this.showHighlight);
				this.mOutHandler = GEvent.bindDom(this.marker, "mouseout", this, this.hideHighlight);
			}
		};

		/** 
		  * removes this listing from the map
		  *
		  * @param map GMap2 to remove the listings from
		  */
		Listing.prototype.removeFromMap = function(){
			// remove listeners
			if(this.handler != null){
				GEvent.removeListener(this.mOutHandler);
				GEvent.removeListener(this.mOverHandler);
				GEvent.removeListener(this.handler);
			}
			// remove marker
			if(this.marker != null){
				self.config.map.removeOverlay(this.marker);
			}
			if(this.polygon != null){
				self.config.map.removeOverlay(this.polygon);
			}
		};
			
		/** Returns the marker
		  *
		  */
		Listing.prototype.getMarker = function(){
			return this.marker;
		};
		
		Listing.prototype.getBounds = function(){
			var listingMarker = this.marker;
			if(listingMarker == null)
				listingMarker = new GMarker(new GLatLng(this.lat, this.lng), self.config.map.listingIcons[this.iconIndex]);
			
			var width = listingMarker.getIcon().iconSize.width;
			var height = listingMarker.getIcon().iconSize.height;
			var point = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(listingMarker.getLatLng(), self.config.map.getMap().getZoom());
			var offset = listingMarker.getIcon().iconAnchor;
			var NE_x = parseFloat(point.x - offset.x + width + self.config.map.clusterSensitivity);
			var NE_y = parseFloat(point.y - offset.y - self.config.map.clusterSensitivity);
			var SW_x = parseFloat(point.x - offset.x - self.config.map.clusterSensitivity);
			var SW_y = parseFloat(point.y - offset.y + height + self.config.map.clusterSensitivity);
			var listingNE = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(NE_x, NE_y), self.config.map.getMap().getZoom());
			var listingSW = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(SW_x, SW_y), self.config.map.getMap().getZoom());
			var listingBounds = new GLatLngBounds(listingSW, listingNE);
			
			listingMarker = null; // Ensure this line doesn't render this.marker null as well...
			
			return listingBounds;
		};

		/** shows the highlight for this listing
		  *
		  */
		Listing.prototype.showHighlight = function(){
			// add content to tooltip
			self.config.map.tooltip.innerHTML = "<div class='listingToolTip'>"+this.mlsnum+"</div>";
			
			var point = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(self.config.map.getMap().fromDivPixelToLatLng(new GPoint(0,0),true),self.config.map.getMap().getZoom());
			var offset = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(this.marker.getPoint(),self.config.map.getMap().getZoom());
			var anchor = this.marker.getIcon().iconAnchor;
			var width = this.marker.getIcon().iconSize.width;
			var height = self.config.map.tooltip.clientHeight;
			var pos = new GControlPosition(G_ANCHOR_TOP_LEFT,new GSize(offset.x-point.x-anchor.x+width,offset.y-point.y-anchor.y-height));
			var hpos = new GControlPosition(G_ANCHOR_TOP_LEFT,new GSize(offset.x-point.x-anchor.x-21,offset.y-point.y-anchor.y-19));
			
			// show the tooltip
			pos.apply(self.config.map.tooltip);
			self.config.map.tooltip.style.visibility="visible";

			// show the highlight
			hpos.apply(self.config.map.highlight);
			self.config.map.highlight.style.visibility="visible";
		};
	
		/** hides the highlight for this listing
		  *
		  */
		Listing.prototype.hideHighlight = function(){
			self.config.map.tooltip.style.visibility="hidden";
			self.config.map.highlight.style.visibility="hidden";
		};
			
		/** gets the index of the appropriate icon from the icons
		  *
		  * @return integer representing the index of the icon on the icon array
		  */
		Listing.prototype.getIconIndex = function(){
			var iconIndex;
			switch(this.mCol){
				case "Blue":
					iconIndex = 0; //Blue (New) TODO: Calculate if listing is new
					break;
				case "Green":
					iconIndex = 4; //Green (Active)
					break;
				case "Yellow":
					iconIndex = 8; //Yellow (Pending)
					break;
				default:
					iconIndex = 12; //Red (Sold)
					break;
			}
			
			if(self.config.mlsSearchType == searchType_residential){
				switch(this.propType){
					case "1":
						iconIndex += 0; //house
						break;
					case "2":
						iconIndex += 1;	//condo
						break;
				}
			}else if(self.config.mlsSearchType == searchType_commercialSale || self.config.mlsSearchType == searchType_commercialLease){
				iconIndex += 3; //commercial
			}else if(self.config.mlsSearchType == searchType_land){
				iconIndex += 2; //land
			}
			return iconIndex;
		};
	
		/** opens a summary view for this listing
		  *
		  */
		Listing.prototype.openHTMLWindow = function(){
			var listingData;
			$.ajax({
				type: "GET",
				url: "listings?pathway=1&mls=true&envPropType="+self.config.mlsSearchType+"&listingNumber_1="+this.listnum,
				async: false,
				dataType: "html",
				error: function(data, error){
					alert("Error: Listing.openHTMLWindow(): " + error + " " + data.toString());
				},
				success: function(data){
					try{
						listingData = data;
					}catch(ex){
						alert("Listing.openHTMLWindow() -Success- " + ex);
					}
				}
			});

			if(listingData != ""){
				//Get center position of map before opening GInfoWindow
				self.config.map.setSavedPosition();

				//place map on center of marker
				var markerPos = this.marker.getLatLng();
				var markerPosPix = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(markerPos, self.config.map.getMap().getZoom());
				markerPosPix.y -= 50;
				markerPos = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(markerPosPix, self.config.map.getMap().getZoom());
				
				var thisMarker = this.marker;
				var markerPanEvent = GEvent.addListener(self.config.map.getMap(), "moveend", function(){
					thisMarker.openInfoWindowHtml(listingData, {maxWidth:1000});
					GEvent.removeListener(markerPanEvent);
					markerPanEvent = null;
				});
				
				self.config.map.getMap().panTo(markerPos);
				
			}else{
				alert("Too Fast...");
			}
		};
		
		function ListingCluster(listings){
			this.marker = null;
			this.listings = listings; // Hashtable of Listing objects
			this.handler = null;
			this.mOverHandler = null;
			this.mOutHandler = null;
			this.bounds = null;
			this.newBounds = null;
			this.padding = 0;
			this.iconIndex = 0;
			this.polygon = null; //For testing, delete when done
		}
		
		ListingCluster.prototype.getIconIndex = function(){
			var iconIndex = 16;
			this.listings.moveFirst();
			while(this.listings.next()){
				if(this.listings.getValue() != null){
					switch(this.listings.getValue().mCol){
						case "Blue":
							iconIndex = 16; //Blue (New)
							break;
						case "Green":
							iconIndex = 20; //Green (Active)
							break;
						case "Yellow":
							iconIndex = 24; //Yellow (Pending)
							break;
						default:
							iconIndex = 28; //Red (Sold)
							break;
					}
					
					if(self.config.mlsSearchType == searchType_residential){
						switch(this.listings.getValue().propType){
							case "1":
								iconIndex += 0; //house
								break;
							case "2":
								iconIndex += 1;	//condo
								break;
						}
					}else if(self.config.mlsSearchType == searchType_land){
						iconIndex += 2; //land
					}else if(self.config.mlsSearchType == searchType_commercialSale || self.config.mlsSearchType == searchType_commercialLease){
						iconIndex += 3; //commercial
					}
					break;
				}
			}
			return iconIndex;
		};
				
		ListingCluster.prototype.markerPosition = function() {
			if(this.bounds == null)
				this.setMarkerBounds();
			return this.bounds.getCenter();
		};
		
		ListingCluster.prototype.markerBounds = function() {
			var markerBounds, initListName, temp;
			
			this.listings.moveFirst();
			while(this.listings.next()){
				initListName = this.listings.getValue().listnum; 
				
				temp = new GMarker(new GLatLng(this.listings.getValue().lat, this.listings.getValue().lng), self.config.listingIcons[this.iconIndex]);
				
				var width = temp.getIcon().iconSize.width;
				var height = temp.getIcon().iconSize.height;
				var point = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(temp.getLatLng(), self.config.map.getMap().getZoom());
				var offset = temp.getIcon().iconAnchor;
				var NE_x = parseFloat(point.x - offset.x + width + self.config.map.clusterSensitivity);
				var NE_y = parseFloat(point.y - offset.y - self.config.map.clusterSensitivity);
				var SW_x = parseFloat(point.x - offset.x - self.config.map.clusterSensitivity);
				var SW_y = parseFloat(point.y - offset.y + height + self.config.map.clusterSensitivity);
				var clusterNE = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(NE_x, NE_y), self.config.map.getMap().getZoom());
				var clusterSW = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(SW_x, SW_y), self.config.map.getMap().getZoom());
				markerBounds = new GLatLngBounds(clusterSW, clusterNE);
				
				temp = null;
				break;
			}
			
			this.listings.moveFirst();
			while(this.listings.next()){
				if(this.listings.getValue().listnum != initListName)
					markerBounds.extend(new GLatLng(this.listings.getValue().lat, this.listings.getValue().lng));
			}
			
			temp = new GMarker(markerBounds.getCenter(), self.config.listingIcons[this.iconIndex]);
			
			var width = temp.getIcon().iconSize.width;
			var height = temp.getIcon().iconSize.height;
			var point = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(temp.getLatLng(), self.config.map.getMap().getZoom());
			var offset = temp.getIcon().iconAnchor;
			var NE_x = parseFloat(point.x - offset.x + width + self.config.map.clusterSensitivity);
			var NE_y = parseFloat(point.y - offset.y - self.config.map.clusterSensitivity);
			var SW_x = parseFloat(point.x - offset.x - self.config.map.clusterSensitivity);
			var SW_y = parseFloat(point.y - offset.y + height + self.config.map.clusterSensitivity);
			var markerNE = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(NE_x, NE_y), self.config.map.getMap().getZoom());
			var markerSW = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(SW_x, SW_y), self.config.map.getMap().getZoom());
			markerBounds = new GLatLngBounds(markerSW, markerNE);
			
			return markerBounds;
		};
		
		ListingCluster.prototype.getMarkerBounds = function() {
			if(this.bounds == null){
				this.bounds = this.markerBounds();
			}
			return this.bounds;
		};
		
		ListingCluster.prototype.getNewMarkerBounds = function() {
			return this.markerBounds();
		};
		
		ListingCluster.prototype.setMarkerBounds = function() {
			this.bounds = this.markerBounds();
		};
		
		//needed?
		ListingCluster.prototype.setNewMarkerBounds = function() {
			this.newBounds = this.markerBounds();
		};	
		
		ListingCluster.prototype.resetMarkerPosition = function() {
			this.setNewMarkerBounds();
			if(!this.bounds.equals(this.newBounds)){
				this.removeMarker();
				this.bounds = this.newBounds;
				this.marker.setLatLng(this.markerPosition());
				this.marker = new GMarker(this.bounds.getCenter(), self.config.listingIcons[this.getIconIndex()]);  //debug
				self.config.map.addOverlay(this.marker);
				this.initMarkerEvents();
			}
		};
		
		ListingCluster.prototype.initializeMarker = function() {
			if(this.listings.size() > 1){
				if(this.marker == null)
					this.marker = new GMarker(this.bounds.getCenter(), self.config.map.listingIcons[this.getIconIndex()]);
				self.config.map.addOverlay(this.marker);
				this.initMarkerEvents();				
			}
		};
		
		ListingCluster.prototype.removeMarker = function() {
			if(this.marker != null){
				this.removeMarkerEvents();
				self.config.map.removeOverlay(this.marker);
			}
		};
		
		ListingCluster.prototype.destroyMarker = function() {
			this.removeMarker();
			this.marker = null;
			this.listings = null;
		};
		
		ListingCluster.prototype.initMarkerEvents = function() {
			if(this.marker != null){
				this.handler = GEvent.bindDom(this.marker, "click", this, this.openHTMLWindow);
				this.mOverHandler = GEvent.bindDom(this.marker, "mouseover", this, this.showHighlight);
				this.mOutHandler = GEvent.bindDom(this.marker, "mouseout", this, this.hideHighlight);
			}
		};
		
		ListingCluster.prototype.showHighlight = function(){
			// add content to tooltip
			var mlsnums = "";
			this.listings.moveFirst();
			while(this.listings.next()){
				mlsnums += this.listings.getValue().mlsnum + "<br/>";
			}
			
			self.config.map.tooltip.innerHTML = "<div class='listingToolTip'>"+this.listings.size()+" Listings <br/> " + mlsnums + "</div>";
			
			var point = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(self.config.map.getMap().fromDivPixelToLatLng(new GPoint(0,0),true),self.config.map.getMap().getZoom());
			var offset = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(this.marker.getPoint(),self.config.map.getMap().getZoom());
			var anchor = this.marker.getIcon().iconAnchor;
			var width = this.marker.getIcon().iconSize.width;
			var height = self.config.map.tooltip.clientHeight;
			var pos = new GControlPosition(G_ANCHOR_TOP_LEFT,new GSize(offset.x-point.x-anchor.x+width,offset.y-point.y-anchor.y-height));
			var hpos = new GControlPosition(G_ANCHOR_TOP_LEFT,new GSize(offset.x-point.x-anchor.x-21,offset.y-point.y-anchor.y-19));
			
			// show the tooltip
			pos.apply(self.config.map.tooltip);
			self.config.map.tooltip.style.visibility="visible";

			// show the highlight
			hpos.apply(self.config.map.highlight);
			self.config.map.highlight.style.visibility="visible";
		};
	
		ListingCluster.prototype.hideHighlight = function(){
			self.config.map.tooltip.style.visibility="hidden";
			self.config.map.highlight.style.visibility="hidden";
		};
		
		/**
		* TODO: Implement code & view for multiple listings
		*/
		ListingCluster.prototype.openHTMLWindow = function(selectedId){
			var listingData;
			var listNums = "";
			this.listings.moveFirst();
			
			var count = 1;
			while(this.listings.next()){
				if(this.listings.getValue() != null){
					listNums += "&listingNumber_" + count + "=" + this.listings.getValue().listnum;
					count++;
				}
			}
			
			if(listNums == "") return; //FAIL!!!!
			
			$.ajax({
				type: "GET",
				url: "listings?pathway=1&mls=true&envPropType="+self.config.mlsSearchType+listNums,
				async: false,
				dataType: "html",
				error: function(data, error){
					alert("Error: Listing.openHTMLWindow(): " + error + " " + data.toString());
				},
				success: function(data){
					try{
						listingData = data;
					}catch(ex){
						alert("Listing.openHTMLWindow() -Success- " + ex);
					}
				}
			});

			if(listingData != ""){
				//Get center position of map before opening GInfoWindow
				self.config.map.setSavedPosition();
				
				//Move content to selected listing
				var infoWindowEvent = GEvent.addListener(this.marker, "infowindowopen", function(){
					if(typeof selectedId == "string"){
						$("#mlsSummaries").scrollTop($("#ln_"+selectedId).position().top);
					}
					GEvent.removeListener(infoWindowEvent);
				});
				
				//place map on center of marker
				var markerPos = this.marker.getLatLng();
				var markerPosPix = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(markerPos, self.config.map.getMap().getZoom());
				markerPosPix.y -= 85;
				markerPos = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(markerPosPix, self.config.map.getMap().getZoom());
				
				var thisMarker = this.marker;
				var markerPanEvent = GEvent.addListener(self.config.map.getMap(), "moveend", function(){
					thisMarker.openInfoWindowHtml(listingData, {maxWidth:1000});
					GEvent.removeListener(markerPanEvent);
					markerPanEvent = null;
				});
				
				self.config.map.getMap().panTo(markerPos);
				
			}else{
				alert("Too Fast...");
			}
		};
		
		ListingCluster.prototype.removeMarkerEvents = function() {
			if(this.mOutHandler != null){
				GEvent.removeListener(this.mOutHandler);
				this.mOutHandler = null;
			}
			
			if(this.mOverHandler != null){
				GEvent.removeListener(this.mOverHandler);
				this.mOverHandler = null;
			}
			
			if(this.handler != null){
				GEvent.removeListener(this.handler);
				this.handler = null;
			}
		};
		
		ListingCluster.prototype.listingExists = function(listnum) {
			this.listings.moveFirst();
			while(this.listings.next()){
				if(this.listings.getKey() == listnum){
					return true;
				}
			}
			return false;
		};
		
		ListingCluster.prototype.removeListing = function(listnum) {
			if(this.listings.size() == 0)
				return false;
			var size = this.listings.size();
			this.listings.remove(listnum);
			if(this.listings.size() != size){ //Item Removed
				return true;
			}else{ //No Change
				return false;
			}
		};
		
		ListingCluster.prototype.addListing = function(listnum, listingData) {
			if(!this.listingExists(listnum)){
				this.listings.put(listnum, listingData);
			}
		};
		
		ListingCluster.prototype.isEmpty = function() {
			if(this.listings == null){
				return true;
			}else{
				if(this.listings.size() == 0){
					return true;
				}else{
					return false;
				}
			}
		};
		
		ListingCluster.prototype.size = function() {
			return this.listings.size();
		};
		
		function AreaLabel(lat, lng, text) {
			this.coords = new GLatLng(lat, lng);
			this.text = text.replace("[\s]/g", "&nbsp");
			this.label = null;
			this.pos = null;
			this.addLabel();
		}
		
		AreaLabel.prototype.addLabel = function() {
			this.label = new ELabel(this.coords, this.text, "areaId", new GSize(0,0), 80, false);
			self.config.map.addOverlay(this.label);
			var gS = new GSize(($(".areaId").width()/2) * -1, $(".areaId").height()/2);
			self.config.map.removeOverlay(this.label);
			this.label.pixelOffset = gS;
			self.config.map.addOverlay(this.label);
		};
		
		AreaLabel.prototype.removeLabel = function() {
			self.config.map.removeOverlay(this.label);
		};
		
		function RPMMapTools(myCenterCoords, myZoom) {
			this.initCenter = myCenterCoords;
			this.initZoom = myZoom;
			this.self = this;
			this.drag = false;
			this.prev_page = false;
			this.next_page = false;
			this.prevPage_event = false;
			this.nextPage_event = false;
		}
		
		RPMMapTools.prototype = new GControl(true, false);
		
		RPMMapTools.prototype.printable = function() {
			return true
		};
		
		RPMMapTools.prototype.selectable = function() {
			return true
		};
		
		RPMMapTools.prototype.getDefaultPosition = function() {
			return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0, 0));
		};
		
		RPMMapTools.prototype.initialize = function(mapRef) {
			var initSelf = this;
			var container = document.createElement("div");
			container.id = "mlsSearchMapToolsContainer";
			container.style.zIndex = "9999";
			container.style.position = "relative";
			container.style.width = "692px";
			container.style.height = "93px";
			
			try{
				//Buttons - Movement
				var mapDir_up = document.createElement("div");
				mapDir_up.id = "mapDir_up";
				this.setDirBtnStyles_(mapDir_up);
				mapDir_up.style.background = "url('/t/resources/rpm3.0/images/search_engine/upArrow.png') no-repeat top left";
				mapDir_up.style.top = "12px";
				mapDir_up.style.left = "37px";
				mapDir_up.style.cursor = "pointer";
				mapDir_up.className = "up_arrow";
				container.appendChild(mapDir_up);
				GEvent.addDomListener(mapDir_up, "mousedown", function() {
					self.config.disableMapMoveEvent = true;
					mapDir_up.innerHTML = "<img src='/t/resources/rpm3.0/images/search_engine/upArrowA.png' style='width=20px; height=20px' />";
				});
				GEvent.addDomListener(mapDir_up, "mouseup", function() {
					mapRef.panDirection(0, +1);
					mapDir_up.innerHTML = "";
					$(function(){
						var event;
						event = GEvent.addDomListener(self.config.map.getMap(), "moveend", function(){
							self.config.disableMapMoveEvent = false;
							$.mLSSearchEngineRunSearch(self.config.currentPage, false);
							GEvent.removeListener(event);
							event = null;
						});
					});
				});
				
				var mapDir_right = document.createElement("div");
				this.setDirBtnStyles_(mapDir_right);
				mapDir_right.style.background = "url('/t/resources/rpm3.0/images/search_engine/rightArrow.png') no-repeat top left";
				mapDir_right.style.top = "37px";
				mapDir_right.style.left = "61px";
				mapDir_right.style.cursor = "pointer";
				container.appendChild(mapDir_right);
				GEvent.addDomListener(mapDir_right, "mousedown", function() {
					self.config.disableMapMoveEvent = true;
					mapDir_right.innerHTML = "<img src='/t/resources/rpm3.0/images/search_engine/rightArrowA.png' style='width=20px; height=20px' />";
				});
				GEvent.addDomListener(mapDir_right, "mouseup", function() {
					mapRef.panDirection(-1, 0);
					mapDir_right.innerHTML = "";
					$(function(){
						var event;
						event = GEvent.addDomListener(self.config.map.getMap(), "moveend", function(){
							self.config.disableMapMoveEvent = false;
							$.mLSSearchEngineRunSearch(self.config.currentPage, false);
							GEvent.removeListener(event);
							event = null;
						});
					});
				});
				
				var mapDir_down = document.createElement("div");
				this.setDirBtnStyles_(mapDir_down);
				mapDir_down.style.background = "url('/t/resources/rpm3.0/images/search_engine/downArrow.png') no-repeat top left";
				mapDir_down.style.top = "62px";
				mapDir_down.style.left = "37px";
				mapDir_down.style.cursor = "pointer";
				container.appendChild(mapDir_down);
				GEvent.addDomListener(mapDir_down, "mousedown", function() {
					self.config.disableMapMoveEvent = true;
					mapDir_down.innerHTML = "<img src='/t/resources/rpm3.0/images/search_engine/downArrowA.png' style='width=20px; height=20px' />";
				});
				GEvent.addDomListener(mapDir_down, "mouseup", function() {
					mapRef.panDirection(0, -1);
					mapDir_down.innerHTML = "";
					$(function(){
						var event;
						event = GEvent.addDomListener(self.config.map.getMap(), "moveend", function(){
							self.config.disableMapMoveEvent = false;
							$.mLSSearchEngineRunSearch(self.config.currentPage, false);
							GEvent.removeListener(event);
							event = null;
						});
					});
				});
				
				var mapDir_left = document.createElement("div");
				this.setDirBtnStyles_(mapDir_left);
				mapDir_left.style.background = "url('/t/resources/rpm3.0/images/search_engine/leftArrow.png') no-repeat top left";
				mapDir_left.style.top = "37px";
				mapDir_left.style.left = "13px";
				mapDir_left.style.cursor = "pointer";
				container.appendChild(mapDir_left);
				GEvent.addDomListener(mapDir_left, "mousedown", function() {
					self.config.disableMapMoveEvent = true;
					mapDir_left.innerHTML = "<img src='/t/resources/rpm3.0/images/search_engine/leftArrowA.png' style='width=20px; height=20px' />";
				});
				GEvent.addDomListener(mapDir_left, "mouseup", function() {
					mapRef.panDirection(+1, 0);
					mapDir_left.innerHTML = "";
					$(function(){
						var event;
						event = GEvent.addDomListener(self.config.map.getMap(), "moveend", function(){
							self.config.disableMapMoveEvent = false;
							$.mLSSearchEngineRunSearch(self.config.currentPage, false);
							GEvent.removeListener(event);
							event = null;
						});
					});
				});
				
				//Buttons - Options
				var areaSelect_btn = document.createElement("div");  //Area Select Button
				areaSelect_btn.id = "areaSelect_btn";
				areaSelect_btn.style.width = "20px";
				areaSelect_btn.style.height = "20px";
				areaSelect_btn.style.cursor = "pointer";
				areaSelect_btn.style.background = "url('/t/resources/rpm3.0/images/search_engine/areaSelect.png') no-repeat top left";
				areaSelect_btn.style.position = "absolute";
				areaSelect_btn.style.display = "inline-block";
				var areaSelect_label = document.createElement("div");  //Label
				areaSelect_label.innerHTML = "Area Select Tool";
				areaSelect_label.style.width = "100px";
				areaSelect_label.style.marginTop = "3px";
				areaSelect_label.style.position = "absolute";
				areaSelect_label.style.right = "0px";
				areaSelect_label.style.display = "inline";
				var areaSelect = document.createElement("div");  //Container
				areaSelect.style.top = "9px";
				areaSelect.style.left = "109px";
				areaSelect.style.height = "20px";
				areaSelect.style.width = "125px";
				areaSelect.style.position = "relative";
				areaSelect.appendChild(areaSelect_btn);
				areaSelect.appendChild(areaSelect_label);
				container.appendChild(areaSelect);
				
				this.dragZoomEvent = null;
				
				GEvent.addDomListener(areaSelect_btn, "click", function() {
					if(!initSelf.drag){
						initSelf.drag = true;
						$("#areaSelect_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/areaSelectA.png' style='width=20px; height=20px' />");
						initSelf.dragZoomEvent = GEvent.addDomListener(container, "mousedown", function(){
							if(initSelf.drag = true){
								$("#areaSelect_btn").html("");
								dragZoomControl.initiateZoom();
								initSelf.drag = false;
								GEvent.removeListener(initSelf.dragZoomEvent);
							}
						});
					}else{
						initSelf.drag = false;
						$("#areaSelect_btn").html("");
						if(initSelf.dragZoomEvent != null){
							GEvent.removeListener(initSelf.dragZoomEvent);
							initSelf.dragZoomEvent = null;
						}
					}
				});
				
				// add a rectangle zoom box control
				var boxStyleOpts = {
					opacity: .2,
					border: "2px solid red"
				};
			
				// second set of options is for everything else
				var otherOpts = {
					buttonHTML: "",
					buttonZoomingHTML: "",
					buttonStartingStyle: {width: '0px', height: '0px'},
					overlayRemoveTime: 1000
				};
				
				//TODO: add events for toggling the area select button
				var eventOpts = {
					dragend : function() {
						initSelf.drag = false;
						if(initSelf.dragZoomEvent != null){
							GEvent.removeListener(initSelf.dragZoomEvent);
							initSelf.dragZoomEvent = null;
						}
						$("#areaSelect_btn").html("");
					}
				}
				
				var dragZoomControl = new DragZoomControl(boxStyleOpts, otherOpts, eventOpts);
				mapRef.addControl(dragZoomControl);
				
				GEvent.addDomListener(areaSelect_btn, "click", function() {
					dragZoomControl.initiateZoom();
				});

				var mapReset_btn = document.createElement("div");  //Reset Button
				mapReset_btn.style.width = "20px";
				mapReset_btn.style.height = "20px";
				mapReset_btn.style.cursor = "pointer";
				mapReset_btn.style.background = "url('/t/resources/rpm3.0/images/search_engine/mapReset.png') no-repeat top left";
				mapReset_btn.style.cssFloat = "left";
				mapReset_btn.style.display = "inline-block";
				mapReset_btn.style.position = "absolute";
				var mapReset_label = document.createElement("div");  //Label
				mapReset_label.innerHTML = "Reset The Map";
				mapReset_label.style.width = "105px";
				mapReset_label.style.marginTop = "3px";
				mapReset_label.style.right = "0px";
				mapReset_label.style.display = "inline";
				mapReset_label.style.position = "absolute";
				var mapReset = document.createElement("div");  //Container
				mapReset.style.position = "relative";
				mapReset.style.top = "16px";  //37px
				mapReset.style.left = "109px";
				mapReset.style.height = "20px";
				mapReset.style.width = "130px"; //130px
				mapReset.appendChild(mapReset_btn);
				mapReset.appendChild(mapReset_label);
				container.appendChild(mapReset);
				GEvent.addDomListener(mapReset_btn, "mousedown", function() {
					mapReset_btn.innerHTML = "<img src='/t/resources/rpm3.0/images/search_engine/mapResetA.png' style='width=20px; height=20px' />";
					mapRef.setCenter(initSelf.initCenter, initSelf.initZoom);
				});
				GEvent.addDomListener(mapReset_btn, "mouseup", function() {
					mapReset_btn.innerHTML = "";
					$(function(){
						$.mLSSearchEngineRunSearch(self.config.currentPage, false);
					});
				});
				
				//Slider - Zoom
				var zoomDec = document.createElement("div");  //Decrease Button
				zoomDec.style.background = "url('/t/resources/rpm3.0/images/search_engine/zoomOut.png') no-repeat top left";
				zoomDec.style.width = "20px";
				zoomDec.style.height = "20px";
				zoomDec.style.cursor = "pointer";
				zoomDec.style.display = "inline-block";
				zoomDec.style.position = "absolute";
				zoomDec.style.left = "0px";
				GEvent.addDomListener(zoomDec, "mousedown", function() {
					zoomDec.innerHTML = "<img src='/t/resources/rpm3.0/images/search_engine/zoomOutA.png' style='width=20px; height=20px' />";
					if(new Number($("#map_zoomSlider").slider("value")) > self.config.map.zoomSliderMin){
						mapRef.setZoom(mapRef.getZoom() - 1);
					}
				});
				GEvent.addDomListener(zoomDec, "mouseup", function() {
					zoomDec.innerHTML = "";
				});
				
				var zoomInc = document.createElement("div");  //Increase Button
				zoomInc.style.background = "url('/t/resources/rpm3.0/images/search_engine/zoomIn.png') no-repeat top right";
				zoomInc.style.width = "20px";
				zoomInc.style.height = "20px";
				zoomInc.style.cursor = "pointer";
				zoomInc.style.display = "inline-block";
				zoomInc.style.position = "absolute";
				zoomInc.style.right = "0px";
				GEvent.addDomListener(zoomInc, "mousedown", function() {
					zoomInc.innerHTML = "<img src='/t/resources/rpm3.0/images/search_engine/zoomInA.png' style='width=20px; height=20px' />";
					if(new Number($("#map_zoomSlider").slider("value")) < self.config.map.zoomSliderMax){
						mapRef.setZoom(mapRef.getZoom() + 1);
					}
				});
				GEvent.addDomListener(zoomInc, "mouseup", function() {
					zoomInc.innerHTML = "";
				});
				
				//For setting the slider on zoom change
				GEvent.addDomListener(mapRef, "zoomend", function(oldLevel, newLevel){
					$("#map_zoomSlider").slider("value", newLevel - (mapRef.getCurrentMapType().getMaximumResolution() - self.config.map.zoomSliderMax));
				});
				
				//NOTE: Slider init & events are located after the map is initialized
				var zoomSlider = document.createElement("div"); //Slider
				zoomSlider.id = "map_zoomSlider";
				zoomSlider.style.width = "67px";
				zoomSlider.style.height = "20px";
				zoomSlider.style.display = "inline-block";
				zoomSlider.style.position = "absolute";
				zoomSlider.style.left = "20px";
				var zoomControl = document.createElement("div"); //Container
				zoomControl.style.top = "65px";
				zoomControl.style.left = "109px";
				zoomControl.style.position = "absolute";
				zoomControl.style.width = "114px";
				zoomControl.style.height = "20px";
				zoomControl.style.background = "url('/t/resources/rpm3.0/images/search_engine/zoomTrack.png') repeat-x scroll 50% 50%";
				zoomControl.appendChild(zoomDec);
				zoomControl.appendChild(zoomSlider);
				zoomControl.appendChild(zoomInc);
				container.appendChild(zoomControl);
				
				//Drop Downs - Options
				var listOrder_ddl = document.createElement("select");  //Listing Order DDL
				listOrder_ddl.id = "mapListingsSort";
				
				var listOrder_opt1 = document.createElement("option");
				listOrder_opt1.innerHTML = "Price Asc";
				listOrder_opt1.setAttribute("value", "0");
				listOrder_ddl.appendChild(listOrder_opt1);
				
				var listOrder_opt2 = document.createElement("option");
				listOrder_opt2.innerHTML = "Price Desc";
				listOrder_opt2.setAttribute("value", "1");
				listOrder_ddl.appendChild(listOrder_opt2);
				
				var listOrder_opt3 = document.createElement("option");
				listOrder_opt3.innerHTML = "List Date Asc";
				listOrder_opt3.setAttribute("value", "2");
				listOrder_ddl.appendChild(listOrder_opt3);
				
				var listOrder_opt4 = document.createElement("option");
				listOrder_opt4.innerHTML = "List Date Desc";
				listOrder_opt4.setAttribute("value", "3");
				listOrder_ddl.appendChild(listOrder_opt4);
				
				var listOrder_opt5 = document.createElement("option");
				listOrder_opt5.innerHTML = "Size Asc";
				listOrder_opt5.setAttribute("value", "4");
				listOrder_ddl.appendChild(listOrder_opt5);
				
				var listOrder_opt6 = document.createElement("option");
				listOrder_opt6.innerHTML = "Size Desc";
				listOrder_opt6.setAttribute("value", "5");
				listOrder_ddl.appendChild(listOrder_opt6);
				
				var listOrder_label = document.createElement("div");  //Listing Order Label
				listOrder_label.innerHTML = "Order Listings by";
				
				var mapType_ddl = document.createElement("select");  //Map Type DDL
				mapType_ddl.id = "mapType";
				var mapType_opt1 = document.createElement("option");
				mapType_opt1.innerHTML = "Map";
				mapType_opt1.setAttribute("value", "map");
				mapType_ddl.appendChild(mapType_opt1);
				
				var mapType_opt2 = document.createElement("option");
				mapType_opt2.innerHTML = "Satellite";
				mapType_opt2.setAttribute("value", "sat");
				mapType_ddl.appendChild(mapType_opt2);
				
				var mapType_opt3 = document.createElement("option");
				mapType_opt3.innerHTML = "Hybrid";
				mapType_opt3.setAttribute("value", "hyb");
				mapType_ddl.appendChild(mapType_opt3);
				
				var mapType_opt4 = document.createElement("option");
				mapType_opt4.innerHTML = "Terrain";
				mapType_opt4.setAttribute("value", "ter");
				mapType_ddl.appendChild(mapType_opt4);
				
				var mapType_label = document.createElement("div");  //Map Type Label
				mapType_label.innerHTML = "Map View Type";
				
				listOrder_label.style.position = "absolute";
				listOrder_label.style.left = "0px";
				listOrder_label.style.paddingTop = "3px";
				listOrder_ddl.style.position = "absolute";
				listOrder_ddl.style.left = "105px";
				$(listOrder_ddl).change(function(){
					$.mLSSearchEngineRunSearch($(this).val(), true);
				});
				
				mapType_label.style.position = "absolute";
				mapType_label.style.left = "245px";
				mapType_label.style.paddingTop = "3px";
				mapType_ddl.style.position = "absolute";
				mapType_ddl.style.left = "335px";
				$(mapType_ddl).change(function(){
					initSelf.changeMapType(mapRef,$(this).val());
				});
				
				var ddl_options = document.createElement("div");  //Drop Down Options Container
				ddl_options.appendChild(listOrder_label);
				ddl_options.appendChild(listOrder_ddl);
				ddl_options.appendChild(mapType_label);
				ddl_options.appendChild(mapType_ddl);
				
				ddl_options.style.position = "relative";
				ddl_options.style.width = "410px";
				ddl_options.style.height = "20px";
				ddl_options.style.top = "-30px";
				ddl_options.style.left = "270px";
				container.appendChild(ddl_options);
				
				//Buttons - Paging
				var firstPage_btn = document.createElement("div");
				firstPage_btn.id = "firstPage_btn";
				firstPage_btn.style.width = "20px";
				firstPage_btn.style.height = "20px";
				firstPage_btn.style.position = "absolute";
				firstPage_btn.style.background = "url('/t/resources/rpm3.0/images/search_engine/firstPage.png') no-repeat top left";
				firstPage_btn.style.display = "inline";
				//firstPage_btn.style.marginRight = "10px";
				firstPage_btn.style.left = "-55px";
				
				var prevPage_btn = document.createElement("div");
				prevPage_btn.id = "prevPage_btn";
				prevPage_btn.style.width = "20px";
				prevPage_btn.style.height = "20px";
				prevPage_btn.style.position = "absolute";
				prevPage_btn.style.background = "url('/t/resources/rpm3.0/images/search_engine/prevPage.png') no-repeat top left";
				prevPage_btn.style.display = "inline";
				//prevPage_btn.style.marginRight = "10px";
				prevPage_btn.style.left = "-25px";
				
				var paging_list = document.createElement("div");
				paging_list.id = "paging_list";
				//paging_list.innerHTML = "<div style='display:inline;'>1261</div> - <div style='display:inline;'>1262</div> - <div style='display:inline;'>1263</div> - <div style='display:inline;'>1264</div> - <div style='display:inline;'>1265</div> - <div style='display:inline;'>1266</div> - <div style='display:inline;'>1267</div>";
				paging_list.style.position = "relative";
				paging_list.style.display = "inline";
				paging_list.style.minWidth = "20px";
				paging_list.style.marginLeft = "5px";
				paging_list.style.marginRight = "5px";
				paging_list.style.top = "2px";
				
				var nextPage_btn = document.createElement("div");
				nextPage_btn.id = "nextPage_btn";
				nextPage_btn.style.width = "20px";
				nextPage_btn.style.height = "20px";
				nextPage_btn.style.position = "absolute";
				nextPage_btn.style.background = "url('/t/resources/rpm3.0/images/search_engine/nextPage.png') no-repeat top left";
				nextPage_btn.style.display = "inline";
				//nextPage_btn.style.marginLeft = "10px";
				nextPage_btn.style.right = "-25px";
				
				var lastPage_btn = document.createElement("div");
				lastPage_btn.id = "lastPage_btn";
				lastPage_btn.style.width = "20px";
				lastPage_btn.style.height = "20px";
				lastPage_btn.style.position = "absolute";
				lastPage_btn.style.background = "url('/t/resources/rpm3.0/images/search_engine/lastPage.png') no-repeat top left";
				lastPage_btn.style.display = "inline";
				//lastPage_btn.style.marginLeft = "10px";
				lastPage_btn.style.right = "-55px";
				
				var listPaging = document.createElement("div");
				listPaging.id = "listPaging";
				listPaging.appendChild(firstPage_btn);
				listPaging.appendChild(prevPage_btn);
				listPaging.appendChild(paging_list);
				listPaging.appendChild(nextPage_btn);
				listPaging.appendChild(lastPage_btn);
								
				listPaging.style.position = "absolute";
				//listPaging.style.maxWidth = "300px";
				listPaging.style.height = "20px";
				listPaging.style.top = "42px";
				listPaging.style.right = "67px";
				listPaging.style.textAlign = "center";
				listPaging.style.display = "none";
				container.appendChild(listPaging);
				
				//Text - Property Count
				var listShowing = document.createElement("div");
				listShowing.id = "listCountSummary";
				listShowing.width = "200px";
				listShowing.height = "22px";
				//listShowing.style.paddingTop = "3px";
				listShowing.style.position = "absolute";
				listShowing.style.top = "70px";
				listShowing.style.right = "9px";
				container.appendChild(listShowing);
				
			}catch(ex){
				alert("RPMMapTools.init() failed... \n" + ex.name + ": " + ex.message);
			}
			
			mapRef.getContainer().appendChild(container);
			return container;
		};
		
		RPMMapTools.prototype.enablePrevPaging = function(dec, min) {
			$("#firstPage_btn").html("");
			$("#firstPage_btn").attr("title", min);
			$("#firstPage_btn").css("cursor", "pointer");
			$("#firstPage_btn").unbind("mousedown").bind("mousedown", function(){
				$("#firstPage_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/firstPageA.png' style='width=20px; height=20px' />");
			});
			$("#firstPage_btn").unbind("mouseup").bind("mouseup", function(){
				$("#firstPage_btn").html("");
				$.mLSSearchEngineRunSearch(min, true);
			});
			
			$("#prevPage_btn").html("");
			$("#prevPage_btn").attr("title", dec);//testing
			$("#prevPage_btn").css("cursor", "pointer");
			$("#prevPage_btn").unbind("mousedown").bind("mousedown", function(){
				$("#prevPage_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/prevPageA.png' style='width=20px; height=20px' />");
			});
			$("#prevPage_btn").unbind("mouseup").bind("mouseup", function(){
				$("#prevPage_btn").html("");
				$.mLSSearchEngineRunSearch(dec, true);
			});
		};
		
		RPMMapTools.prototype.disablePrevPaging = function() {
			$("#firstPage_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/firstPageG.png' style='width=20px; height=20px' />");
			$("#firstPage_btn").css("cursor", "default");
			$("#firstPage_btn").unbind("mouseup");
			$("#firstPage_btn").unbind("mousedown");
			$("#firstPage_btn").removeAttr("title");
			
			$("#prevPage_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/prevPageG.png' style='width=20px; height=20px' />");
			$("#prevPage_btn").css("cursor", "default");
			$("#prevPage_btn").unbind("mouseup");
			$("#prevPage_btn").unbind("mousedown");
			$("#prevPage_btn").removeAttr("title");
		};
		
		RPMMapTools.prototype.enableNextPaging = function(inc, max) {
			$("#nextPage_btn").html("");
			$("#nextPage_btn").attr("title", inc); //testing
			$("#nextPage_btn").css("cursor", "pointer");
			$("#nextPage_btn").unbind("mousedown").bind("mousedown", function(){
				$("#nextPage_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/nextPageA.png' style='width=20px; height=20px' />");
			});
			$("#nextPage_btn").unbind("mouseup").bind("mouseup", function(){
				$("#nextPage_btn").html("");
				$.mLSSearchEngineRunSearch(inc, true);
			});
			
			$("#lastPage_btn").html("");
			$("#lastPage_btn").attr("title", max);
			$("#lastPage_btn").css("cursor", "pointer");
			$("#lastPage_btn").unbind("mousedown").bind("mousedown", function(){
				$("#lastPage_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/lastPageA.png' style='width=20px; height=20px' />");
			});
			$("#lastPage_btn").unbind("mouseup").bind("mouseup", function(){
				$("#lastPage_btn").html("");
				$.mLSSearchEngineRunSearch(max, true);
			});
		};
		
		RPMMapTools.prototype.disableNextPaging = function() {
			$("#nextPage_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/nextPageG.png' style='width=20px; height=20px' />");
			$("#nextPage_btn").css("cursor", "default");
			$("#nextPage_btn").unbind("mouseup");
			$("#nextPage_btn").unbind("mousedown");
			$("#nextPage_btn").removeAttr("title");
			
			$("#lastPage_btn").html("<img src='/t/resources/rpm3.0/images/search_engine/lastPageG.png' style='width=20px; height=20px' />");
			$("#lastPage_btn").css("cursor", "default");
			$("#lastPage_btn").unbind("mouseup");
			$("#lastPage_btn").unbind("mousedown");
			$("#lastPage_btn").removeAttr("title");
		};
		
		RPMMapTools.prototype.changeMapType = function(mapRef, mapType) {
			var curMapType = mapRef.getCurrentMapType();
			var newMapType;
			switch(mapType) {
				case "sat":
					newMapType = G_SATELLITE_MAP;
					break;
				case "hyb":
					newMapType = G_HYBRID_MAP;
					break;
				case "ter":
					newMapType = G_PHYSICAL_MAP;
					break;
				default: //"map"
					newMapType = G_NORMAL_MAP;
			}
			
			var curTypeMaxRes = new Number(curMapType.getMaximumResolution());
			var newTypeMinRes = new Number(newMapType.getMinimumResolution());
			var newTypeMaxRes = new Number(newMapType.getMaximumResolution());
			
			var zoom = new Number(mapRef.getZoom());
			var zoomOffset = new Number(0);
			var oldValue;
			var newValue;
			
			//alert("Current Map Type: " + curMapType.getName() + "\nNew Map Type: " + newMapType.getName() + "\nCurrent Max Res: " + curTypeMaxRes + "\nnewTypeMaxRes: " + newTypeMaxRes);
			
			if(zoom >= newTypeMaxRes) {
				zoom = newTypeMaxRes;
				$("#map_zoomSlider").slider("value", $("#map_zoomSlider").slider("option", "max"));
			} else if(zoom <= newTypeMinRes) {
				zoom = newTypeMinRes;
				$("#map_zoomSlider").slider("value", $("#map_zoomSlider").slider("option", "min"));
			} else if(curTypeMaxRes > newTypeMaxRes) {
				zoomOffset = curTypeMaxRes - newTypeMaxRes;
				oldValue = new Number($("#map_zoomSlider").slider("value"));
				newValue = oldValue + zoomOffset;
				$("#map_zoomSlider").slider("value", (new Number($("#map_zoomSlider").slider("value")) + zoomOffset));
			} else if(curTypeMaxRes < newTypeMaxRes) {
				zoomOffset = newTypeMaxRes - curTypeMaxRes;
				oldValue = new Number($("#map_zoomSlider").slider("value"));
				newValue = oldValue - zoomOffset;
				$("#map_zoomSlider").slider("value", (new Number($("#map_zoomSlider").slider("value")) - zoomOffset));
			}
			
			mapRef.setMapType(newMapType);
			mapRef.setZoom(zoom);
		};
		
		RPMMapTools.prototype.setDirBtnStyles_ = function(button) {
			button.style.position = "absolute";
			button.style.width = "20px";
			button.style.height = "20px";
		};
		
		RPMMapTools.prototype.setSliderZoom = function(mapRef) {
			var sliderValue = new Number($("#map_zoomSlider").slider("value"));
			var minRes = mapRef.getCurrentMapType().getMaximumResolution() - self.config.map.zoomSliderMax;
			mapRef.setZoom(minRes + sliderValue);
		};
		
		/**
		*	Controller for MLS Search List View
		*   neCoords: self.config.map.getNortheastBounds()
		*   swCoords: self.config.map.getSouthwestBounds()
		*/
		function MLSSearchListSummary(neCoords, swCoords, page, sortOrder, firstLoad) {
			this.neCoords = neCoords;
			this.swCoords = swCoords;
			this.page = page;
			this.sortOrder = sortOrder;
			this.getMLSSearchListSummariesView(this.neCoords, this.swCoords, this.page, this.sortOrder, true, firstLoad);
		}
		
		/**
		* Loads the listing view as well as results for the listing view
		*/
		MLSSearchListSummary.prototype.getMLSSearchListSummariesView = function(neCoords, swCoords, page, sortOrder, initLoad, firstLoad) {
			//TODO: Show Loading Message
			var myself = this;
			this.neCoords = neCoords;
			this.swCoords = swCoords;
			this.page = page;
			this.sortOrder = sortOrder;
			
			if(!initLoad){
				$("#listingsPanelLoadingOverlay").block({message: "<div style='font-size:2em;font-weight:bold;'>Loading...</div><img src='t/resources/rpm3.0/images/search_engine/map-ajax-loader.gif' />"});
			}
			
			if(firstLoad){
				$("#searchEngineRightColumn").block({message: "<div style='font-size:2em;font-weight:bold;'>Loading...</div><img src='t/resources/rpm3.0/images/search_engine/map-ajax-loader.gif' />"});
			}
			
			// fetch the listing/areaID data from the server
			if(self.searchAjaxActivity != null)
				self.searchAjaxActivity.abort();
				
			self.searchAjaxActivity = $.ajax({
				type: "GET",
				url: self.config.absUrl,
				data: "pathway=5&list=1&envPropType="+self.config.mlsSearchType+"&"+$.generateSerializedRPMFields(self.config.searchFields)+"&startNumber="+page+"&latitude="+swCoords.lat()+"&latitude="+neCoords.lat()+"&longitude="+swCoords.lng()+"&longitude="+neCoords.lng()+"&listingsSort="+sortOrder+"&searchViewType="+self.config.currentSearchView+"&zoomLevel="+self.config.map.getZoom(),
				dataType: "html",
				async: true,
				error: function(data, error){
					alert("Error: getMLSSearchListSummariesView(): " + error + " " + data);
				},
				success: function(data){
					$("#listingsPanelModule").html(data);
				},
				complete: function(xmlhttprequest, successtype){
					if(!initLoad){
						$("#listingsPanelLoadingOverlay").unblock();
					}
					
					if(firstLoad){
						$("#searchEngineRightColumn").unblock();
					}
					
					$(function(){
						$("#searchEngineMapContainer > div").css("display", "none");
						$("#listingsPanel").css("display", "inline");
						$("#listingView").html(listTabLabel);
						myself.setSortingEvent();
					});
					self.searchAjaxActivity = null;
				}
			});
		};
		
		MLSSearchListSummary.prototype.setSortingEvent = function(){
			$("#listingsSort").unbind("change").bind("change", function(){
				$.mLSSearchEngineRunSearch();
			});
		};
		
			/**
	 * Exposes the run search method
	 *
	 * @param sNumber optional starting number
	 * @param incremental boolean indicating whether this is just an incremental search or not
	 */
	$.mLSSearchEngineRunSearch = function(sNumber, incremental){
		if(!this.config.disableMapMoveEvent){
			//alert("Running Search"); //daebug
			
			if(this.config.map.removeAreaLabel && this.config.map.areaLabel != null){
				this.config.map.areaLabel.removeLabel();
				this.config.map.areaLabel = null;
				$("#q").val("");
			}else if(!this.config.map.removeAreaLabel){
				this.config.map.removeAreaLabel = true;
			}
			
			if(sNumber == null){
				sNumber = this.config.currentPage;
			}else{
				this.config.currentPage = sNumber;
			}
			if(this.config.currentSearchView == this.config.searchViews.list){
				this.config.refactorMap = true;
				this.config.currentListingsSort = parseInt($("#listingsSort").val(), 10);
				$("#mapListingsSort").val(this.config.currentListingsSort);
				if(this.config.map.mlsSearchListSummary == null){  //First Load into List View
					$("#searchEngineViews li").removeClass("select");
					$("#listingView").html(loadingLabel);
					$("#listingView").parent("li").addClass("select");
					this.config.map.mlsSearchListSummary = new MLSSearchListSummary(this.config.currentNEBounds, this.config.currentSWBounds, this.config.currentPage, this.config.currentListingsSort, true);
				}else{
					this.config.map.mlsSearchListSummary.getMLSSearchListSummariesView(this.config.currentNEBounds, this.config.currentSWBounds, sNumber, this.config.currentListingsSort, false, false);
				}
			}else if(this.config.currentSearchView == this.config.searchViews.stats){
				this.config.refactorMap = true;
				$.mlsSearchEngineMarketStats(false);
			}else{
				if(typeof this.config != "undefined"){
					this.config.mLSSearchEngineRunSearch(sNumber, incremental);
				}
			}
		}else{
			//alert("Not Running Search"); //daebug
		}
		return false;
	};
			
		/** Map
		  *
		  * @param centerCoords center coordinates for the map
		  * @param minZoom the minimum zoom for the map
		  * @param maxZoom the maximum zoom for the map
		  * @param maxResults the maximum for the map
		  * @param zoomLevel the starting zoom level for the map
		  * @param absUrl the update url for the map
		  */
		function Map(centerCoords, minZoom, maxZoom, maxResults, zoomLevel, absUrl, mapDiv, listingIcons) {
			var opts = this;
			// set the map parameters
			this.maxZoom = maxZoom;
			this.minZoom = minZoom;
			this.maxResults = maxResults;
			this.zoomLevel = zoomLevel;
			this.absoluteUrl = absUrl;
			this.northEastBounds = null;
			this.southWestBounds = null;
			this.mapDiv = mapDiv;
			this.loadingMessage = null;
			this.currentListings = null;
			this.currentClusters = null;
			this.listingIcons = listingIcons;
			this.savedPosition = false;
			this.openInfoWindowAgain = false;
			this.markerArray = null;
			this.clusterSensitivity = 0;
			this.autoComplete = null;
			this.rpmMapTools = null;
			this.pageMultiple = 7;
			this.mlsSearchListSummary = null;
			this.areaLabel = null;
			this.removeAreaLabel = true;
			this.zoomSliderMin = 0;
			this.zoomSliderMax = 7;
			
			// intialize and center the map
			this.map = new GMap2(document.getElementById(this.mapDiv));
			this.setCenter(centerCoords, this.zoomLevel);
			
			G_NORMAL_MAP.getMinimumResolution = function(){return new Number(minZoom)};
			G_SATELLITE_MAP.getMinimumResolution = function(){return new Number(minZoom)};
			G_HYBRID_MAP.getMinimumResolution = function(){return new Number(minZoom)};
			G_PHYSICAL_MAP.getMinimumResolution = function(){return new Number(minZoom - 2)};
			
			G_NORMAL_MAP.getMaximumResolution = function(){return new Number(maxZoom)};
			G_SATELLITE_MAP.getMaximumResolution = function(){return new Number(maxZoom)};
			G_HYBRID_MAP.getMaximumResolution = function(){return new Number(maxZoom)};
			G_PHYSICAL_MAP.getMaximumResolution = function(){return new Number(maxZoom - 2)};
			
			var toolsOverlay = new GScreenOverlay("/t/resources/rpm3.0/images/search_engine/mapToolsBG.png", new GScreenPoint(0, -599, "pixels", "pixels"), new GScreenPoint(0, -599, "pixels", "pixels"), new GScreenSize(692, 93, "pixels", "pixels"));
			this.map.addOverlay(toolsOverlay);
			this.rpmMapTools = new RPMMapTools(centerCoords, this.zoomLevel);
			this.map.addControl(this.rpmMapTools);
			
			// TODO: calculate initial slider handle position
			var initHandlePos = new Number(this.zoomLevel) - (this.map.getCurrentMapType().getMaximumResolution() - this.zoomSliderMax);
			
			$(function(){
				//for some reason, using variables (this.zoomSliderMin, this.zoomSliderMax) for the min/max values forces it to use the defaults instead (0, 100)
				$("#map_zoomSlider").slider({
					//step: 1,
					min: 0,
					max: 7,
					value: initHandlePos,
					orientation: "horizontal",
					change: function(event, ui) {
						//Potential bug here:
						//When a programmatic event calls, the event object is missing the event.originalEvent
						//property which screws up when looking for event.originalEvent.type.
						try {
							if(event.originalEvent.type == "mouseup" || event.originalEvent.type == "keyup"){
								opts.rpmMapTools.setSliderZoom(opts.map);
							}
						} catch(ex) {
							//it's a programmatic call, do nothing
						}
					}
				});
			});
			
			// setup tabs
			$("#mapView").click(function(){
				if(self.config.currentSearchView != self.config.searchViews.map){
					self.config.currentSearchView = self.config.searchViews.map;
					$("#mapListingsSort").show(); //for IE6
					$("#mapType").show(); //for IE6
					$("#searchEngineViews li").removeClass("select");
					$("#mapView").parent("li").addClass("select");
					$(function(){
						$("#searchEngineMapContainer > div").css("display", "none");
						$("#searchEngineMapPanelLoadingOverlay").css("display", "inline");
						//$("#searchEngineMapPanelLoadingOverlay").block({message:"<div style='font-size:2em;font-weight:bold;'>Loading...</div><img src='t/resources/rpm3.0/images/search_engine/map-ajax-loader.gif' />"});
						
						opts.map.checkResize();
						//$("#searchEngineMapPanelLoadingOverlay").unblock();
						if(self.config.refactorMap == true){
							self.config.refactorMap = false;
							$.mLSSearchEngineRunSearch(self.config.currentPage, false);
						}
						$("#listingsPanelModule").html("");
						$("#statisticsPanelModule").html("");
					});
				}
			});
			
			$("#listingView").click(function(){
				if(self.config.currentSearchView != self.config.searchViews.list && self.mapLoaded){
					$("#searchEngineViews li").removeClass("select");
					$("#listingView").html(loadingLabel);
					$("#listingView").parent("li").addClass("select");
					
					self.config.currentSearchView = self.config.searchViews.list;
					
					if($.browser.msie && $.browser.version == "6.0"){
						$("#mapListingsSort").hide(); //for IE6
						$("#mapType").hide(); //for IE6
					}
					
					$(function(){
						if(opts.mlsSearchListSummary == null){
							opts.mlsSearchListSummary = new MLSSearchListSummary(self.config.currentNEBounds, self.config.currentSWBounds, self.config.currentPage, self.config.currentListingsSort, false);
						}else{
							opts.mlsSearchListSummary.getMLSSearchListSummariesView(self.config.currentNEBounds, self.config.currentSWBounds, self.config.currentPage, self.config.currentListingsSort, false, false);
						}
						$("#statisticsPanelModule").html("");
					});
				}
			});
			
			if($('#searchTypes').val() != searchType_commercialSale && $('#searchTypes').val() != searchType_commercialLease){
				this.setStatsViewEvent();
			}
			
			// setup tooltip
			this.tooltip=document.createElement("div");
			this.map.getPane(G_MAP_FLOAT_PANE).appendChild(this.tooltip);
			this.tooltip.style.visibility="hidden";
			
			// setup highlighting
			this.highlight=document.createElement("div");
			this.map.getPane(G_MAP_MARKER_SHADOW_PANE).appendChild(this.highlight);
			this.highlight.style.visibility="hidden";
			this.highlight.innerHTML = $.rpmImageSafe("glow","/t/resources/rpm3.0/images/icons/searchEngine/glow.png",60,60," "," ", self.config.browser);

			// setup loading message
			$('<span id="loadingMessage">Searching Listings...</span>').appendTo('#searchEngineMapPanel');
			this.loadingMessage = $('#loadingMessage');
		}
		
		Map.prototype.setStatsViewEvent = function(){
			$("#statsView").click(function(){
				if(($('#searchTypes').val() != searchType_commercialSale && $('#searchTypes').val() != searchType_commercialLease) && self.config.currentSearchView != self.config.searchViews.stats && self.mapLoaded){
					$(function(){
						$.mlsSearchEngineMarketStats(true);
					});
				}
			});
		};

		/** returns the map container
		  *
		  * @param mType the map type
		  */
		Map.prototype.setMapType = function(mType){
			return this.map.setMapType(mType);
		};

		/** returns the map container
		  *
		  */
		Map.prototype.getContainer = function(){
			return this.map.getContainer();
		};

		/** Shows the listing paging navigator on the map and displays a listing summary
		  *
		  * @param lowerLimit
		  * @param upperLimit
		  * @param totalResults
		  * @param maxResults
		  */
		Map.prototype.addListingNavTools = function(lowerLimit, upperLimit, totalResults, maxResults, startNumber){
			// create the navigation section of the Map Tools
			//daebug
			/*
			alert("Lower Limit: " + lowerLimit +
			"\nUpper Limit: " + upperLimit + 
			"\nTotal Results: " + totalResults +
			"\nMax Results: " + maxResults + 
			"\nStart Number: " + startNumber);
			*/
			
			var listCountSummary;
			var totalPages;
			var totalPagesOutput;
			var pageNumbers = "";
			var pageNumberStart;
			var pageNumberEnd;
			var currentPage = 0;
			var prevChunk;
			var nextChunk;
			var prevResults;
			var nextResults;
			
			if(totalResults == 0){
				listCountSummary = "No Listings Found";
				$("#listPaging").css("display", "none");
				this.rpmMapTools.disablePrevPaging();
				this.rpmMapTools.disableNextPaging();
			}else{
				if(totalResults <= maxResults){
					totalPages = 1;
					totalPagesOutput = "1 page";
				}else if(totalResults % maxResults == 0){
					totalPages = (totalResults / maxResults);
					totalPagesOutput = totalPages + " pages";
				}else{
					totalPages = parseInt((totalResults / maxResults) + 1, 10);
					totalPagesOutput = totalPages + " pages";
				}
				listCountSummary = "Showing " + (lowerLimit+1) + " to " + upperLimit + " of " + totalResults + " properties (" + totalPagesOutput + ")";
				if(startNumber == 0){
					currentPage = 1;
				}else{
					currentPage = (startNumber/maxResults) + 1;
				}
				
				if(totalPages == 1) {
					pageNumbers = "<div style='display:inline;cursor:pointer;font-weight:bold;'>1</div>";
				}else if(totalPages <= this.pageMultiple){
					for(var i=0;i<totalPages;i++){
						if((i+1) == currentPage){
							pageNumbers += "<div style='display:inline;cursor:pointer;font-weight:bold;'>" + (i + 1) + "</div>";
						}else{
							pageNumbers += "<div style='display:inline;cursor:pointer;font-weight:normal;' onclick='$.mLSSearchEngineRunSearch(" + i * maxResults + ", true)'>" + (i + 1) + "</div>";
						}
						
						if(i != totalPages - 1){
							pageNumbers += " - ";
						}
					}
				}else{					
					if((totalPages - currentPage) < parseInt(this.pageMultiple / 2, 10)){
						pageNumberStart = (totalPages - this.pageMultiple) + 1;
					}else if((currentPage - parseInt(this.pageMultiple / 2, 10)) > 0){
						pageNumberStart = currentPage - parseInt(this.pageMultiple / 2, 10);
					}else{
						pageNumberStart = 1;
					}
					
					if(currentPage <= parseInt(this.pageMultiple / 2, 10)){
						pageNumberEnd = this.pageMultiple;
					}else if((currentPage + parseInt(this.pageMultiple / 2, 10)) > totalPages){
						pageNumberEnd = totalPages;
					}else{
						pageNumberEnd = currentPage + parseInt(this.pageMultiple / 2, 10);
					}
					
					for(var i=pageNumberStart;i<=pageNumberEnd;i++){
						if(i == currentPage){
							pageNumbers += "<div style='display:inline;cursor:pointer;font-weight:bold;'>" + i + "</div>";
						}else{
							pageNumbers += "<div style='display:inline;cursor:pointer;font-weight:normal;' onclick='$.mLSSearchEngineRunSearch(" + (i - 1) * maxResults + ", true)'>" + i + "</div>";
						}
						
						if(i != pageNumberEnd){
							pageNumbers += " - ";
						}
						
					}
				}
				
				$("#paging_list").html(pageNumbers);
				
				prevResults = startNumber - maxResults;
				nextResults = startNumber + maxResults;
				
/*
				//For paging by multiples of the value stored in this.pageMultiple
				prevChunk = (maxResults * (currentPage - 1)) - (this.pageMultiple * maxResults);
				nextChunk = (this.pageMultiple * maxResults) + (maxResults * (currentPage - 1));
				
				if(prevChunk < 0){
					prevChunk = 0;
				}
				if(nextChunk > (totalPages - 1) * maxResults){
					nextChunk = (totalPages - 1) * maxResults;
				}
*/
				
				prevChunk = 0;
				nextChunk = (totalPages - 1) * maxResults;
				
				if(totalPages == 1){
					this.rpmMapTools.disablePrevPaging();
					this.rpmMapTools.disableNextPaging();
				}else if(lowerLimit == 0){
					this.rpmMapTools.disablePrevPaging();
					this.rpmMapTools.enableNextPaging(nextResults, nextChunk);
				}else if(upperLimit == totalResults){
					this.rpmMapTools.enablePrevPaging(prevResults, prevChunk);
					this.rpmMapTools.disableNextPaging();
				}else{
					this.rpmMapTools.enablePrevPaging(prevResults, prevChunk);
					this.rpmMapTools.enableNextPaging(nextResults, nextChunk);
				}
				
				$("#listPaging").css("display", "inline");
			}
			
			$('#listCountSummary').html(listCountSummary);
		};

		/** shows the listing navigator on the map
		  *
		  */
		Map.prototype.setSavedPosition = function(){
			if(!this.savedPosition){
				this.map.savePosition();
				this.savedPosition = true;
			}else{
				this.openInfoWindowAgain = true;
			}
		};

		/** returns the map to the saved position
		  *
		  */
		Map.prototype.returnToSavedPosition = function(){
			if(!this.openInfoWindowAgain){
				this.savedPosition = false;
				this.map.returnToSavedPosition();
			}
		};

		/** adds a control to the map
		  *
		  * @param control to add to the map
		  */
		Map.prototype.addControl = function(control){
			this.map.addControl(control);
		};

		/** returns the current zoom level of the map
		  *
		  * @return zoom level of map
		  */
		Map.prototype.getZoom = function(){
			return this.map.getZoom();
		};

		Map.prototype.setZoom = function(zoomValue){
			this.map.setZoom(zoomValue);
		};
	
		/** centers the map on given coordinates and zoom level
		  *
		  * @param centerCoords coordinates to center the map at
		  * @param zoomLevel zoom level to start the map at
		  */
		Map.prototype.setCenter = function(centerCoords, zoomLevel){
			this.map.setCenter(centerCoords, zoomLevel);
		};
	
		/** gets the current center of the map
		  *
		  * @return coordinates indicating the center of the map
		  */
		Map.prototype.getCenter = function(){
			return this.map.getCenter();
		};
	
		/** Returns the NorthEast bounds of this map
		  * Compensate for markers and map tools overlay
		  * @return Northeast bounds
		  */
		Map.prototype.getNortheastBounds = function(){
			//TODO: Compensate for map tools at top...
			//Tools Overlay Width/Height: 692/93
			//Map Marker Width/Height: 18/29
			
			return this.map.fromContainerPixelToLatLng(new GPoint(683, 150)); //683, 130
			//return this.map.getBounds().getNorthEast();
		};

		/** Returns the Southwest bounds of this map
		  * Compensate for markers 
		  * @return Southwest bounds
		  */
		Map.prototype.getSouthwestBounds = function(){
			var SWCoordsLatLng = this.map.fromLatLngToContainerPixel(this.map.getBounds().getSouthWest());
			SWCoordsLatLng.x = 9;
			return this.map.fromContainerPixelToLatLng(SWCoordsLatLng);
			//return this.map.getBounds().getSouthWest();
		};

		/** returns the actual GMap2 object
		  *
		  * @return GMap2 object
		  */
		Map.prototype.getMap = function(){
			return this.map;
		};

		/** removes an overlay from the map
		  *
		  * @param overlay
		  */
		Map.prototype.removeOverlay = function(overlay){
			this.map.removeOverlay(overlay);
		};

		/** adds an overlay to the map
		  *
		  * @param overlay
		  */
		Map.prototype.addOverlay = function(overlay){
			this.map.addOverlay(overlay);
		};
		
		/** shows the loading message
		  *
		  */
		Map.prototype.showLoadingMessage = function(){
			// show the loading message
			this.loadingMessage.show();
		};

		/** hides the loading message
		  *
		  */
		Map.prototype.hideLoadingMessage = function(){
			this.loadingMessage.hide();
		};
		
		Map.prototype.getMarkerBounds = function(lat, lng){	
			var tempMarker = new GMarker(new GLatLng(lat, lng), self.config.map.listingIcons[0]);
			var width = tempMarker.getIcon().iconSize.width;
			var height = tempMarker.getIcon().iconSize.height;
			var point = self.config.map.getMap().getCurrentMapType().getProjection().fromLatLngToPixel(tempMarker.getLatLng(), self.config.map.getMap().getZoom());
			var offset = tempMarker.getIcon().iconAnchor;
			var NE_x = parseFloat(point.x - offset.x + width + self.config.map.clusterSensitivity);
			var NE_y = parseFloat(point.y - offset.y - self.config.map.clusterSensitivity);
			var SW_x = parseFloat(point.x - offset.x - self.config.map.clusterSensitivity);
			var SW_y = parseFloat(point.y - offset.y + height + self.config.map.clusterSensitivity);
			var listingNE = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(NE_x, NE_y), self.config.map.getMap().getZoom());
			var listingSW = self.config.map.getMap().getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(SW_x, SW_y), self.config.map.getMap().getZoom());
			var listingBounds = new GLatLngBounds(listingSW, listingNE);
			tempMarker = null;
			
			return listingBounds;
		};
		
		Map.prototype.addListings = function(data){
			var listnum, cluster, removeList = [], tempListings = new Hashtable(), newListings = new Hashtable(), invalidListings = [], newListing, existingListings = new Hashtable();
			var debug = false;
			if(this.currentListings == null)
				this.currentListings = new Hashtable();
			if(this.currentClusters == null)
				this.currentClusters = [];
				
			this.listings = new Array(data.listings.length); //wtf is this
			
			//Get New List of Listings and List of Existing Listings
			for(var x=0;x<data.listings.length;x++){
				listnum = data.listings[x].listingNumber;
				if(this.currentListings.get(listnum) == null){
					newListing = new Listing(data.listings[x].listingNumber, data.listings[x].mlsNumber, data.listings[x].propType, data.listings[x].latitude, data.listings[x].longitude, data.listings[x].statusDisplay, data.listings[x].markerColor, data.listings[x].propAddr, data.listings[x].sqft, data.listings[x].bdrms, data.listings[x].baths, data.listings[x].listPriceShort);
					tempListings.put(listnum, newListing);
					newListings.put(listnum, newListing);
				}else{
					tempListings.put(listnum, this.currentListings.get(listnum));
					existingListings.put(listnum, this.currentListings.get(listnum));
				}
			}
			
			//Remove existing iistings from existingListings if they already reside in a cluster
			invalidListings = [];
			for(var x=0;x<this.currentClusters.length;x++){
				existingListings.moveFirst();
				while(existingListings.next()){
					if(this.currentClusters[x].listingExists(existingListings.getKey())){
						invalidListings.push(existingListings.getKey());
					}
				}
			}
			
			for(var x=0;x<invalidListings.length;x++){
				existingListings.remove(invalidListings[x]);
			}
				
			//Get List Of Current Listings to be deleted
			this.currentListings.moveFirst();
			while(this.currentListings.next()){
				listnum = this.currentListings.getValue().listnum;
				if(tempListings.get(listnum) == null){
					removeList.push(listnum);
					this.currentListings.get(listnum).removeFromMap();
				}
			}
			
			//Check each ListingCluster:
			for(var x=0;x<this.currentClusters.length;x++){
				cluster = this.currentClusters[x];
				//- Remove non-present Listings from cluster
				for(var y=0;y<removeList.length;y++){
					if(cluster.listingExists(removeList[y])){
						cluster.removeListing(removeList[y]);
					}
				}
				//- Destroy clusters with less than two listings and add listing to existing listings queue for rendering if available
				if(cluster.size() < 2){
					cluster.destroyMarker();
					this.currentClusters.splice(x, 1);
					x--;
				}else{
					this.currentClusters[x] = cluster;
				}
			}
			
			//- refactor listings in each cluster, place invalid listings in newListings
			// TODO: Remove existing listings in each cluster from existingListings()
			var clusteredListings, clusterBounds, refactored = false;
			for(var x=0;x<this.currentClusters.length;x++){
				clusteredListings = [];
				invalidListings = [];
				var cluster = this.currentClusters[x];
				cluster.listings.moveFirst();
				while(cluster.listings.next()){
					if(cluster.listings.getValue() != null){
						clusteredListings.push(cluster.listings.getValue());
					}
				}
				
				if(clusteredListings.length >= 2){
					refactored = false;
					clusterBounds = clusteredListings[0].getBounds();
					for(var y=clusteredListings.length - 1;y>0;y--){
						if(clusteredListings[y].getBounds().intersects(clusterBounds)){
							clusterBounds.extend(new GLatLng(clusteredListings[y].lat, clusteredListings[y].lng));
							var newCenter = clusterBounds.getCenter();
							clusterBounds = this.getMarkerBounds(newCenter.lat(), newCenter.lng());
						}else{
							if(debug){
								alert("Found Invalid Listing in Cluster: " + clusteredListings[y].mlsnum);
							}
							invalidListings.push(clusteredListings[y].listnum);
							refactored = true;
						}
					}
					
					for(var z=0;z<invalidListings.length;z++){
						var temp = this.currentClusters[x].listings.get(invalidListings[z]); 
						if(temp.getBounds().intersects(clusterBounds)){
							clusterBounds.extend(new GLatLng(clusteredListings[y].lat, clusteredListings[y].lng));
							var newCenter = clusterBounds.getCenter();
							clusterBounds = this.getMarkerBounds(newCenter.lat(), newCenter.lng());
							invalidListings.splice(z, 1);
							z--;
						}
					}
					
					if(invalidListings.length == 0){
						refactored = false;
					}
					
					if(refactored){
						cluster.refactored = true;
						for(var y=0;y<invalidListings.length;y++){
							if(cluster.listings.get(invalidListings[y]) != null){
								existingListings.put(this.currentClusters[x].listings.get(invalidListings[y]).listnum, this.currentClusters[x].listings.get(invalidListings[y]));
								cluster.listings.remove(invalidListings[y]);
							}
						}
						this.currentClusters[x] = cluster;
					}
					
					for(var z=0;z<invalidListings.length;z++){
						if(debug){
							if(cluster.listings.get(invalidListings[z]) != null){
								alert("Listing " + invalidListings[z] + " still present!!!");
							}
						}
						removeList.push(invalidListings[z]);
						newListings.remove(invalidListings[z]);
					}
				}
				
				
				// remove ListingCluster if there are < 2 listings remaining in the ListingCluster
				if(this.currentClusters[x].size() < 2){
					this.currentClusters[x].listings.moveFirst();
					while(this.currentClusters[x].listings.next()){
						existingListings.put(this.currentClusters[x].listings.getValue().listnum, this.currentClusters[x].listings.getValue());
					}
					this.currentClusters[x].destroyMarker();
					this.currentClusters.splice(x, 1);
					x--;
				}
			}
			
			// refactor the clusters themselves
			for(var x=0;x<this.currentClusters.length;x++){
				cluster = this.currentClusters[x];
				for(var y=this.currentClusters.length-1;y>x;y--){
					var otherCluster = this.currentClusters[y];
					if(cluster.getMarkerBounds().intersects(otherCluster.getMarkerBounds())){
						var otherClusterListings = otherCluster.listings;
						otherClusterListings.moveFirst();
						while(otherClusterListings.next()){
							if(cluster.listings.get(otherClusterListings.getKey()) != null){
								otherClusterListings.remove(otherClusterListings.getKey());
							}
						}
						if(otherClusterListings.size() > 0){
							cluster.listings.add(otherClusterListings);
						}
						otherCluster.destroyMarker();
						this.currentClusters.splice(y, 1);
						if(y < this.currentClusters.length-1){
							y++;
						}
					}
				}
			}
			
			// add listings to existing clusters if applicable
			var unclusteredListings = newListings.add(existingListings);
			invalidListings = [];
			unclusteredListings.moveFirst();
			var count = 0;
			while(unclusteredListings.next()){
				var newListing = unclusteredListings.getValue();
				for(var y=0;y<this.currentClusters.length;y++){
					if(!this.currentClusters[y].listingExists(newListing.listnum)){
						this.currentClusters[y].setNewMarkerBounds();
						if(newListing.getBounds().intersects(this.currentClusters[y].newBounds)){
							this.currentClusters[y].addListing(newListing.listnum, newListing);
							this.currentClusters[y].setNewMarkerBounds();
							invalidListings.push(newListing.listnum);
							break;
						}
					}else{
						invalidListings.push(newListing.listnum);
						count++;
					}
				}
			}
			
			if(debug){
				if(count > 0)
					alert("Listings already found in cluster: " + count);
			}
			
			for(var x=0;x<invalidListings.length;x++){
				if(newListings.get(invalidListings[x]) != null){
					newListings.remove(invalidListings[x]); //Remove new listings that have now become clustered
				}
				
				if(existingListings.get(invalidListings[x]) != null){
					existingListings.remove(invalidListings[x]); //Remove existing listings that have now become clustered
				}
				removeList.push(invalidListings[x]); //Also remove single listings that are currently overlaid on map
			}
			
			// create new ListingClusters if applicable
			//TODO: refactor existing non-clustered markers (existingListings) - use tempListings instead?
			var newClusters = [];
			var clustered = false;
			invalidListings = [];
			unclusteredListings = newListings.add(existingListings);
			var unclusteredListingsArray = [];
			for(i in unclusteredListings.hash){
				if(unclusteredListings.hash[i] != null){
					unclusteredListingsArray.push(unclusteredListings.hash[i]);
				}
			}
			/*
			var msg = "New Listings: " + newListings.size() +
			          "\nExisting Listings: " + existingListings.size() +
					  "\nTotal Unclustered Listings: " + unclusteredListingsArray.length;
			alert(msg);
			*/
			var limit = unclusteredListingsArray.length;
			var count = 0;
			for(var i=0;i<limit;i++){
				clustered = false;
				var newListing = unclusteredListingsArray[i];
				if(newClusters.length > 0){
					for(var j=0;j<newClusters.length;j++){
						if(newClusters[j].getMarkerBounds().intersects(newListing.getBounds())) {
							newClusters[j].addListing(newListing.listnum, newListing);
							newClusters[j].setMarkerBounds();
							unclusteredListingsArray.splice(i, 1);
							invalidListings.push(newListing.listnum);
							clustered = true;
							i--;
							limit--;
							break;
						}
					}
				}
				if(!clustered){
					var newListingsCluster = new Hashtable();
					var listingBounds = newListing.getBounds();
					for(var k=i+1;k<unclusteredListingsArray.length;k++){
						if(unclusteredListingsArray[k].getBounds().intersects(listingBounds)) {
							//listingBounds.extend(new GLatLng(unclusteredListingsArray[k].lat, unclusteredListingsArray[k].lng));
							newListingsCluster.put(unclusteredListingsArray[k].listnum, unclusteredListingsArray[k]);
							invalidListings.push(unclusteredListingsArray[k].listnum);
							unclusteredListingsArray.splice(k, 1);
							limit--;
							k--;
						}
					}
					if(newListingsCluster.size() > 0){
						newListingsCluster.put(newListing.listnum, newListing);
						invalidListings.push(newListing.listnum);
						unclusteredListingsArray.splice(i, 1);
						i--;
						limit--;
						var newCluster = new ListingCluster(newListingsCluster);
						newCluster.setMarkerBounds();
						newClusters.push(newCluster);
					}
				}
				/*
				var msg = "Loop Iteration: " + count + "\n" + 
				          "Count(i): " + i + "\n" + 
						  "Limit: " + limit + "\n" + 
						  "Number of Listings: " + unclusteredListingsArray.length + "\n" + 
						  "Number of Clusters: " + newClusters.length;
				alert(msg);
				count++;
				*/
			}
			
			for(var x=0;x<invalidListings.length;x++){
				if(newListings.get(invalidListings[x]) != null){
					newListings.remove(invalidListings[x]); //Remove new listings that have now become clustered
				}
				
				if(existingListings.get(invalidListings[x]) != null){
					removeList.push(invalidListings[x]); //Remove existing listings that have now become clustered
				}
			}
			
			// render markers
			if(debug){
				alert("Total:\nNumber of New Listings: " + newListings.size() + 
				"\nNumber of Listings in TempListings: " + tempListings.size() +
				"\nNumber of Existing Clusters: " + this.currentClusters.length +
				"\nNumber of New Clusters: " + newClusters.length);
			}
			
			for(var x=0;x<removeList.length;x++){
				if(this.currentListings.get(removeList[x]) != null){ 
					this.currentListings.get(removeList[x]).removeFromMap();
				}
			}
			
			var nullListings = [];
			
			newListings.moveFirst();
			while(newListings.next()){
				if(newListings.getValue() != null){
					tempListings.get(newListings.getValue().listnum).addToMap(self.config.listingIcons);
				}else{
					if(debug){
						nullListings.push(newListings.getKey());
					}
				}
			}
			
			for(var x=0;x<newClusters.length;x++){
				newClusters[x].initializeMarker();
			}
			
			for(var x=0;x<this.currentClusters.length;x++){
				this.currentClusters[x].resetMarkerPosition();
			}
			
			this.currentListings = tempListings;
			this.currentClusters = this.currentClusters.concat(newClusters);
			
			if(debug){
				var msg = "";
				for(var i=0;i<nullListings.length;i++){
					var found = false;
					msg += nullListings[i] + " - ";
					for(var j=0;j<this.currentClusters.length;j++){
						if(this.currentClusters[j].listingExists(nullListings[i])){
							found = true;
						}
					}
					if(found){
						msg += "found in cluster\n";
					}else{
						msg += "not found in cluster\n";
					}
				}
				if(msg != "")
					alert(msg);
			}
			
			// calculate the number of data chunks this result set needs to be broken into {REVIEW THIS...}
			var num = Math.round(data.totalResults/data.maxResults + 0.4);
			
			// if the result is '0' then increase the result counter by 1
			// we need to do this if we have fewer than 10% of data.maxResults
			if(num == 0){
				num = 1;
			}else if(data.totalResults % data.maxResults != 0){
				num += 1;
			}
			
			var lowerLimit;
			var upperLimit;
			var debugStop = false;
			
			if(data.totalResults == 0){
				self.config.map.addListingNavTools(-1, -1, data.totalResults, data.maxResults, data.startNumber);
			}else{
				//alert("Num: " + num + " - Looping for shit..."); //daebug
				for(i = 0; i < num; i++){
					lowerLimit = i*data.maxResults;
					upperLimit = (i+1)*data.maxResults;
					if(upperLimit > data.totalResults){
						upperLimit = data.totalResults;
					}
		
					//daebug
					/*
					if(!debugStop){
						if(!confirm("Data Start Number: " + data.startNumber + "\nLower Limit: " + lowerLimit)){
							debugStop = true;
						}
					}
					*/
					
					if(data.startNumber == lowerLimit){ 
						//alert("Setting paging info..."); //daebug
						self.config.map.addListingNavTools(lowerLimit, upperLimit, data.totalResults, data.maxResults, data.startNumber);
					}
				}
				//alert("Done Looping."); //daebug
			}
			
		};
	
		/** removes all overlays from the map
		  *
		  */
		Map.prototype.clearOverlays = function(){
			this.currentListings = null;
			this.currentClusters = null; //Wasn't here b4...
			this.map.clearOverlays();
		};

		/** Modifies the map in case the container size has changed
		  *
		  */
		Map.prototype.checkResize = function(){
			this.map.checkResize()
		};

		/** changes the map into large-format, hiding the statistics panel. If the map is
		  * already in large format then no changes are made.
		  *
		  */
		Map.prototype.makeLarge = function(){
			$('#quickStats').unbind("click");
			$('#quickStats').unbind("mouseout");
			$('#quickStats').unbind("mouseover");
			$('#quickStats').hide("blind", {}, 0, function(){
				$("#mapStats_mostExp").html("<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\"  />");
				$("#mapStats_leastExp").html("<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\"  />");
				$("#mapStats_avg").html("<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\"  />");
				$("#mapStats_new").html("<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\"  />");
				$("#searchEngineMapPanel, #searchEngineMap").css('height', '749px');
				self.config.map.checkResize();
			});
		};

		/** changes the map into small-format, hiding the statistics panel. If the map is
		  * already in small format then no changes are made.
		  *
		  */
		Map.prototype.makeSmall = function(){
			$('#quickStats').show("blind", {}, 0, function(){
				$("#searchEngineMapPanel, #searchEngineMap").css('height', '707px');
				self.config.map.checkResize();
				$('#quickStats').bind("mouseover", function(){
					$('#quickStats').toggleClass("quickStats_on");
				});
				$('#quickStats').bind("mouseout", function(){
					$('#quickStats').toggleClass("quickStats_on");
				});
				$('#quickStats').bind("click", function(){
					$("#statsView").click();
				});
			});
		};
			
		/** initialize residential search
		  *
		  */
		var initSearch = function(){
			// set the save link
			$('#saveSendOptions').click(function(){
				//var startNumber = document.getElementById("searchEngineListingsResultsSelect").options[document.getElementById("searchEngineListingsResultsSelect").selectedIndex].value;
				var startNumber = 0;
				$.vIPAjax({
					type: "POST",
					url: "listings",
					beforeSend: function(){
						$('#sePanel').block({message: 'Saving... <img src="/t/resources/rpm3.0/images/activity/indicator_medium.gif" />', baseZ:100 });
					},
					data: "pathway=5&startNumber="+startNumber+"&saveSearch=true&envPropType="+self.config.mlsSearchType+"&"+$.generateSerializedRPMFields(self.config.searchFields)+"&latitude="+self.config.map.getSouthwestBounds().lat()+"&latitude="+self.config.map.getNortheastBounds().lat()+"&longitude="+self.config.map.getSouthwestBounds().lng()+"&longitude="+self.config.map.getNortheastBounds().lng()+"&zoomLevel="+self.config.map.getZoom()+"&listingsSort="+$("#mapListingsSort").val(),
					dataType: "html",
					error: function(data, error){
						alert("Error: showListingDetails(): " + error + " " + data.toString());
					},
					success: function(data){
						// load the listing overlay
						$('#saveSearchButton').hide();
						$('#savedSearchMessage').show();
					},
					complete: function(){
						setTimeout(function(){$('#sePanel').unblock();}, 500);
					},
					failComplete: function() {
						window.scrollTo(0,0);
						setTimeout(function(){$('#sePanel').unblock();}, 500);
					}
				}, function(){
					setTimeout(function(){$('#sePanel').unblock();}, 500);
				});
			});
			
			$('#saveSendOptions').mouseover(function(){
				$('#saveSendOptions').toggleClass("saveSendOptions_on");
			});
			
			$('#saveSendOptions').mouseout(function(){
				$('#saveSendOptions').toggleClass("saveSendOptions_on");
			});
			
			// grab all slider fields (if any)
			$("#searchEngineSearchOptions").find('.slider').each(function(){
				if(self.config.currentRangeType == null || self.config.currentRangeType == self.config.rangeTypes.drop){
					self.config.currentRangeType = self.config.rangeTypes.slide;
				}
				self.config.searchFields = $.addRangeField(this.id.substring(0, this.id.indexOf('_')), self.config.searchFields);
			});
			
			// grab all range drop down fields (if any)
			$("#searchEngineSearchOptions").find('.ddRange').each(function(){
				if(self.config.currentRangeType == null || self.config.currentRangeType == self.config.rangeTypes.slide){
					self.config.currentRangeType = self.config.rangeTypes.drop;
				}
				self.config.searchFields = $.addDDRangeField(this.id, self.config.searchFields);
			});
			
			// grab all the date time fields.
			$('.datetime_range').each(function(){
				self.config.searchFields = $.addDateTimeRangeField(this.id.substring(0, this.id.indexOf('_')), self.config.searchFields);
			});

			// grab all treeview fields
			$('.treeView').each(function(){
				var fieldId = this.id.substring(0, this.id.indexOf('_'));
				var leaves = new Array();
				$(this).children().each(function(){
					var id = $(this).children(":first").attr("id");
					leaves.push(id.substring(fieldId.length, id.length));
				});
				self.config.searchFields = $.addTreeField(fieldId, leaves, self.config.searchFields);
			});

			// grab all checkbox fields
			$('#searchEngineVIPOptions').find('input').each(function(){
				self.config.searchFields = $.addCheckboxField(this.id, self.config.searchFields);
			});

			// create the tree view component
			$("#searchEngineTree").treeview({
				animated: "fast",
				collapsed: true,
				unique: true,
				toggle: function(){}
			});
			
			// set tree view height
			setTreeViewHeight();
			
			// open the first tree
			if($("#searchEngineTree li:first").attr("class").indexOf('lastExpandable') >= 0){
				$("#searchEngineTree li:first").removeClass("expandable").addClass("collapsable");
				$("#searchEngineTree li:first").removeClass("lastExpandable").addClass("lostCollapsable");
			}else{
				$("#searchEngineTree li:first").removeClass("expandable").addClass("collapsable");
			}
			$("#searchEngineTree li:first ul").show();

			// attach events to the foreclosure/estate sale checkboxes, etc.
			$('#foreclosure, #estateSale').click(function(){
				var self = this;
			
				// make sure this feature can be accessed
				vIPAjaxRequest = $.vIPAjax({
					type: "GET",
					dataType: "html",
					url: "listings",
					data: "pathway=5&vipAccessCheck=true",
					error: function(data, error){
						alert("Error - MLSSearchEngine.js.initSearch(): " + error + " " + data);
					},
					success: function(data){
						// make sure the other isn't checked
						if(self.id == 'estateSale'){
							$('#foreclosure:checked').each(function(){
								this.checked=false;
							});
						}else{
							$('#estateSale:checked').each(function(){
								this.checked=false;
							});
						}
						
						// run search
						$.mLSSearchEngineRunSearch(); //used to call search directly
					},
					failComplete:function(){
						window.scrollTo(0,0);
					}
				}, function(){
					$('#estateSale:checked, #foreclosure:checked').each(function(){
						this.checked=false;
					});
				});
			});
			
			$("#q").autocomplete("listings", {
				delay: 400,
			    extraParams: {
					pathway: 5,
					autoComp: "true"
				},
				minChars: 2,
				cacheLength: 1
			});
			
			$("#q").blur(function(){
				$("#q").flushCache();
			});
			
			$("#mlsTextSearch_btn").click(function(){
				if($("#q").attr("value").length > 1){
					$("#mlsTextSearch_btn").blur();
					self.searchAjaxActivity = $.ajax({
						type: "GET",
						url: "listings",
						data: "pathway=5&textSearch=true&queryText="+encodeURIComponent($("#q").attr("value")),
						dataType: "json",
						beforeSend: function(){
							//$.mLSSearchEngineShowBusyOverlay('mlsSearchType');
						},
						error: function(data, error){
							setTimeout(function(){$('#searchEngineSearchOptionsLoadingOverlay').unblock();}, 1000);
							alert("Error: MLSTextSearch: " + error + " - " + data.statusText);
						},
						success: function(data){
							if(data.searchResultType == "Listing"){
								$.mLSSearchEngineShowListingDetails(data.listingNumber);
								$("#q").flushCache();
							}else if(data.searchResultType == "Map"){
								self.config.map.getMap().setCenter(new GLatLng(data.lat, data.lng), parseInt(data.zoom, 10), self.config.map.getMap().getCurrentMapType());
								self.config.currentNEBounds = self.config.map.getNortheastBounds();
								self.config.currentSWBounds = self.config.map.getSouthwestBounds();
																
								$(function(){
									$.mLSSearchEngineRunSearch();
									self.config.map.areaLabel = new AreaLabel(data.lat, data.lng, data.queryText);
								});
								$("#q").flushCache();
							}else{
								alert("No Results Found");
							}
						},
						complete: function(xmlhttprequest, successtype){
							//setTimeout(function(){$.mLSSearchEngineHideBusyOverlay("loading");}, 1000);
						}
					});
				}
			});

			//Lock out the searching if we have a date time restricion in effect.
			if($('#listDateRangeStart').val() != '' || $('#listDateRangeEnd').val() != '') {
				$.mLSSearchEngineLockListDate();
			}

		}
		
		/** trigger the search based on which property type has been selected
		  *
		  * @param mlsSearchType integer constant indicating the type of search to run
		  * @param initialLoad boolean indicating whether this is the first load or not
		  * @param callback to be run once the search is loaded
		  */
		var loadSearch = function(mlsSearchType, initialLoad){
			// clean up search - unloads/destroys any JS components used in the prior MLS search type
			self.config.searchFields = new Array();
			self.config.mlsSearchType = mlsSearchType;

			if(self.config.currentSearchView == self.config.searchViews.stats && (mlsSearchType == searchType_commercialSale || mlsSearchType == searchType_commercialLease || mlsSearchType == searchType_rental)){
				$("#mapView").click();
			}
			
			// if this isn't an initial load, get the new search criteria from the server
			if(!initialLoad){
				// fetch the listing/areaID data from the server
				if(self.searchAjaxActivity != null)
					self.searchAjaxActivity.abort();
				
				self.searchAjaxActivity = $.ajax({
					type: "GET",
					url: "listings",
					data: "pathway=5&options=true&envPropType="+mlsSearchType,
					dataType: "html",
					beforeSend: function(){
						$.mLSSearchEngineShowBusyOverlay('mlsSearchType');
					},
					error: function(data, error){
						setTimeout(function(){$('#searchEngineSearchOptionsLoadingOverlay').unblock();}, 1000);
						alert("Error: loadSearch(): " + error + " " + data);
					},
					success: function(data){
						$('#searchEngineSearchOptions').html(data);
					},
					complete: function(xmlhttprequest, successtype){
						setTimeout(function(){$.mLSSearchEngineHideBusyOverlay("loading");}, 1000);
						// initialize the search options
						initSearch();
						initSearchTypes(mlsSearchType);
						
						// run the search
						$.mLSSearchEngineRunSearch();  //used to call search directly
					}
				});
			}else{
				// initialize the search options
				initSearch();
				initSearchTypes(mlsSearchType);
				
				// run the search
				$.mLSSearchEngineRunSearch();  //used to call search directly
				
			}
			return false;
		}
		
		var setTreeViewHeight = function(){
			var leftColHt = $("#searchEngineLeftColumn").height();
			var rightColHt = $("#searchEngineRightColumn").height();
			
			if(leftColHt < rightColHt){
				var incHeight = rightColHt - leftColHt;
				var outputScrollHeight = $("#searchEngineLeftColumn .outputScroll").height() + incHeight;
				$("#searchEngineLeftColumn .outputScroll").css("height", outputScrollHeight);
			}
		}
			

		/** --------------------------------------------------
		* ----------- Loading starts here --------------
		* --------------------------------------------------
		*/
		// initialize the config object
		self.config = jQuery.extend({}, options || {});

		// run the initialization routines
		if (GBrowserIsCompatible()) {
			// create the browser object
			self.config.browser = $.browserDetectLite();

			// Create Listing Icons
			self.config.listingIcons = new Array();
			self.config.listingIcons[0] = ListingIcon("new_house.png");
			self.config.listingIcons[1] = ListingIcon("new_condo.png");
			self.config.listingIcons[2] = ListingIcon("new_land.png");
			self.config.listingIcons[3] = ListingIcon("new_comm.png");
			self.config.listingIcons[4] = ListingIcon("active_house.png");
			self.config.listingIcons[5] = ListingIcon("active_condo.png");
			self.config.listingIcons[6] = ListingIcon("active_land.png");
			self.config.listingIcons[7] = ListingIcon("active_comm.png");
			self.config.listingIcons[8] = ListingIcon("pending_house.png");
			self.config.listingIcons[9] = ListingIcon("pending_condo.png");
			self.config.listingIcons[10] = ListingIcon("pending_land.png");
			self.config.listingIcons[11] = ListingIcon("pending_comm.png");
			self.config.listingIcons[12] = ListingIcon("sold_house.png");
			self.config.listingIcons[13] = ListingIcon("sold_condo.png");
			self.config.listingIcons[14] = ListingIcon("sold_land.png");
			self.config.listingIcons[15] = ListingIcon("sold_comm.png");
			
			// Clustered Listings Icons
			self.config.listingIcons[16] = ListingIcon("new_house_m.png");
			self.config.listingIcons[17] = ListingIcon("new_condo_m.png");
			self.config.listingIcons[18] = ListingIcon("new_land_m.png");
			self.config.listingIcons[19] = ListingIcon("new_comm_m.png");
			self.config.listingIcons[20] = ListingIcon("active_house_m.png");
			self.config.listingIcons[21] = ListingIcon("active_condo_m.png");
			self.config.listingIcons[22] = ListingIcon("active_land_m.png");
			self.config.listingIcons[23] = ListingIcon("active_comm_m.png");
			self.config.listingIcons[24] = ListingIcon("pending_house_m.png");
			self.config.listingIcons[25] = ListingIcon("pending_condo_m.png");
			self.config.listingIcons[26] = ListingIcon("pending_land_m.png");
			self.config.listingIcons[27] = ListingIcon("pending_comm_m.png");
			self.config.listingIcons[28] = ListingIcon("sold_house_m.png");
			self.config.listingIcons[29] = ListingIcon("sold_condo_m.png");
			self.config.listingIcons[30] = ListingIcon("sold_land_m.png");
			self.config.listingIcons[31] = ListingIcon("sold_comm_m.png");

			// create the map object
			self.config.map = new Map(self.config.centerCoords,
			  self.config.minZoom,
			  self.config.maxZoom,
			  self.config.maxResults,
			  self.config.zoomLevel,
			  self.config.absUrl,
			  self.config.mapDiv,
			  self.config.listingIcons
			);
			
			// create global vars for the different views
			self.config.searchViews = {map:0, list:1, stats:2};
			//self.config.currentSearchView = self.config.searchViews.map;
			self.config.currentSearchView = self.config.startSearchViewType;
			self.config.rangeTypes = {slide: 0, drop: 1};
			self.config.currentRangeType = null;
			self.config.currentNEBounds = null;
			self.config.currentSWBounds = null;
			self.config.currentPage = 0;
			self.config.currentListingsSort = 0;
			self.config.refactorMap = false;
			self.config.disableMapMoveEvent = false;
			
			$(function(){  
				//NEEDED??? Is being set in mLSSearchEngineRunSearch()
				self.config.currentNEBounds = self.config.map.getNortheastBounds();
				self.config.currentSWBounds = self.config.map.getSouthwestBounds();
			});
						
			// load the data into the map
			$(window).load(function(){
				// This event fires when the map view is on listings, and when the map is
				// moved we want to display those listings that fall within the boundaries of the map.
				// This fires on map drag
				GEvent.addListener(self.config.map.getMap(), "dragend", function(){
					if(!self.config.map.savedPosition){
						self.config.map.removeAreaLabel = false;
						$.mLSSearchEngineRunSearch(); //used to call search directly
					}
				});
				
				// If the map is zoomed then reload results
			  	GEvent.addListener(self.config.map.getMap(), "zoomend", function(oldLevel, newLevel){
					$.mLSSearchEngineRunSearch(); //used to call search directly					
			  	});
			  	
				// If the map is moved then reload results
				// This fires on clicking Area Ids
				// Depricated
				/*
			  	GEvent.addListener(self.config.map.getMap(), "moveend", function(oldLevel, newLevel){
					if(self.config.areaIdentifierReload != null && self.config.areaIdentifierReload false && !self.config.map.savedPosition){
						$.mLSSearchEngineRunSearch(); //used to call search directly
						self.config.areaIdentifierReload = false;
					}
			  	});
				*/
				
				GEvent.addListener(self.config.map.getMap(), "infowindowopen", function(){
					self.config.map.openInfoWindowAgain = false;
				});

				GEvent.addListener(self.config.map.getMap(), "infowindowclose", function(){
					self.config.map.returnToSavedPosition();
				});
				
				// add event to disclosure link
				$('#searchEnginedisclaimerLink').click(function(){
					$('#searchEngineDisclaimer:visible').slideUp();
					$('#searchEngineDisclaimer:not(:visible)').slideDown();
					return false;
				});
				
				//Soft refreshes in Firefox won't reset the drop downs...
				if($.browser.mozilla){
					$("form").each(function(){
						this.reset();
					});
				}
				
				//show/hide stats
				if(self.config.mlsSearchType == searchType_commercialSale || self.config.mlsSearchType == searchType_commercialLease){
					self.config.map.makeLarge();
				}else{
					self.config.map.makeSmall();
				}
				
				// load the search with the default mlsSearchType
				loadSearch(self.config.mlsSearchType, true, function(){});
				
			});
		}else{
			alert("Incompatible Browser!");
		}
		
		var initSearchTypes = function(){
			$('#searchTypes').change(function(){
				if($(this).val() == searchType_residential){
					self.config.map.makeSmall();
					//$("#quickStatsOverlay").css("display", "inline");  //Taken care of by makeSmall()
					$("#statsView").show();
					self.config.map.setStatsViewEvent();
					return loadSearch(searchType_residential, false);
				}else if($(this).val() == searchType_land){
					self.config.map.makeSmall();
					//$("#quickStatsOverlay").css("display", "inline");  //Taken care of by makeSmall()
					$('#statisticsPanel:hidden').show();
					$("#statsView").show();
					self.config.map.setStatsViewEvent();
					return loadSearch(searchType_land, false);
				}else if($(this).val() == searchType_commercialSale){
					self.config.map.makeLarge();
					//$("#quickStatsOverlay").css("display", "none");  //Taken care of by makeLarge()
					$("#statsView").hide();
					return loadSearch(searchType_commercialSale, false);
				}else if($(this).val() == searchType_commercialLease){
					self.config.map.makeLarge();
					//$("#quickStatsOverlay").css("display", "none");  //Taken care of by makeLarge()
					$("#statsView").hide();
					return loadSearch(searchType_commercialLease, false);
				}else if($(this).val() == searchType_rental){
					self.config.map.makeLarge();
					$("#statsView").hide();
					return loadSearch(searchType_rental, false);
				}else{
					return false;
				}
			});			
		}
				
		/** 
		* 
		* 
		*/ 
		var mLSSearchEngineRunSearchStats = self.config.mLSSearchEngineRunSearchStats = function(){
			// fetch the statistics data from the server
			if(self.statsAjaxActivity != null)
				self.statsAjaxActivity.abort();
				
			self.statsAjaxActivity = $.ajax({
				type: "GET",
				url: self.config.absUrl,
				beforeSend: function(){
					//$("#mapStats_mostExp").html("<img src=\"/t/resources/rpm3.0/images/activity/indicator_small.gif\"/>");
					//$("#mapStats_leastExp").html("<img src=\"/t/resources/rpm3.0/images/activity/indicator_small.gif\"/>");
					//$("#mapStats_avg").html("<img src=\"/t/resources/rpm3.0/images/activity/indicator_small.gif\"/>");
					//$("#mapStats_new").html("<img src=\"/t/resources/rpm3.0/images/activity/indicator_small.gif\"/>");
				},
				data: "pathway=48&map=true&envPropType="+self.config.mlsSearchType+"&"+$.generateSerializedRPMFields(self.config.searchFields)+"&latitude="+self.config.map.getSouthwestBounds().lat()+"&latitude="+self.config.map.getNortheastBounds().lat()+"&longitude="+self.config.map.getSouthwestBounds().lng()+"&longitude="+self.config.map.getNortheastBounds().lng(),
				dataType: "json",
				async: true,
				error: function(data, error){
					alert("Error: mLSSearchEngineRenderStats(): " + error + " " + data);
					$("#mapStats_mostExp").html("N/A");
					$("#mapStats_leastExp").html("N/A");
					$("#mapStats_avg").html("N/A");
					$("#mapStats_new").html("N/A");
				},
				success: function(data){
					// populate the statistics
					$("#mapStats_mostExp").html(data.maxPrice);
					$("#mapStats_leastExp").html(data.minPrice);
					$("#mapStats_avg").html(data.averagePrice);
					$("#mapStats_new").html(data.listedToday);
				},
				complete: function(xmlhttprequest, successtype){
					self.statsAjaxActivity = null;
				}
			});
		}

		/**
		 * Runs a full search
		 *
		 * @param sNumber optional starting number
		 * @param incremental optional flag as to whether or not this is a paging call
		 */
		var mLSSearchEngineRunSearch = self.config.mLSSearchEngineRunSearch = function(sNumber, incremental){
			self.mapLoaded = false;
			
			if(incremental == null){
				incremental = false;
			}
			
			if((self.config.mlsSearchType == searchType_residential || self.config.mlsSearchType == searchType_land) && !incremental){
				$("#mapStats_mostExp").html("<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\"  />");
				$("#mapStats_leastExp").html("<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\"  />");
				$("#mapStats_avg").html("<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\"  />");
				$("#mapStats_new").html("<img src=\"/t/resources/rpm3.0/images/activity/se_indicator_small.gif\"  />");
			}
			
			// show saved search button
			$('#savedSearchMessage:not(:hidden)').hide();
			$('#saveSearchButton:hidden').show();
			
			// get the starting number
			var startNumber;
			if(sNumber == null)
				startNumber = 0;
			else
				startNumber = sNumber;
			
			// Save global vars
			self.config.currentNEBounds = self.config.map.getNortheastBounds();
			self.config.currentSWBounds = self.config.map.getSouthwestBounds();
			self.config.currentPage = startNumber;

			// show loading message
			self.config.map.showLoadingMessage();
		
			// fetch the listing/areaID data from the server
			if(self.searchAjaxActivity != null)
				self.searchAjaxActivity.abort();
				
			self.searchAjaxActivity = $.ajax({
				type: "GET",
				url: self.config.absUrl,
				data: "pathway=5&search=1&envPropType="+self.config.mlsSearchType+"&"+$.generateSerializedRPMFields(self.config.searchFields)+"&startNumber="+startNumber+"&latitude="+self.config.map.getSouthwestBounds().lat()+"&latitude="+self.config.map.getNortheastBounds().lat()+"&longitude="+self.config.map.getSouthwestBounds().lng()+"&longitude="+self.config.map.getNortheastBounds().lng()+"&zoomLevel="+self.config.map.getZoom()+"&listingsSort="+$("#mapListingsSort").val()+"&searchViewType="+self.config.currentSearchView+"&zoomLevel="+self.config.map.getZoom(),
				dataType: "json",
				async: true,
				error: function(data, error){
					alert("Error: mLSSearchEngineRunSearch(): " + error + " " + data);
				},
				success: function(data){
					// add listings
					self.config.map.addListings(data);
				},
				complete: function(xmlhttprequest, successtype){
					// hide loading message
					self.config.map.hideLoadingMessage();
					self.mapLoaded = true;
					
					// show the search stats
					if((self.config.mlsSearchType == searchType_residential || self.config.mlsSearchType == searchType_land) && !incremental){
						self.config.mLSSearchEngineRunSearchStats();
					}
					
					self.searchAjaxActivity = null;
				}
			});
		}
	}
	
	/** Locks the search engine because we searching with a list date range.
	  *
	  * Shows an overlay over the left hand panel that disables it.
	  */
	$.mLSSearchEngineLockListDate = function(){

		//Lock the left hand panel.
		$.mLSSearchEngineShowBusyOverlay('listDateRestriction');

		//Register the onclick function that hides this thing when the user wishes to be done.
		$('#searchEngineLeftColumnBusyCloseListDateRestriction').click(function(){
			return $.mLSSearchEngineUnLockListDate();
		});

		return false;
	}

	/** Removes the listing date restriction on the search and hides the busy overlay that prevents searching.
	 *
	 */
	$.mLSSearchEngineUnLockListDate = function(){
		//Hide the overlay.
		$.mLSSearchEngineHideBusyOverlay("listDateRestriction");

		//Set the list date range variables to blank to clear the list date range restriction.
		$('#listDateRangeStart').val('');
		$('#listDateRangeEnd').val('');

		//Re-Run the search as it's results will now be different.
		$.mLSSearchEngineRunSearch();

		return false;
	}
		
})(jQuery);