diff --git a/plugins/ElevationProfile/.project b/plugins/ElevationProfile/.project
index 091983087..fa9f47f0a 100644
--- a/plugins/ElevationProfile/.project
+++ b/plugins/ElevationProfile/.project
@@ -24,5 +24,6 @@
 	<natures>
 		<nature>org.eclipse.jdt.core.javanature</nature>
 		<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
+		<nature>org.apache.ivyde.eclipse.ivynature</nature>
 	</natures>
 </projectDescription>
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationHelper.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationHelper.java
index da02596f8..e1ebb3754 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationHelper.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationHelper.java
@@ -5,9 +5,11 @@ import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 import java.util.List;
+import java.util.Optional;
 
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.SystemOfMeasurement;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.plugins.elevation.gpx.GeoidCorrectionKind;
@@ -34,9 +36,6 @@ public final class ElevationHelper {
 
     private static GeoidCorrectionKind geoidKind = GeoidCorrectionKind.None;
 
-    /** The HGT reader instance. */
-    private static final HgtReader hgt = new HgtReader();
-
     /**
      * Gets the current mode of GEOID correction.
      */
@@ -165,11 +164,11 @@ public final class ElevationHelper {
      * @return The z coordinate or {@link Double#NaN}, if elevation value could not be obtained
      *         not height attribute.
      */
-    public static double getSrtmElevation(LatLon ll) {
+    public static double getSrtmElevation(ILatLon ll) {
         if (ll != null) {
             // Try to read data from SRTM file
             // TODO: Option to switch this off
-            double eleHgt = hgt.getElevationFromHgt(ll);
+            double eleHgt = HgtReader.getElevationFromHgt(ll);
 
             if (isValidElevation(eleHgt)) {
                 return eleHgt;
@@ -178,6 +177,18 @@ public final class ElevationHelper {
         return NO_ELEVATION;
     }
 
+    /**
+     * Get the bounds for the pixel elevation for the latitude
+     * @param location The location to get
+     * @return The bounds for the elevation area
+     */
+    public static Optional<Bounds> getBounds(ILatLon location) {
+        if (location != null) {
+            return HgtReader.getBounds(location);
+        }
+        return Optional.empty();
+    }
+
     /**
      * Checks given area for SRTM data.
      *
@@ -251,7 +262,7 @@ public final class ElevationHelper {
         if (wpt == null) return -1;
 
         Calendar calendar = GregorianCalendar.getInstance(); // creates a new calendar instance
-        calendar.setTime(wpt.getDate());   // assigns calendar to given date
+        calendar.setTimeInMillis(wpt.getTimeInMillis()); // assigns calendar to given date
         return calendar.get(Calendar.HOUR_OF_DAY);
     }
 
@@ -262,7 +273,7 @@ public final class ElevationHelper {
         if (wpt == null) return -1;
 
         Calendar calendar = GregorianCalendar.getInstance(); // creates a new calendar instance
-        calendar.setTime(wpt.getDate());   // assigns calendar to given date
+        calendar.setTimeInMillis(wpt.getTimeInMillis()); // assigns calendar to given date
         return calendar.get(Calendar.MINUTE);
     }
 }
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationProfilePlugin.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationProfilePlugin.java
index 20929ab30..d43cae774 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationProfilePlugin.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationProfilePlugin.java
@@ -5,6 +5,7 @@ import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.Color;
 
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.gui.IconToggleButton;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.MainMenu;
@@ -32,6 +33,7 @@ public class ElevationProfilePlugin extends Plugin {
         super(info);
 
         createColorMaps();
+        ExtensionFileFilter.addImporter(new HgtFileImporter());
 
         // TODO: Disable this view as long as it is not stable
         MainMenu.add(MainApplication.getMenu().imagerySubMenu, new AddElevationLayerAction(), false, 0);
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java
index 000d24a73..7479c3912 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java
@@ -2,16 +2,25 @@
 package org.openstreetmap.josm.plugins.elevation;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.nio.ShortBuffer;
-import java.nio.channels.FileChannel;
+import java.nio.file.Paths;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+import org.apache.commons.compress.utils.IOUtils;
+import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.io.Compression;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Logging;
 
@@ -22,18 +31,17 @@ import org.openstreetmap.josm.tools.Logging;
  *  @author Oliver Wieland &lt;oliver.wieland@online.de&gt;
  */
 public class HgtReader {
-    private static final int SECONDS_PER_MINUTE = 60;
+    private static final int SRTM_EXTENT = 1; // degree
+    private static final List<String> COMPRESSION_EXT = Arrays.asList("xz", "gzip", "zip", "bz", "bz2");
 
     public static final String HGT_EXT = ".hgt";
 
     // alter these values for different SRTM resolutions
-    public static final int HGT_RES = 3; // resolution in arc seconds
-    public static final int HGT_ROW_LENGTH = 1201; // number of elevation values per line
-    public static final int HGT_VOID = -32768; // magic number which indicates 'void data' in HGT file
+    public static final int HGT_VOID = Short.MIN_VALUE; // magic number which indicates 'void data' in HGT file
 
-    private final HashMap<String, ShortBuffer> cache = new HashMap<>();
+    private static final HashMap<String, short[][]> cache = new HashMap<>();
 
-    public double getElevationFromHgt(LatLon coor) {
+    public static double getElevationFromHgt(ILatLon coor) {
         try {
             String file = getHgtFileName(coor);
             // given area in cache?
@@ -47,18 +55,21 @@ public class HgtReader {
                 for (String location : Preferences.getAllPossiblePreferenceDirs()) {
                     String fullPath = new File(location + File.separator + "elevation", file).getPath();
                     File f = new File(fullPath);
+                    if (!f.exists()) {
+                        for (String ext : COMPRESSION_EXT) {
+                            f = new File(fullPath + "." + ext);
+                            if (f.exists()) break;
+                        }
+                    }
                     if (f.exists()) {
-                        // found something: read HGT file...
-                        ShortBuffer data = readHgtFile(fullPath);
-                        // ... and store result in cache
-                        cache.put(file, data);
+                        read(f);
                         break;
                     }
                 }
             }
 
             // read elevation value
-            return readElevation(coor);
+            return readElevation(coor, file);
         } catch (FileNotFoundException e) {
             Logging.error("Get elevation from HGT " + coor + " failed: => " + e.getMessage());
             // no problem... file not there
@@ -71,27 +82,49 @@ public class HgtReader {
         }
     }
 
-    @SuppressWarnings("resource")
-    private ShortBuffer readHgtFile(String file) throws Exception {
-        CheckParameterUtil.ensureParameterNotNull(file);
+    public static Bounds read(File file) throws FileNotFoundException, IOException {
+        String location = file.getName();
+        for (String ext : COMPRESSION_EXT) {
+            location = location.replaceAll("\\." + ext + "$", "");
+        }
+        short[][] sb = readHgtFile(file.getPath());
+        // Overwrite the cache file (assume that is desired)
+        cache.put(location, sb);
+        Pattern pattern = Pattern.compile("(N|S)([0-9]{2})(E|W)([0-9]{3})");
+        Matcher matcher = pattern.matcher(location);
+        if (matcher.lookingAt()) {
+            int lat = (matcher.group(1) == "S" ? -1 : 1) * Integer.parseInt(matcher.group(2));
+            int lon = (matcher.group(3) == "W" ? -1 : 1) * Integer.parseInt(matcher.group(4));
+            return new Bounds(lat, lon, lat + 1, lon + 1);
+        }
+        return null;
+    }
 
-        FileChannel fc = null;
-        ShortBuffer sb = null;
-        try {
-            // Eclipse complains here about resource leak on 'fc' - even with 'finally' clause???
-            fc = new FileInputStream(file).getChannel();
-            // choose the right endianness
+    private static short[][] readHgtFile(String file) throws FileNotFoundException, IOException {
+        CheckParameterUtil.ensureParameterNotNull(file);
 
-            ByteBuffer bb = ByteBuffer.allocateDirect((int) fc.size());
-            while (bb.remaining() > 0) fc.read(bb);
+        short[][] data = null;
 
-            bb.flip();
-            sb = bb.order(ByteOrder.BIG_ENDIAN).asShortBuffer();
-        } finally {
-            if (fc != null) fc.close();
+        try (InputStream fis = Compression.getUncompressedFileInputStream(Paths.get(file))) {
+            // choose the right endianness
+            ByteBuffer bb = ByteBuffer.wrap(IOUtils.toByteArray(fis));
+            //System.out.println(Arrays.toString(bb.array()));
+            bb.order(ByteOrder.BIG_ENDIAN);
+            int size = (int) Math.sqrt(bb.array().length / 2);
+            data = new short[size][size];
+            int x = 0;
+            int y = 0;
+            while (x < size) {
+                while (y < size) {
+                    data[x][y] = bb.getShort(2 * (x * size + y));
+                    y++;
+                }
+                x++;
+                y = 0;
+            }
         }
 
-        return sb;
+        return data;
     }
 
     /**
@@ -101,38 +134,88 @@ public class HgtReader {
      * @param coor the coordinate to get the elevation data for
      * @return the elevation value or <code>Double.NaN</code>, if no value is present
      */
-    public double readElevation(LatLon coor) {
+    public static double readElevation(LatLon coor) {
         String tag = getHgtFileName(coor);
+        return readElevation(coor, tag);
+    }
+
+    /**
+     * Reads the elevation value for the given coordinate.
+     *
+     * See also <a href="http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file">stackexchange.com</a>
+     * @param coor the coordinate to get the elevation data for
+     * @param fileName The expected filename
+     * @return the elevation value or <code>Double.NaN</code>, if no value is present
+     */
+    public static double readElevation(ILatLon coor, String fileName) {
 
-        ShortBuffer sb = cache.get(tag);
+        short[][] sb = cache.get(fileName);
 
         if (sb == null) {
             return ElevationHelper.NO_ELEVATION;
         }
 
-        // see http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file
-        double fLat = frac(coor.lat()) * SECONDS_PER_MINUTE;
-        double fLon = frac(coor.lon()) * SECONDS_PER_MINUTE;
-
-        // compute offset within HGT file
-        int row = (int) Math.round(fLat * SECONDS_PER_MINUTE / HGT_RES);
-        int col = (int) Math.round(fLon * SECONDS_PER_MINUTE / HGT_RES);
-
-        row = HGT_ROW_LENGTH - row;
-        int cell = (HGT_ROW_LENGTH * (row - 1)) + col;
-
-        // valid position in buffer?
-        if (cell < sb.limit()) {
-            short ele = sb.get(cell);
-            // check for data voids
-            if (ele == HGT_VOID) {
-                return ElevationHelper.NO_ELEVATION;
-            } else {
-                return ele;
-            }
-        } else {
+        int[] index = getIndex(coor, sb.length);
+        short ele = sb[index[0]][index[1]];
+
+        if (ele == HGT_VOID) {
             return ElevationHelper.NO_ELEVATION;
         }
+        return ele;
+    }
+
+    public static Optional<Bounds> getBounds(ILatLon location) {
+        final String fileName = getHgtFileName(location);
+        final short[][] sb = cache.get(fileName);
+
+        if (sb == null) {
+            return Optional.empty();
+        }
+
+        final double latDegrees = location.lat();
+        final double lonDegrees = location.lon();
+
+        final float fraction = ((float) SRTM_EXTENT) / sb.length;
+        final int latitude = (int) Math.floor(latDegrees) + (latDegrees < 0 ? 1 : 0);
+        final int longitude = (int) Math.floor(lonDegrees) + (lonDegrees < 0 ? 1 : 0);
+
+        final int[] index = getIndex(location, sb.length);
+        final int latSign = latitude > 0 ? 1 : -1;
+        final int lonSign = longitude > 0 ? 1 : -1;
+        final double minLat = latitude + latSign * fraction * index[0];
+        final double maxLat = latitude + latSign * fraction * (index[0] + 1);
+        final double minLon = longitude + lonSign * fraction * index[1];
+        final double maxLon = longitude + lonSign * fraction * (index[1] + 1);
+        return Optional.of(new Bounds(Math.min(minLat, maxLat), Math.min(minLon, maxLon),
+                Math.max(minLat, maxLat), Math.max(minLon, maxLon)));
+    }
+
+    /**
+     * Get the index to use for a short[latitude][longitude] = height in meters array
+     *
+     * @param latLon
+     *            The location to get the index for
+     * @param mapSize
+     *            The size of the map
+     * @return A [latitude, longitude] = int (index) array.
+     */
+    private static int[] getIndex(ILatLon latLon, int mapSize)
+    {
+        double latDegrees = latLon.lat();
+        double lonDegrees = latLon.lon();
+
+        float fraction = ((float) SRTM_EXTENT) / mapSize;
+        int latitude = (int) Math.floor(Math.abs(latDegrees - (int) latDegrees) / fraction);
+        int longitude = (int) Math.floor(Math.abs(lonDegrees - (int) lonDegrees) / fraction);
+        if (latDegrees >= 0)
+        {
+            latitude = mapSize - 1 - latitude;
+        }
+        if (lonDegrees < 0)
+        {
+            longitude = mapSize - 1 - longitude;
+        }
+        return new int[] { latitude, longitude };
     }
 
     /**
@@ -143,19 +226,23 @@ public class HgtReader {
      * @param latLon the coordinate to get the filename for
      * @return the file name of the HGT file
      */
-    public String getHgtFileName(LatLon latLon) {
-        int lat = (int) latLon.lat();
-        int lon = (int) latLon.lon();
+    public static String getHgtFileName(ILatLon latLon) {
+        int lat = (int) Math.floor(latLon.lat());
+        int lon = (int) Math.floor(latLon.lon());
 
         String latPref = "N";
-        if (lat < 0) latPref = "S";
+        if (lat < 0) {
+            latPref = "S";
+            lat = Math.abs(lat);
+        }
 
         String lonPref = "E";
         if (lon < 0) {
             lonPref = "W";
+            lon = Math.abs(lon);
         }
 
-        return String.format("%s%02d%s%03d%s", latPref, lat, lonPref, lon, HGT_EXT);
+        return latPref + lat + lonPref + lon + HGT_EXT;
     }
 
     public static double frac(double d) {
@@ -167,4 +254,8 @@ public class HgtReader {
         fPart = d - iPart;
         return fPart;
     }
+
+    public static void clearCache() {
+        cache.clear();
+    }
 }
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/IElevationProfile.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/IElevationProfile.java
index 44965bbd9..3b5718e90 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/IElevationProfile.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/IElevationProfile.java
@@ -1,7 +1,7 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.plugins.elevation;
 
-import java.util.Date;
+import java.time.Instant;
 import java.util.List;
 
 import org.openstreetmap.josm.data.Bounds;
@@ -20,12 +20,12 @@ public interface IElevationProfile {
     /**
      * Gets the time stamp of first recorded track point.
      */
-    Date getStart();
+    Instant getStart();
 
     /**
      * Gets the time stamp of last recorded track point.
      */
-    Date getEnd();
+    Instant getEnd();
 
     /**
      * Gets the minimum elevation height of all tracks and routes.
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/actions/AddElevationLayerAction.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/actions/AddElevationLayerAction.java
index d77a46067..0a4e15988 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/actions/AddElevationLayerAction.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/actions/AddElevationLayerAction.java
@@ -27,6 +27,9 @@ public class AddElevationLayerAction extends JosmAction {
         if (currentLayer == null) {
             currentLayer = new ElevationGridLayer(tr("Elevation Grid")); // TODO: Better name
             MainApplication.getLayerManager().addLayer(currentLayer);
+        } else if (!MainApplication.getLayerManager().containsLayer(currentLayer)) {
+            currentLayer = null;
+            actionPerformed(arg0);
         }
     }
 }
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationProfile.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationProfile.java
index 879a12dc2..69d015663 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationProfile.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationProfile.java
@@ -1,8 +1,8 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.plugins.elevation.gpx;
 
+import java.time.Instant;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
 import org.openstreetmap.josm.data.Bounds;
@@ -44,8 +44,8 @@ IGpxWaypointVisitor {
     private int maxHeight;
     private int avrgHeight;
     private double dist;
-    private Date start = new Date();
-    private Date end = new Date();
+    private Instant start;
+    private Instant end;
     private final WayPoint[] importantWayPoints = new WayPoint[4];
     private IElevationProfile parent;
     private int sumEle; // temp var for average height
@@ -120,8 +120,8 @@ IGpxWaypointVisitor {
         if (n == 0)
             return;
 
-        start = new Date(0L);
-        end = new Date();
+        start = Instant.EPOCH;
+        end = Instant.now();
         this.minHeight = Integer.MAX_VALUE;
         this.maxHeight = Integer.MIN_VALUE;
         sumEle = 0;
@@ -195,8 +195,8 @@ IGpxWaypointVisitor {
      */
     protected void setStart(WayPoint wp) {
         importantWayPoints[WAYPOINT_START] = wp;
-        if(wp.getDate() != null)
-            this.start = wp.getDate();
+        if(wp.getInstant() != null)
+            this.start = wp.getInstant();
     }
 
     /**
@@ -204,8 +204,8 @@ IGpxWaypointVisitor {
      */
     protected void setEnd(WayPoint wp) {
         importantWayPoints[WAYPOINT_END] = wp;
-        if(wp.getDate() != null)
-            this.end = wp.getDate();
+        if(wp.getInstant() != null)
+            this.end = wp.getInstant();
     }
 
     public void setParent(IElevationProfile parent) {
@@ -256,7 +256,7 @@ IGpxWaypointVisitor {
     }
 
     @Override
-    public Date getEnd() {
+    public Instant getEnd() {
         return end;
     }
 
@@ -307,10 +307,10 @@ IGpxWaypointVisitor {
         WayPoint wp2 = getEndWayPoint();
 
         if (wp1 != null && wp2 != null) {
-            Date wp1Date = wp1.getDate();
-            Date wp2Date = wp2.getDate();
+            Instant wp1Date = wp1.getInstant();
+            Instant wp2Date = wp2.getInstant();
             if (wp1Date != null && wp2Date != null) {
-                return wp2Date.getTime() - wp1Date.getTime();
+                return wp2Date.toEpochMilli() - wp1Date.toEpochMilli();
             } else {
                 Logging.warn("Waypoints without date: " + wp1 + " / " + wp2);
             }
@@ -325,7 +325,7 @@ IGpxWaypointVisitor {
     }
 
     @Override
-    public Date getStart() {
+    public Instant getStart() {
         return start;
     }
 
@@ -389,11 +389,11 @@ IGpxWaypointVisitor {
             return;
 
         if (wp.hasDate()) {
-            if (wp.getDate().after(end)) {
+            if (wp.getInstant().isAfter(this.end)) {
                 setEnd(wp);
             }
 
-            if (wp.getDate().before(start)) {
+            if (wp.getInstant().isBefore(start)) {
                 setStart(wp);
             }
         }
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridLayer.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridLayer.java
index ec63979ae..da76bf4c0 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridLayer.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridLayer.java
@@ -7,10 +7,14 @@ import java.awt.Color;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 
 import javax.swing.Action;
 import javax.swing.Icon;
 
+import org.apache.commons.jcs3.JCS;
 import org.openstreetmap.gui.jmapviewer.MemoryTileCache;
 import org.openstreetmap.gui.jmapviewer.Tile;
 import org.openstreetmap.gui.jmapviewer.TileController;
@@ -18,11 +22,19 @@ import org.openstreetmap.gui.jmapviewer.TileXY;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.imagery.CoordinateConversion;
+import org.openstreetmap.josm.data.imagery.TileJobOptions;
+import org.openstreetmap.josm.data.osm.BBox;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.Notification;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.plugins.elevation.ElevationHelper;
+import org.openstreetmap.josm.plugins.elevation.HgtReader;
 import org.openstreetmap.josm.plugins.elevation.IVertexRenderer;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Logging;
@@ -31,7 +43,7 @@ import org.openstreetmap.josm.tools.Logging;
  * @author Oliver Wieland &lt;oliver.wieland@online.de&gt;
  *
  */
-public class ElevationGridLayer extends Layer implements TileLoaderListener {
+public class ElevationGridLayer extends Layer implements TileLoaderListener, MouseListener {
     private static final int ELE_ZOOM_LEVEL = 13;
     private final IVertexRenderer vertexRenderer;
     private final MemoryTileCache tileCache;
@@ -39,11 +51,15 @@ public class ElevationGridLayer extends Layer implements TileLoaderListener {
     protected ElevationGridTileLoader tileLoader;
     protected TileController tileController;
 
+    private ILatLon clickLocation;
+
     private Bounds lastBounds;
     private TileSet tileSet;
 
     public ElevationGridLayer(String name) {
         super(name);
+        HgtReader.clearCache();
+        MainApplication.getMap().mapView.addMouseListener(this);
 
         setOpacity(0.8);
         setBackgroundLayer(true);
@@ -52,7 +68,7 @@ public class ElevationGridLayer extends Layer implements TileLoaderListener {
         tileCache = new MemoryTileCache();
         tileCache.setCacheSize(500);
         tileSource = new ElevationGridTileSource(name);
-        tileLoader = new ElevationGridTileLoader(this);
+        tileLoader = new ElevationGridTileLoader(this, JCS.getInstance("elevationgridlayer"), new TileJobOptions(20, 20, null, 3600));
         tileController = new ElevationGridTileController(tileSource, tileCache, this, tileLoader);
     }
 
@@ -89,6 +105,16 @@ public class ElevationGridLayer extends Layer implements TileLoaderListener {
                 }
             }
         }
+        // Paint the current point area
+        ElevationHelper.getBounds(this.clickLocation).ifPresent(bounds -> {
+            final BBox bbox = bounds.toBBox();
+            final Point upperLeft = mv.getPoint(bbox.getTopLeft());
+            final Point bottomRight = mv.getPoint(bbox.getBottomRight());
+            final Rectangle rectangle = new Rectangle(upperLeft.x, upperLeft.y,
+                    bottomRight.x - upperLeft.x, bottomRight.y - upperLeft.y);
+            g.setColor(Color.RED);
+            g.draw(rectangle);
+        });
     }
 
     @Override
@@ -151,6 +177,38 @@ public class ElevationGridLayer extends Layer implements TileLoaderListener {
         g.drawString(text, x, y);
     }
 
+    @Override
+    public void mouseClicked(MouseEvent e) {
+        if (e.getButton() == MouseEvent.BUTTON1) {
+            this.clickLocation = MainApplication.getMap().mapView.getLatLon(e.getX(), e.getY());
+            final double elevation = ElevationHelper.getSrtmElevation(clickLocation);
+            Notification notification = new Notification("Elevation is: " + elevation);
+            notification.setDuration(Notification.TIME_SHORT);
+            GuiHelper.runInEDT(notification::show);
+            GuiHelper.runInEDT(this::invalidate);
+        }
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e) {
+        // Do nothing
+    }
+
+    @Override
+    public void mouseReleased(MouseEvent e) {
+        // Do nothing
+    }
+
+    @Override
+    public void mouseEntered(MouseEvent e) {
+        // Do nothing
+    }
+
+    @Override
+    public void mouseExited(MouseEvent e) {
+        // Do nothing
+    }
+
     private class TileSet {
         int x0, x1, y0, y1;
         int tileMax = -1;
@@ -223,4 +281,11 @@ public class ElevationGridLayer extends Layer implements TileLoaderListener {
             return this.tilesSpanned() > 200;
         }
     }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        HgtReader.clearCache();
+        MainApplication.getMap().mapView.removeMouseListener(this);
+    }
 }
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTile.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTile.java
index a21720fd4..390f17cc3 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTile.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTile.java
@@ -9,7 +9,6 @@ import java.awt.Point;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.List;
 import java.util.concurrent.BlockingDeque;
 import java.util.concurrent.LinkedBlockingDeque;
 
@@ -54,8 +53,7 @@ public class ElevationGridTile extends Tile {
 
     /**
      * Paints the vertices of this tile.
-     *
-     * @param g the graphics context
+     *  @param g the graphics context
      * @param mv the map view
      * @param vertexRenderer the vertex renderer
      */
@@ -66,7 +64,6 @@ public class ElevationGridTile extends Tile {
             Point p1 = mv.getPoint(eleVertex.get(1));
             Point p2 = mv.getPoint(eleVertex.get(2));
             Triangle shape = new Triangle(p0, p1, p2);
-
             // obtain vertex color
             g.setColor(vertexRenderer.getElevationColor(eleVertex));
             // TODO: Move to renderer
@@ -82,16 +79,13 @@ public class ElevationGridTile extends Tile {
 
         // We abuse the loadImage method to render the vertices...
         //
-        while (toDo.size() > 0) {
+        while (!toDo.isEmpty()) {
             EleVertex vertex = toDo.poll();
 
             if (vertex.isFinished()) {
                 vertices.add(vertex);
             } else {
-                List<EleVertex> newV = vertex.divide();
-                for (EleVertex eleVertex : newV) {
-                    toDo.add(eleVertex);
-                }
+                toDo.addAll(vertex.divide());
             }
         }
         setLoaded(true);
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTileLoader.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTileLoader.java
index fccb15e1a..7bd5ef08b 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTileLoader.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTileLoader.java
@@ -1,59 +1,112 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.plugins.elevation.grid;
 
+import java.io.IOException;
+import java.net.URL;
+import java.util.Optional;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.apache.commons.jcs3.access.behavior.ICacheAccess;
 import org.openstreetmap.gui.jmapviewer.Tile;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
-import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
+import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
+import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
+import org.openstreetmap.josm.data.cache.JCSCachedTileLoaderJob;
+import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
+import org.openstreetmap.josm.data.imagery.TileJobOptions;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
 /**
  * @author Olli
  *
  */
-public class ElevationGridTileLoader implements TileLoader {
-    protected TileLoaderListener listener;
+public class ElevationGridTileLoader extends TMSCachedTileLoader {
 
-    public ElevationGridTileLoader(TileLoaderListener listener) {
-        CheckParameterUtil.ensureParameterNotNull(listener);
-        this.listener = listener;
-    }
+    class ElevationGridTileJob extends JCSCachedTileLoaderJob<String, BufferedImageCacheEntry> implements TileJob {
 
-    @Override
-    public TileJob createTileLoaderJob(final Tile tile) {
-        CheckParameterUtil.ensureParameterNotNull(tile);
+        private final Tile tile;
+        private final TileLoaderListener listener;
+        private final ICacheAccess<String, BufferedImageCacheEntry> cache;
 
-        return new TileJob() {
-
-            @Override
-            public void run() {
-                synchronized (tile) {
-                    if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading())
-                        return;
-                    tile.initLoading();
-                }
-                try {
-                    tile.loadImage(null);
-                    tile.setLoaded(true);
-                    listener.tileLoadingFinished(tile, true);
-                } catch (Exception e) {
-                    tile.setError(e.getMessage());
-                    listener.tileLoadingFinished(tile, false);
-                } finally {
-                    tile.finishLoading();
-                }
-            }
+        protected ElevationGridTileJob(TileLoaderListener listener, Tile tile, ICacheAccess<String, BufferedImageCacheEntry> cache, TileJobOptions options,
+                ThreadPoolExecutor downloadJobExecutor) {
+            super(cache, options, downloadJobExecutor);
+            this.cache = cache;
+            this.tile = tile;
+            this.listener = listener;
+        }
 
-            @Override
-            public void submit() {
-                run();
+        @Override
+        public void run() {
+            synchronized (tile) {
+                if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading())
+                    return;
+                tile.initLoading();
+            }
+            try {
+                tile.loadImage(null);
+                tile.setLoaded(true);
+                listener.tileLoadingFinished(tile, true);
+            } catch (Exception e) {
+                tile.setError(e.getMessage());
+                listener.tileLoadingFinished(tile, false);
+            } finally {
+                tile.finishLoading();
             }
+        }
+
+        @Override
+        public void submit() {
+            run();
+        }
 
-            @Override
-            public void submit(boolean force) {
-                submit();
+        @Override
+        public void submit(boolean force) {
+            submit();
+        }
+
+        @Override
+        public String getCacheKey() {
+            if (tile != null) {
+                TileSource tileSource = tile.getTileSource();
+                return Optional.ofNullable(tileSource.getName()).orElse("").replace(':', '_') + ':'
+                        + tileSource.getTileId(tile.getZoom(), tile.getXtile(), tile.getYtile());
             }
-        };
+            return null;
+        }
+
+        @Override
+        public URL getUrl() throws IOException {
+            return new URL(String.format("http://localhost/elevation/%d/%d", tile.getTileXY().getXIndex(), tile.getTileXY().getYIndex()));
+        }
+
+        @Override
+        protected BufferedImageCacheEntry createCacheEntry(byte[] content) {
+            return new BufferedImageCacheEntry(content);
+        }
+    }
+
+    /**
+     * Constructor
+     * @param listener          called when tile loading has finished
+     * @param cache             of the cache
+     * @param options           tile job options
+     */
+    public ElevationGridTileLoader(TileLoaderListener listener, ICacheAccess<String, BufferedImageCacheEntry> cache,
+           TileJobOptions options) {
+        super(listener, cache, options);
+    }
+
+    @Override
+    public TileJob createTileLoaderJob(final Tile tile) {
+        CheckParameterUtil.ensureParameterNotNull(tile);
+
+        return new ElevationGridTileJob(listener,
+                tile,
+                cache,
+                options,
+                getDownloadExecutor());
     }
 
     @Override
diff --git a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfilePanel.java b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfilePanel.java
index 5d4dfd458..a45483432 100644
--- a/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfilePanel.java
+++ b/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfilePanel.java
@@ -15,8 +15,8 @@ import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionListener;
 import java.text.Format;
 import java.text.SimpleDateFormat;
+import java.time.Instant;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
 import javax.swing.BorderFactory;
@@ -253,10 +253,9 @@ public class ElevationProfilePanel extends JPanel implements ComponentListener,
     /**
      * Formats the date in a predefined manner: "21. Oct 2010, 12:10".
      */
-    private String formatDate(Date date) {
+    private String formatDate(Instant date) {
         Format formatter = new SimpleDateFormat("d MMM yy, HH:mm");
-
-        return formatter.format(date);
+        return formatter.format(date.toEpochMilli());
     }
 
     /**
