/**
 * @class MapSearch
 * Google implmentation of the MapSearch
 * @extends MapSearch
 */
Object.extend (MapSearch.prototype, {
    initialize: function(mapString) {
        // set up a map controller object so that we can draw activity routes on the map.
        // both controller and search are using the same map
        this.mc = new MapController(mapString, null, false);
        this.mc.usePositionMarker = false;
        this.map = this.mc.map;
		
        log('setting up map');
        this.mc.map.addControl(new GMapTypeControl());
        this.mc.map.addControl(new GLargeMapControl());
        this.mc.map.addControl(new GScaleControl());
        this.mc.map.enableDoubleClickZoom();
        this.mc.map.enableContinuousZoom();
        
		this.mc.centerAndScale(40, -100, 3);

		this.results = new Hash({});
		this.nextPagePossible = false;
        this.geocoder = new GClientGeocoder();
		this.baseIcon = MBIcon.getBaseIcon();
        this.indicator = new Indicator('indicator');
        
        this.currentViewId = "searchResultsCurrentView";
		this.resultsActionsId = "searchResultsActions";
        this.resultsListId = "searchResultsList";
        this.pageSelectId = "searchResultsPageSelect";
        
        this.currentKeywords = "";
        this.currentLocation = "";
        this.currentBounds = null;
        this.handler = null;
    },

    /**
     * performSearch resets all previous search values and performs a new search with the user entered
     * values for keyword and location.
     * 
     * @param keyword
     * @param location
     * @member MapSearch
     */          
    performSearch: function(keyword, location, pageNumber, centerLat, centerLng, zoom) {
    	this.clearResults();
		
		this.currentKeywords = keyword;
		this.currentLocation = "";
		addLocationLabel();
		
		if(pageNumber) {
			this.resultsPage = parseInt(pageNumber);
		} else {
			this.resultsPage = 1;
		}
	
		if(location==currentMapViewText) location = "";
	
		if(location || zoom) {
			this.locationChanged = true;

			// update the results only after the map has finished moving
			this.handler = GEvent.bind(this.map, "moveend", this, this.updateResults);
					
			if(location) {
				this.geocoder.getLocations(location, this.moveToLocation.bind(this));
			} else {
				this.map.setCenter(new GLatLng(centerLat, centerLng), parseInt(zoom));
			}
		} else {
			this.currentBounds = this.map.getBounds();
			this.locationChanged = false;
			this.updateResults();
		}
    },

    /**
     * 
     * 
     * @member MapSearch
     */
    updateResults: function() {
		// TODO: abort the last request if there is one pending
	
		// need to do this so tat we 
		if(this.locationChanged) {
			this.currentBounds = this.map.getBounds();
			this.locationChanged = false;
		}
	
		var bounds = this.currentBounds;
	
		url = localPath + "/export/ActivitiesList.jspx?";
		url += "pageNumber=" + this.resultsPage + "&";
		url += "keywords=" + escape(this.currentKeywords) + "&";
		url += "minLat=" + bounds.getSouthWest().x + "&";
		url += "minLng=" + bounds.getSouthWest().y + "&";
		url += "maxLat=" + bounds.getNorthEast().x + "&";
		url += "maxLng=" + bounds.getNorthEast().y;

		var request = new Ajax.Request(url, {
			onSuccess: function(resp) {
				eval(resp.responseText);
		
				this.indicator.hide();
				this.clearResults();
				
				this.nextPagePossible = nextPage;
				
				if(activitiesList.length != 0) {
					$(this.resultsListId).innerHTML = "";
					for (var i = 0;i<activitiesList.length;i++)	{
						var activity = activitiesList[i];
						this.addActivity(activity, i);
					}
				}
				this.updatePageSelect();
				this.updateCurrentView();
				this.updateActions();
			}.bind(this),
			onFailure: function(resp) {
				log("Error retrieving results");
				this.indicator.hide();
				$(this.currentViewId).innerHTML = "";
			}.bind(this)
		});
		
		// remove the search handler that we created when the user entered a 'location'
		if(this.handler) {
			GEvent.removeListener(this.handler);
			this.handler = null;
		}
	
		this.indicator.show();
		$(this.currentViewId).innerHTML = "<span class='loadingResultsText'>Loading...</span>"; 
    },

    /**
     * 
     * 
     * @param response
     * @member MapSearch
     */
    moveToLocation: function(response) {

		if (!response || response.Status.code != 200) {
			new ActionMessage("Warning", "Sorry, we were unable to find that location.  Please try something more specific or <a href='#' onclick=toggleHelpOverlay('searchFormComponentHelpOverlay')>get help</a>.");
			GEvent.clearListeners(this.map, "moveend");
//			alert("Sorry, we were unable to find that location.  Please try something more specific.");
		} else {
			place = response.Placemark[0];
			point = new GLatLng(place.Point.coordinates[1],
			                    place.Point.coordinates[0]);

			var zoomLevel = 10;
			switch(place.AddressDetails.Accuracy) {
				case 1: // Country level accuracy.
					zoomLevel = 4;
					break;
				case 2: // Region (state, province, prefecture, etc.) level accuracy.
					zoomLevel = 6;
					break;
				case 3: // Sub-region (county, municipality, etc.) level accuracy.
					zoomLevel = 9;
					break;
				case 4: // Town (city, village) level accuracy.
					zoomLevel = 11;
					break;
				case 5: // Post code (zip code) level accuracy.
					zoomLevel = 12;
					break;
				case 6: // Street level accuracy
					zoomLevel = 16;
					break;
				case 7: // Intersection level accuracy.
					zoomLevel = 17;
					break;
				case 8: // Address level accuracy.
					zoomLevel = 18;
					break;
			}

			this.map.setCenter(point, zoomLevel);
			this.currentLocation = place.address;
		}
    },

    /**
     * 
     * 
     * @param activity
     * @param listIndex
     * @member MapSearch
     */  	
    addActivity: function(activity, listIndex) {
    	// create a marker and add it to the map
    	var marker = this.createMarker(new GLatLng(activity.startLat, activity.startLng), listIndex);
	
		GEvent.bind(marker, "click", this, function() {
			this.selectActivity(activity.activityId);
		}.bind(this));
		this.map.addOverlay(marker);
		var markerImage = marker.printImage;
		
		// add the activity listing to the search results window
		var listId = "result" + activity.activityId;
		
		// add a new SearchResult object to the results hash
		var searchResult = new SearchResult(activity, marker, listId);
		
		$(this.resultsListId).innerHTML += this.listResultHtml(searchResult);
		
		var tmp = new Hash();
		tmp[activity.activityId] = searchResult;
		this.results.merge(tmp);
    },

    /**
     * 
     * 
     * @param searchResult
     * @member MapSearch
     */      
    listResultHtml: function(searchResult) {
    	var listId = searchResult.listId;
    	var marker = searchResult.marker;
    	var activity = searchResult.activity;
    	
    	var resultHtml = "";
    	
    	resultHtml += "<div class='searchResultContainer'>";
    	resultHtml += "<img src='" + marker.getIcon().image + "'>";
    	resultHtml += "<div class='searchResultText' id='" + listId + "' onclick='search.selectActivity(" + activity.activityId + ")'>";
    	resultHtml += "<a href='javascript:void(0)'>" + activity.activityName.truncate(25) + "</a><br/>";
    	resultHtml += "by " + activity.username + "<br/>";
    	// resultHtml += "Activity Type: <b>" + activity.activityType.truncate(15) + "</b><br/>";
		resultHtml += "<span onclick='search.drawRoute(" + activity.activityId + ")'><a href='javascript:void(0);'>Draw Route</a></span> | ";
		resultHtml += "<a href='" + this.getActivityLink(activity.activityId) + "'>Details >></a></div>";
    	resultHtml += "</div></div>";
    	
    	return resultHtml;
    },

    /**
     * 
     * 
     * @param activityId
     * @member MapSearch
     */    
    selectActivity: function(activityId) {
		this.clearSelection();
	
		var result = this.results[activityId];
		var activity = result.activity;
		var marker = result.marker;
		var listId = result.listId;
	
		// open info window over the map marker
		detailsTab = "<div class='searchResultInfoWindow'>"
		detailsTab += "<a href='" + this.getActivityLink(activity.activityId) + "' class='searchResultActivityName'>" + activity.activityName + "</a><br/>";
		detailsTab += "by <b>" + activity.username + "</b><br/>";
		detailsTab += "on " + activity.startDate + "<br/>";
		detailsTab += "Activity Type: <b>" + activity.activityType + "</b><br/>";
    	detailsTab += "Event Type: <b>" + activity.eventType + "</b><br/><br/>";
    	
    	detailsTab += "Total Time: <b>" + activity.totalDuration + "</b><br/>";
		detailsTab += "Distance: <b>" + activity.totalDistance + "</b><br/>";
		detailsTab += "Average Speed: <b>" + activity.averageMovingSpeed + "</b><br/>";
		detailsTab += "Elevation Gain: <b>+" + activity.totalElevationGain + " / -" + activity.totalElevationLoss + "</b><br/><br/>";
		
		detailsTab += "<span onclick='search.drawRoute(" + activity.activityId + ")'><a href='javascript:void(0);'>Draw Route</a></span> | ";
		detailsTab += "<a href='" + this.getActivityLink(activity.activityId) + "'>Details >></a></div>";
		
		var routeTab = "route"; 
		
		var infoTabs = [
			new GInfoWindowTab("Details", detailsTab),
			new GInfoWindowTab("Route", routeTab)
		];
		marker.openInfoWindowHtml(detailsTab);

		// highlight the text result
		Element.addClassName($(listId), "searchResultSelected");
//		this.drawRoute(activityId);
    },

    /**
     * 
     * 
     * @member MapSearch
     */      
    searchParams: function() {
       	var params = "";
    	
    	if(this.currentKeywords) {
	    	params += "keyword=" + escape(this.currentKeywords) + "&";
	    }
	    if(this.currentLocation) {
	    	params += "location=" + escape(this.currentLocation) + "&";
	    } else {
	    	params += "mapLat=" + this.map.getCenter().y + "&";
	    	params += "mapLng=" + this.map.getCenter().x + "&";
	    	params += "mapZoom=" + this.map.getZoom() + "&";
	    }
    	params += "pageNumber=" + this.resultsPage + "&";
    	    	
    	return params;
    },

    /**
     * 
     * 
     * @param activityId
     * @member MapSearch
     */    
    drawRoute: function(activityId) {
		var result = this.results[activityId];
		
		if(!result.isDrawn) {
			var url = localPath + "/export/GpsTrack.jspx?";
			url += "activityId=" + activityId + "&";
	
			this.indicator.show();
	
			new Ajax.Request(url, {
				onSuccess: function(resp) {
					this.indicator.hide();
					
					eval(resp.responseText); 
				    var track = new Track(trackJSON);
				    
				    this.mc.centerAndScale(track.getStart().getLat(), track.getStart().getLon());
				    this.mc.addTrack(track);
//				    this.mc.addStartFinishMarkers(track);
				}.bind(this),
				onFailure: function(resp) {
					log("Error retrieving activity track");
				}
			});
			
			result.setDrawn();
		}
	},

    /**
     * 
     * 
     * @member MapSearch
     */
    clearSelection: function() {
		var resultValues = this.results.values();
		resultValues.each(function(result) {
			var listId = result.listId;
			
			Element.removeClassName($(listId), "searchResultSelected");
		});
	},

    /**
     * 
     * 
     * @member MapSearch
     */
	clearResults: function() {
		this.map.clearOverlays();	
		this.results = new Hash({});
		this.nextPagePossible = false;
		
		$(this.currentViewId).innerHTML = "";
		$(this.resultsActionsId).innerHTML = "";
		$(this.resultsListId).innerHTML = "";
		$(this.pageSelectId).innerHTML = "";
	},
	
    /**
     * 
     * 
     * @param point
     * @param index
     * @member MapSearch
     */
	createMarker: function(point, index) {
		// Create a lettered icon for this point using our icon class
		var letter = String.fromCharCode("A".charCodeAt(0) + index);
		var icon = new GIcon(this.baseIcon);
		icon.image = "http://www.google.com/mapfiles/marker" + letter + ".png";
		var marker = new GMarker(point, icon);

		return marker;
	},

    /**
     * Updates the text at the top of the search result informing the user of what results they
     * are currently looking at.
     * 
     * @member MapSearch
     */	
	updateCurrentView: function() {
		log("updating current view");
	    this.indicator.hide();
		if(this.resultsPage == 1 && this.results.values().length == 0) {
			$(this.currentViewId).innerHTML = "";
			
			$(this.currentViewId).innerHTML += "Your search";
			if(this.currentKeywords) {
				$(this.currentViewId).innerHTML += " for <b>'" + this.currentKeywords + "'</b>";
			}
			if(this.currentLocation) {
				$(this.currentViewId).innerHTML += " near " + this.currentLocation;
			}
			$(this.currentViewId).innerHTML += " did not match any activities.";

			return;
		}
	
		var resultsStart = ((this.resultsPage - 1) * 10) + 1;
		var resultsEnd = ((this.resultsPage - 1) * 10) + this.results.values().length;
	
		$(this.currentViewId).innerHTML = "";
		$(this.currentViewId).innerHTML += "Viewing results " + resultsStart + " - " + resultsEnd + " for";

		if(this.currentKeywords) {
			$(this.currentViewId).innerHTML += " <b>'" + this.currentKeywords + "'</b>";
		} else {
			$(this.currentViewId).innerHTML += " <b>all</b>";
		}
		$(this.currentViewId).innerHTML += " activities";
		if(this.currentLocation) {
			$(this.currentViewId).innerHTML += " near <b>" + this.currentLocation + "</b>";
		} else {
			$(this.currentViewId).innerHTML += " in the <b>map view</b>";
		}
		$(this.currentViewId).innerHTML += ".";
	},
	

    /**
     * Updates the current search results actions including the link here and email links.
     * 
     * @member MapSearch
     */	
	updateActions: function() {
		log("updating results actions");

		if(this.results.values().length > 0) {
			$(this.resultsActionsId).innerHTML = "<a href='" + this.getSearchLink() + "'><img src='" + localPath + "/image/search/results-link.png' /></a> <a href='" + this.getSearchLink() + "'>Link Here</a>";
			$(this.resultsActionsId).innerHTML += " | ";
			$(this.resultsActionsId).innerHTML += "<a href='" + this.getEmailLink() + "'><img src='" + localPath + "/image/search/results-email.png' /></a> <a href='" + this.getEmailLink() + "'>Email</a>";
		}
	},

	getActivityLink: function(activityId) {
		var activityLink;
		activityLink = localPath;
		activityLink += "/activity/" + activityId;
		activityLink += "?" + this.searchParams();
        
        return activityLink;
	},
	
	getSearchLink: function() {
		var searchLink;
		searchLink = localHost + localPath;
		searchLink += "/search.do?";
		searchLink += this.searchParams();
        
        return searchLink;
	},
	
	getEmailLink: function() {
		var emailSubject = "Check out these rides from zumo Connect!";
		var emailLink = "mailto:?subject=" + escape(emailSubject) + "&body=" + escape(this.getSearchLink());
        
        return emailLink;
	},
	
	
    /**
     * Draws the page selection links at the bottom of the search results window.  Handles logic for number
     * of pages and whether the total number of total results in known.
     * 
     * @member MapSearch
     */
	updatePageSelect: function() {
		log("updating page select");
		
		$(this.pageSelectId).innerHTML = "";
		if(this.resultsPage > 1) {
			$(this.pageSelectId).innerHTML += "<span onclick='search.previousPage()'><a href='javascript:void(0)'>Prev</a></span> ";	
		}
		
		if(this.resultsPage == 1 && !this.nextPagePossible) {
			return;
		}
		
		var pagesToShow = this.resultsPage;
		if(this.nextPagePossible) {
			pagesToShow += 1;
		}
		
		log("pagesToShow: " + pagesToShow);
		
		for(n = 0; n < pagesToShow; n++) {
			var page = n + 1;
			if(page == search.resultsPage) {
				$(this.pageSelectId).innerHTML += page + " ";
			}
			else if(page > (search.resultsPage - 6)) {
				$(this.pageSelectId).innerHTML += "<span onclick='search.setResultsPage(" + page + ")'><a href='javascript:void(0)'>" + page + "</a></span> ";
			}
		}

		log("going on");

		if(this.nextPagePossible) {
			$(this.pageSelectId).innerHTML += "<span onclick='search.nextPage()'><a href='javascript:void(0)'>Next</a></span> ";
		}
	},
	
	toString: function() {
	    return 'MapSearch google style';
	}
});