content: package tim.prune.function.browser;
  
  import tim.prune.I18nManager;
  import tim.prune.data.DataPoint;
  import tim.prune.data.TrackInfo;
  
  /**
   * Class to manage the generation of map urls
   * for display in an external browser
   */
  public abstract class UrlGenerator
  {
  	public enum WebService
  	{
  		MAP_SOURCE_GOOGLE,      /* Google maps */
  		MAP_SOURCE_OSM,         /* OpenStreetMap */
  		MAP_SOURCE_MAPQUEST,    /* Mapquest */
  		MAP_SOURCE_BING,        /* Bing */
  		MAP_SOURCE_PEAKFINDER,  /* PeakFinder */
  		MAP_SOURCE_GEOHACK,     /* Geohack */
  		MAP_SOURCE_MAPILLARY,
  		MAP_SOURCE_GRAPHHOPPER  /* Routing with GraphHopper */
  	}
  
  	/**
  	 * Generate a URL for the given source and track info
  	 * @param inSource source to use, from the enum in UrlGenerator
  	 * @param inTrackInfo track info
  	 * @return url for map
  	 */
  	public static String generateUrl(WebService inSource, TrackInfo inTrackInfo)
  	{
  		switch (inSource)
  		{
  			case MAP_SOURCE_GOOGLE:
  				return generateGoogleUrl(inTrackInfo);
  			case MAP_SOURCE_MAPQUEST:
  				return generateMapquestUrl(inTrackInfo);
  			case MAP_SOURCE_BING:
  				return generateBingUrl(inTrackInfo);
  			case MAP_SOURCE_MAPILLARY:
  				return generateMapillaryUrl(inTrackInfo);
  			case MAP_SOURCE_PEAKFINDER:
  				return generatePeakfinderUrl(inTrackInfo);
  			case MAP_SOURCE_GEOHACK:
  				return generateGeohackUrl(inTrackInfo);
  			case MAP_SOURCE_GRAPHHOPPER:
  				return generateGraphHopperUrl(inTrackInfo);
  			case MAP_SOURCE_OSM:
  			default:
  				return generateOpenStreetMapUrl(inTrackInfo);
  		}
  	}
  
  	/**
  	 * Generate a url for Google maps
  	 * @param inTrackInfo track information
  	 * @return URL
  	 */
  	private static String generateGoogleUrl(TrackInfo inTrackInfo)
  	{
  		MapCoords coords = MapCoords.from(inTrackInfo);
  		if (coords == null) {
  			return null;
  		}
  		// Build basic url with centre position and span
  		String url = "https://" + I18nManager.getText("url.googlemaps")
  			+ "/?ll=" + coords.getLatitude() + "," + coords.getLongitude()
  			+ "&spn=" + coords.getLatSpan() + "," + coords.getLonSpan();
  		DataPoint currPoint = inTrackInfo.getCurrentPoint();
  		// Add selected point, if any
  		if (currPoint != null)
  		{
  			url = url + "&q=" + coords.getLatitude() + "," + coords.getLongitude();
  			if (currPoint.getWaypointName() != null) {
  				url = url + "(" + currPoint.getWaypointName() + ")";
  			}
  		}
  		return url;
  	}
  
  	/**
  	 * Generate a url for Mapquest maps
  	 * @param inTrackInfo track information
  	 * @return URL
  	 */
  	private static String generateMapquestUrl(TrackInfo inTrackInfo)
  	{
  		MapCoords coords = MapCoords.from(inTrackInfo);
  		if (coords == null) {
  			return null;
  		}
  		return "https://www.mapquest.com/latlng/"
  			+ coords.getLatitude() + "," + coords.getLongitude();
  	}
  
  	/**
  	 * Generate a url for Bing maps
  	 * @param inTrackInfo track information
  	 * @return URL
  	 */
  	private static String generateBingUrl(TrackInfo inTrackInfo)
  	{
  		MapCoords coords = MapCoords.from(inTrackInfo);
  		if (coords == null) {
  			return null;
  		}
  		return "https://www.bing.com/maps?cp=" + coords.getLatitude() + "~" + coords.getLongitude()
  			+ "&where1=" + coords.getLatitude() + "%2C%20" + coords.getLongitude();
  	}
  
  	/**
  	 * Generate a url for routing with GraphHopper
  	 * @param inTrackInfo track information
  	 * @return URL
  	 */
  	private static String generateGraphHopperUrl(TrackInfo inTrackInfo)
  	{
  		// Check if any data to display
  		if (inTrackInfo != null && inTrackInfo.getTrack() != null && inTrackInfo.getTrack().getNumPoints() >= 2)
  		{
  			if (inTrackInfo.getTrack().getNumPoints() == 2)
  			{
  				// Use first and last point of track
  				return generateGraphHopperUrl(inTrackInfo.getTrack().getPoint(0),
  					inTrackInfo.getTrack().getPoint(1));
  			}
  			else if (inTrackInfo.getSelection().hasRangeSelected())
  			{
  				// Use first and last point of selection
  				final int startIndex = inTrackInfo.getSelection().getStart();
  				final int endIndex = inTrackInfo.getSelection().getEnd();
  				return generateGraphHopperUrl(inTrackInfo.getTrack().getPoint(startIndex),
  					inTrackInfo.getTrack().getPoint(endIndex));
  			}
  		}
  		return null;
  	}
  
  	/**
  	 * Generate a url for routing with GraphHopper
  	 * @param inStartPoint start point of routing
  	 * @param inEndPoint end point of routing
  	 * @return URL
  	 */
  	private static String generateGraphHopperUrl(DataPoint inStartPoint, DataPoint inEndPoint)
  	{
  		MapCoords startCoords = MapCoords.from(inStartPoint);
  		MapCoords endCoords = MapCoords.from(inEndPoint);
  		if (startCoords == null || endCoords == null) {
  			return null;
  		}
  		return "https://graphhopper.com/maps/"
  			+ "?point=" + startCoords.getLatitude() + "%2C" + startCoords.getLongitude()
  			+ "&point=" + endCoords.getLatitude() + "%2C" + endCoords.getLongitude()
  			+ "&locale=" + I18nManager.getText("wikipedia.lang")
  			+ "&elevation=true&weighting=fastest";
  	}
  
  	/**
  	 * Generate a url for Open Street Map
  	 * @param inTrackInfo track information
  	 * @return URL
  	 */
  	private static String generateOpenStreetMapUrl(TrackInfo inTrackInfo)
  	{
  		MapCoords minCoords = MapCoords.minValues(inTrackInfo);
  		MapCoords maxCoords = MapCoords.maxValues(inTrackInfo);
  		if (minCoords == null || maxCoords == null) {
  			return null;
  		}
  		String url = "https://www.openstreetmap.org/?minlat=" + minCoords.getLatitude()
  			+ "&maxlat=" + maxCoords.getLatitude()
  			+ "&minlon=" + minCoords.getLongitude() + "&maxlon=" + maxCoords.getLongitude();
  		MapCoords pointCoords = MapCoords.from(inTrackInfo.getCurrentPoint());
  		// Add selected point, if any (no way to add point name?)
  		if (pointCoords != null) {
  			url = url + "&mlat=" + pointCoords.getLatitude()
  				+ "&mlon=" + pointCoords.getLongitude();
  		}
  		return url;
  	}
  
  	/**
  	 * Generate a url for PeakFinder
  	 * @param inTrackInfo track information
  	 * @return URL
  	 */
  	private static String generatePeakfinderUrl(TrackInfo inTrackInfo)
  	{
  		MapCoords coords = MapCoords.from(inTrackInfo.getCurrentPoint());
  		if (coords == null) {
  			return null;
  		}
  		return "https://www.peakfinder.org/?lat=" + coords.getLatitude()
  			+ "&lng=" + coords.getLongitude();
  	}
  
  	/**
  	 * Generate a url for Geohack
  	 * @param inTrackInfo track information
  	 * @return URL
  	 */
  	private static String generateGeohackUrl(TrackInfo inTrackInfo)
  	{
  		MapCoords coords = MapCoords.from(inTrackInfo.getCurrentPoint());
  		if (coords == null) {
  			return null;
  		}
  		return "https://tools.wmflabs.org/geohack/geohack.php?params=" + coords.getLatitude()
  			+ "_N_" + coords.getLongitude() + "_E";
  		// Note: Could use absolute values and S, W but this seems to work
  	}
  
  	/**
  	 * Generate a url for Mapillary
  	 * @param inTrackInfo track information
  	 * @return URL
  	 */
  	private static String generateMapillaryUrl(TrackInfo inTrackInfo)
  	{
  		MapCoords coords = MapCoords.from(inTrackInfo);
  		if (coords == null) {
  			return null;
  		}
  		return "https://www.mapillary.com/app/?lat=" + coords.getLatitude() + "&lng=" + coords.getLongitude() + "&z=16";
  	}
  }
  