Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java	(revision 31301)
@@ -16,4 +16,5 @@
 
 import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 public class AttributionSupport {
@@ -53,5 +54,5 @@
     }
 
-    public void paintAttribution(Graphics g, int width, int height, Coordinate topLeft, Coordinate bottomRight, int zoom, ImageObserver observer) {
+    public void paintAttribution(Graphics g, int width, int height, ICoordinate topLeft, ICoordinate bottomRight, int zoom, ImageObserver observer) {
         if (source == null || !source.requiresAttribution()) {
             attrToUBounds = null;
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java	(revision 31301)
@@ -191,5 +191,5 @@
      *            {@link #MIN_ZOOM} &lt;= zoom level &lt;= {@link #MAX_ZOOM}
      */
-    public void setDisplayPosition(Coordinate to, int zoom) {
+    public void setDisplayPosition(ICoordinate to, int zoom) {
         setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), to, zoom);
     }
@@ -209,8 +209,7 @@
      *            {@link TileSource#getMaxZoom()}
      */
-    public void setDisplayPosition(Point mapPoint, Coordinate to, int zoom) {
-        int x = tileSource.LonToX(to.getLon(), zoom);
-        int y = tileSource.LatToY(to.getLat(), zoom);
-        setDisplayPosition(mapPoint, x, y, zoom);
+    public void setDisplayPosition(Point mapPoint, ICoordinate to, int zoom) {
+        Point p = tileSource.latLonToXY(to, zoom);
+        setDisplayPosition(mapPoint, p.x, p.y, zoom);
     }
 
@@ -268,10 +267,9 @@
                 for (MapMarker marker : mapMarkerList) {
                     if (marker.isVisible()) {
-                        int x = tileSource.LonToX(marker.getLon(), mapZoomMax);
-                        int y = tileSource.LatToY(marker.getLat(), mapZoomMax);
-                        x_max = Math.max(x_max, x);
-                        y_max = Math.max(y_max, y);
-                        x_min = Math.min(x_min, x);
-                        y_min = Math.min(y_min, y);
+                        Point p = tileSource.latLonToXY(marker.getCoordinate(), mapZoomMax);
+                        x_max = Math.max(x_max, p.x);
+                        y_max = Math.max(y_max, p.y);
+                        x_min = Math.min(x_min, p.x);
+                        y_min = Math.min(y_min, p.y);
                     }
                 }
@@ -283,8 +281,10 @@
                 for (MapRectangle rectangle : mapRectangleList) {
                     if (rectangle.isVisible()) {
-                        x_max = Math.max(x_max, tileSource.LonToX(rectangle.getBottomRight().getLon(), mapZoomMax));
-                        y_max = Math.max(y_max, tileSource.LatToY(rectangle.getTopLeft().getLat(), mapZoomMax));
-                        x_min = Math.min(x_min, tileSource.LonToX(rectangle.getTopLeft().getLon(), mapZoomMax));
-                        y_min = Math.min(y_min, tileSource.LatToY(rectangle.getBottomRight().getLat(), mapZoomMax));
+                        Point bottomRight = tileSource.latLonToXY(rectangle.getBottomRight(), mapZoomMax);
+                        Point topLeft = tileSource.latLonToXY(rectangle.getTopLeft(), mapZoomMax);
+                        x_max = Math.max(x_max, bottomRight.x);
+                        y_max = Math.max(y_max, topLeft.y);
+                        x_min = Math.min(x_min, topLeft.x);
+                        y_min = Math.min(y_min, bottomRight.y);
                     }
                 }
@@ -297,10 +297,9 @@
                     if (polygon.isVisible()) {
                         for (ICoordinate c : polygon.getPoints()) {
-                            int x = tileSource.LonToX(c.getLon(), mapZoomMax);
-                            int y = tileSource.LatToY(c.getLat(), mapZoomMax);
-                            x_max = Math.max(x_max, x);
-                            y_max = Math.max(y_max, y);
-                            x_min = Math.min(x_min, x);
-                            y_min = Math.min(y_min, y);
+                            Point p = tileSource.latLonToXY(c, mapZoomMax);
+                            x_max = Math.max(x_max, p.x);
+                            y_max = Math.max(y_max, p.y);
+                            x_min = Math.min(x_min, p.x);
+                            y_min = Math.min(y_min, p.y);
                         }
                     }
@@ -368,8 +367,6 @@
      * @return latitude / longitude
      */
-    public Coordinate getPosition() {
-        double lon = tileSource.XToLon(center.x, zoom);
-        double lat = tileSource.YToLat(center.y, zoom);
-        return new Coordinate(lat, lon);
+    public ICoordinate getPosition() {
+        return tileSource.XYToLatLon(center, zoom);
     }
 
@@ -383,5 +380,5 @@
      * @return latitude / longitude
      */
-    public Coordinate getPosition(Point mapPoint) {
+    public ICoordinate getPosition(Point mapPoint) {
         return getPosition(mapPoint.x, mapPoint.y);
     }
@@ -395,10 +392,8 @@
      * @return latitude / longitude
      */
-    public Coordinate getPosition(int mapPointX, int mapPointY) {
+    public ICoordinate getPosition(int mapPointX, int mapPointY) {
         int x = center.x + mapPointX - getWidth() / 2;
         int y = center.y + mapPointY - getHeight() / 2;
-        double lon = tileSource.XToLon(x, zoom);
-        double lat = tileSource.YToLat(y, zoom);
-        return new Coordinate(lat, lon);
+        return tileSource.XYToLatLon(x, y, zoom);
     }
 
@@ -413,13 +408,31 @@
      */
     public Point getMapPosition(double lat, double lon, boolean checkOutside) {
-        int x = tileSource.LonToX(lon, zoom);
-        int y = tileSource.LatToY(lat, zoom);
-        x -= center.x - getWidth() / 2;
-        y -= center.y - getHeight() / 2;
+        Point p = tileSource.latLonToXY(lat, lon, zoom);
+        p.translate(-(center.x - getWidth() / 2), -(center.y - getHeight() /2));
+
         if (checkOutside) {
-            if (x < 0 || y < 0 || x > getWidth() || y > getHeight())
+            if (p.x < 0 || p.y < 0 || p.x > getWidth() || p.y > getHeight())
                 return null;
         }
-        return new Point(x, y);
+        return p;
+    }
+
+    /**
+     * Calculates the position on the map of a given coordinate
+     *
+     * @param lat Latitude
+     * @param lon longitude
+     * @param offset Offset respect Latitude
+     * @param checkOutside
+     * @return Integer the radius in pixels
+     */
+    public Integer getLatOffset(double lat, double lon, double offset, boolean checkOutside) {
+        Point p = tileSource.latLonToXY(lat, lon, zoom);
+        int y = p.y - center.y - getHeight() / 2;
+        if (checkOutside) {
+            if (y < 0 || y > getHeight())
+                return null;
+        }
+        return y;
     }
 
@@ -432,4 +445,5 @@
      * @return Integer the radius in pixels
      */
+    @Deprecated
     public Integer getLatOffset(double lat, double offset, boolean checkOutside) {
         int y = tileSource.LatToY(lat + offset, zoom);
@@ -463,5 +477,5 @@
             return (int) marker.getRadius();
         else if (p != null) {
-            Integer radius = getLatOffset(marker.getLat(), marker.getRadius(), false);
+            Integer radius = getLatOffset(marker.getLat(), marker.getLon(), marker.getRadius(), false);
             radius = radius == null ? null : p.y - radius.intValue();
             return radius;
@@ -509,6 +523,6 @@
         double pDistance = center.distance(origin);
 
-        Coordinate originCoord = getPosition(origin);
-        Coordinate centerCoord = getPosition(center);
+        ICoordinate originCoord = getPosition(origin);
+        ICoordinate centerCoord = getPosition(center);
 
         double mDistance = tileSource.getDistance(originCoord.getLat(), originCoord.getLon(),
@@ -826,5 +840,5 @@
                 || zoom == this.zoom)
             return;
-        Coordinate zoomPos = getPosition(mapPoint);
+        ICoordinate zoomPos = getPosition(mapPoint);
         tileController.cancelOutstandingJobs(); // Clearing outstanding load
         // requests
@@ -971,5 +985,5 @@
         if (tileSource.getMinZoom() < MIN_ZOOM)
             throw new RuntimeException("Minimum zoom level too low");
-        Coordinate position = getPosition();
+        ICoordinate position = getPosition();
         this.tileSource = tileSource;
         tileController.setTileSource(tileSource);
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/TileXY.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/TileXY.java	(revision 31301)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/TileXY.java	(revision 31301)
@@ -0,0 +1,57 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.gui.jmapviewer;
+
+/**
+ * @author w
+ *
+ */
+public class TileXY {
+    /**
+     * x index of the tile (horizontal)
+     */
+    private double x;
+    /**
+     * y number of the tile (vertical)
+     */
+    private double y;
+
+    /**
+     * Returns an instance of coordinates.
+     *
+     * @param d number of the tile
+     * @param e number of the tile
+     */
+    public TileXY(double d, double e) {
+        this.x = d;
+        this.y = e;
+    }
+
+    /**
+     * @return x index of the tile as integer
+     */
+    public int getXIndex() {
+        return x < 0 ? (int) Math.ceil(x) : (int) Math.floor(x);
+    }
+
+    /**
+     * @return y index of the tile as integer
+     */
+    public int getYIndex() {
+        return y < 0 ? (int) Math.ceil(x) : (int) Math.floor(y);
+    }
+
+    /**
+     * @return x index as double, might be non integral, when the point is not topleft corner of the tile
+     */
+    public double getX() {
+        return x;
+    }
+
+    /**
+     * @return y index as double, might be non integral, when the point is not topleft corner of the tile
+     */
+    public double getY() {
+        return y;
+    }
+
+}
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java	(revision 31301)
@@ -3,6 +3,4 @@
 
 import java.awt.Image;
-
-import org.openstreetmap.gui.jmapviewer.Coordinate;
 
 public interface Attributed {
@@ -18,5 +16,5 @@
      * @return Attribution text for the image source.
      */
-    String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight);
+    String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight);
 
     /**
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java	(revision 31301)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java	(revision 31301)
@@ -0,0 +1,18 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.gui.jmapviewer.interfaces;
+
+import java.util.Map;
+
+/**
+ * Interface for template tile sources, @see TemplatedTMSTileSource
+ *
+ * @author Wiktor Niesiobędzki
+ * @since TODO
+ */
+public interface TemplatedTileSource extends TileSource {
+    /**
+     *
+     * @return headers to be sent with http requests
+     */
+    public Map<String, String> getHeaders();
+}
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java	(revision 31301)
@@ -2,4 +2,5 @@
 package org.openstreetmap.gui.jmapviewer.interfaces;
 
+import java.awt.Point;
 import java.io.IOException;
 import java.util.List;
@@ -7,4 +8,6 @@
 
 import org.openstreetmap.gui.jmapviewer.JMapViewer;
+import org.openstreetmap.gui.jmapviewer.Tile;
+import org.openstreetmap.gui.jmapviewer.TileXY;
 
 /**
@@ -36,4 +39,5 @@
      *
      */
+    @Deprecated //not used anymore
     public enum TileUpdate {
         IfNoneMatch, ETag, IfModifiedSince, LastModified, None
@@ -93,20 +97,22 @@
 
     /**
-     * Specifies the tile image type. For tiles rendered by Mapnik or
-     * Osmarenderer this is usually <code>"png"</code>.
-     *
-     * @return file extension of the tile image type
-     */
-    String getTileType();
-
-    /**
      * Specifies how large each tile is.
-     * @return The size of a single tile in pixels.
+     * @return The size of a single tile in pixels. -1 if default size should be used
      */
     int getTileSize();
 
     /**
+     * @return default tile size, for this tile source
+     * TODO: @since
+     */
+    public int getDefaultTileSize();
+
+    /**
      * Gets the distance using Spherical law of cosines.
-     *  @return the distance, m.
+     * @param la1 latitude of first point
+     * @param lo1 longitude of first point
+     * @param la2 latitude of second point
+     * @param lo2 longitude of second point
+     * @return the distance betwen first and second point, in m.
      */
     double getDistance(double la1, double lo1, double la2, double lo2);
@@ -114,49 +120,140 @@
     /**
      * Transform longitude to pixelspace.
+     * @param aLongitude
+     * @param aZoomlevel
      * @return [0..2^Zoomlevel*TILE_SIZE[
      */
+    @Deprecated
     int LonToX(double aLongitude, int aZoomlevel);
 
     /**
      * Transforms latitude to pixelspace.
+     * @param aLat
+     * @param aZoomlevel
      * @return [0..2^Zoomlevel*TILE_SIZE[
-     */
+     * @deprecated use lonLatToXY instead
+     */
+    @Deprecated
     int LatToY(double aLat, int aZoomlevel);
 
     /**
+     * @param lon
+     * @param lat
+     * @param zoom
+     * @return transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined)
+     */
+    public Point latLonToXY(double lat, double lon, int zoom);
+
+    public Point latLonToXY(ICoordinate point, int zoom);
+
+    /**
      * Transforms pixel coordinate X to longitude
+     * @param aX
+     * @param aZoomlevel
      * @return ]-180..180[
      */
+    @Deprecated
     double XToLon(int aX, int aZoomlevel);
 
     /**
      * Transforms pixel coordinate Y to latitude.
+     * @param aY
+     * @param aZoomlevel
      * @return [MIN_LAT..MAX_LAT]
      */
+    @Deprecated
     double YToLat(int aY, int aZoomlevel);
 
     /**
+     * @param point
+     * @param zoom
+     * @return WGS84 Coordinates of given point
+     */
+    public ICoordinate XYToLatLon(Point point, int zoom);
+
+    public ICoordinate XYToLatLon(int x, int y, int zoom);
+
+    /**
      * Transforms longitude to X tile coordinate.
+     * @param lon
+     * @param zoom
      * @return [0..2^Zoomlevel[
      */
+    @Deprecated
     double lonToTileX(double lon, int zoom);
 
     /**
      * Transforms latitude to Y tile coordinate.
+     * @param lat
+     * @param zoom
      * @return [0..2^Zoomlevel[
      */
+    @Deprecated
     double latToTileY(double lat, int zoom);
 
     /**
+     * @param lon
+     * @param lat
+     * @param zoom
+     * @return x and y tile indices
+     */
+    public TileXY latLonToTileXY(double lat, double lon, int zoom);
+
+    public TileXY latLonToTileXY(ICoordinate point, int zoom);
+
+    /**
      * Transforms tile X coordinate to longitude.
+     * @param x
+     * @param zoom
      * @return ]-180..180[
      */
+    @Deprecated
     double tileXToLon(int x, int zoom);
 
     /**
      * Transforms tile Y coordinate to latitude.
+     * @param y
+     * @param zoom
      * @return [MIN_LAT..MAX_LAT]
      */
+    @Deprecated
     double tileYToLat(int y, int zoom);
+
+    /**
+     * @param xy
+     * @param zoom
+     * @return WGS84 coordinates of given tile
+     */
+    public ICoordinate tileXYToLatLon(TileXY xy, int zoom);
+
+    public ICoordinate tileXYToLatLon(Tile tile);
+
+    public ICoordinate tileXYToLatLon(int x, int y, int zoom);
+
+    /**
+     * @param zoom
+     * @return maximum X index of tile for specified zoom level
+     */
+    public int getTileXMax(int zoom);
+
+    /**
+     *
+     * @param zoom
+     * @return minimum X index of tile for specified zoom level
+     */
+    public int getTileXMin(int zoom);
+
+    /**
+     *
+     * @param zoom
+     * @return maximum Y index of tile for specified zoom level
+     */
+    public int getTileYMax(int zoom);
+
+    /**
+     * @param zoom
+     * @return minimum Y index of tile for specified zoom level
+     */
+    public int getTileYMin(int zoom);
 
     /**
@@ -178,3 +275,5 @@
      */
     public Map<String, String> getMetadata(Map<String, List<String>> headers);
+
+
 }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java	(revision 31301)
@@ -4,5 +4,5 @@
 import java.awt.Image;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 /**
@@ -39,5 +39,5 @@
 
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
         return DEFAULT_OSM_ATTRIBUTION;
     }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java	(revision 31301)
@@ -2,4 +2,5 @@
 package org.openstreetmap.gui.jmapviewer.tilesources;
 
+import java.awt.Point;
 import java.io.IOException;
 import java.util.HashMap;
@@ -8,6 +9,16 @@
 import java.util.Map.Entry;
 
+import org.openstreetmap.gui.jmapviewer.Coordinate;
 import org.openstreetmap.gui.jmapviewer.OsmMercator;
-
+import org.openstreetmap.gui.jmapviewer.Tile;
+import org.openstreetmap.gui.jmapviewer.TileXY;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
+
+/**
+ * Class generalizing all tile based tile sources
+ *
+ * @author Wiktor Niesiobędzki
+ *
+ */
 public abstract class AbstractTMSTileSource extends AbstractTileSource {
 
@@ -20,4 +31,9 @@
     protected OsmMercator osmMercator;
 
+    /**
+     * Creates an instance based on TileSource information
+     *
+     * @param info description of the Tile Source
+     */
     public AbstractTMSTileSource(TileSourceInfo info) {
         this.name = info.getName();
@@ -33,4 +49,11 @@
     }
 
+    /**
+     * @return default tile size to use, when not set in Imagery Preferences
+     */
+    public int getDefaultTileSize() {
+        return OsmMercator.DEFAUL_TILE_SIZE;
+    }
+
     @Override
     public String getName() {
@@ -53,4 +76,7 @@
     }
 
+    /**
+     * @return image extension, used for URL creation
+     */
     public String getExtension() {
         return "png";
@@ -58,4 +84,8 @@
 
     /**
+     * @param zoom level of the tile
+     * @param tilex tile number in x axis
+     * @param tiley tile number in y axis
+     * @return String containg path part of URL of the tile
      * @throws IOException when subclass cannot return the tile URL
      */
@@ -64,4 +94,7 @@
     }
 
+    /**
+     * @return Base part of the URL of the tile source
+     */
     public String getBaseUrl() {
         return this.baseUrl;
@@ -78,9 +111,4 @@
     }
 
-    @Override
-    public String getTileType() {
-        return "png";
-    }
-
     /*
      * Most tilesources use OsmMercator projection.
@@ -88,4 +116,7 @@
     @Override
     public int getTileSize() {
+        if (tileSize <= 0) {
+            return getDefaultTileSize();
+        }
         return tileSize;
     }
@@ -107,4 +138,17 @@
 
     @Override
+    public Point latLonToXY(double lat, double lon, int zoom) {
+        return new Point(
+                (int)osmMercator.LonToX(lon, zoom),
+                (int)osmMercator.LatToY(lat, zoom)
+                );
+    }
+
+    @Override
+    public Point latLonToXY(ICoordinate point, int zoom) {
+        return latLonToXY(point.getLat(), point.getLon(), zoom);
+    }
+
+    @Override
     public double XToLon(int x, int zoom) {
         return osmMercator.XToLon(x, zoom);
@@ -117,4 +161,17 @@
 
     @Override
+    public Coordinate XYToLatLon(Point point, int zoom) {
+        return XYToLatLon(point.x, point.y, zoom);
+    }
+
+    @Override
+    public Coordinate XYToLatLon(int x, int y, int zoom) {
+        return new Coordinate(
+                osmMercator.YToLat(y, zoom),
+                osmMercator.XToLon(x, zoom)
+                );
+    }
+
+    @Override
     public double latToTileY(double lat, int zoom) {
         return osmMercator.LatToY(lat, zoom) / tileSize;
@@ -127,4 +184,17 @@
 
     @Override
+    public TileXY latLonToTileXY(double lat, double lon, int zoom) {
+        return new TileXY(
+                osmMercator.LonToX(lon, zoom) / tileSize,
+                osmMercator.LatToY(lat, zoom) / tileSize
+                );
+    }
+
+    @Override
+    public TileXY latLonToTileXY(ICoordinate point, int zoom) {
+        return latLonToTileXY(point.getLat(), point.getLon(), zoom);
+    }
+
+    @Override
     public double tileYToLat(int y, int zoom) {
         return osmMercator.YToLat(y * tileSize, zoom);
@@ -135,4 +205,43 @@
         return osmMercator.XToLon(x * tileSize, zoom);
     }
+
+    @Override
+    public Coordinate tileXYToLatLon(TileXY xy, int zoom) {
+        return tileXYToLatLon(xy.getXIndex(), xy.getYIndex(), zoom);
+    }
+
+    @Override
+    public Coordinate tileXYToLatLon(Tile tile) {
+        return tileXYToLatLon(tile.getXtile(), tile.getYtile(), tile.getZoom());
+    }
+
+    @Override
+    public Coordinate tileXYToLatLon(int x, int y, int zoom) {
+        return new Coordinate(
+                osmMercator.YToLat(y * tileSize, zoom),
+                osmMercator.XToLon(x * tileSize, zoom)
+                );
+    }
+
+    @Override
+    public int getTileXMax(int zoom) {
+        return getTileMax(zoom);
+    }
+
+    @Override
+    public int getTileXMin(int zoom) {
+        return 0;
+    }
+
+    @Override
+    public int getTileYMax(int zoom) {
+        return getTileMax(zoom);
+    }
+
+    @Override
+    public int getTileYMin(int zoom) {
+        return 0;
+    }
+
 
     @Override
@@ -168,3 +277,7 @@
         return ret;
     }
+
+    private int getTileMax(int zoom) {
+        return (int)Math.pow(2.0, zoom) - 1;
+    }
 }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java	(revision 31301)
@@ -6,5 +6,5 @@
 import java.util.Map;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
 
@@ -24,5 +24,5 @@
 
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
         return attributionText;
     }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java	(revision 31301)
@@ -30,4 +30,5 @@
 import org.openstreetmap.gui.jmapviewer.Coordinate;
 import org.openstreetmap.gui.jmapviewer.JMapViewer;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
@@ -263,5 +264,5 @@
 
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
         try {
             final List<Attribution> data = getAttribution();
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOpenAerialTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOpenAerialTileSource.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOpenAerialTileSource.java	(revision 31301)
@@ -2,5 +2,5 @@
 package org.openstreetmap.gui.jmapviewer.tilesources;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 public class MapQuestOpenAerialTileSource extends AbstractMapQuestTileSource {
@@ -13,5 +13,5 @@
 
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
         return "Portions Courtesy NASA/JPL-Caltech and U.S. Depart. of Agriculture, Farm Service Agency - "+MAPQUEST_ATTRIBUTION;
     }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOsmTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOsmTileSource.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOsmTileSource.java	(revision 31301)
@@ -2,5 +2,5 @@
 package org.openstreetmap.gui.jmapviewer.tilesources;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 public class MapQuestOsmTileSource extends AbstractMapQuestTileSource {
@@ -13,6 +13,6 @@
     
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft,
-            Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft,
+            ICoordinate botRight) {
         return super.getAttributionText(zoom, topLeft, botRight)+" - "+MAPQUEST_ATTRIBUTION;
     }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java	(revision 31301)
@@ -8,5 +8,27 @@
 import java.util.regex.Pattern;
 
-public class TemplatedTMSTileSource extends TMSTileSource {
+import org.openstreetmap.gui.jmapviewer.interfaces.TemplatedTileSource;
+
+/**
+ * Handles templated TMS Tile Source. Templated means, that some patterns within
+ * URL gets substituted.
+ *
+ * Supported parameters
+ * {zoom} - substituted with zoom level
+ * {z} - as above
+ * {NUMBER-zoom} - substituted with result of equation "NUMBER - zoom",
+ *                  eg. {20-zoom} for zoom level 15 will result in 5 in this place
+ * {zoom+number} - substituted with result of equation "zoom + number",
+ *                 eg. {zoom+5} for zoom level 15 will result in 20.
+ * {x} - substituted with X tile number
+ * {y} - substituted with Y tile number
+ * {!y} - substituted with Yahoo Y tile number
+ * {-y} - substituted with reversed Y tile number
+ * {switch:VAL_A,VAL_B,VAL_C,...} - substituted with one of VAL_A, VAL_B, VAL_C. Usually
+ *                                  used to specify many tile servers
+ * {header:(HEADER_NAME,HEADER_VALUE)} - sets the headers to be sent to tile server
+ */
+
+public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTileSource {
 
     private Random rand = null;
@@ -14,18 +36,22 @@
     private Map<String, String> headers = new HashMap<>();
 
-    public static final String COOKIE_HEADER   = "Cookie";
-    public static final String PATTERN_ZOOM    = "\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}";
-    public static final String PATTERN_X       = "\\{x\\}";
-    public static final String PATTERN_Y       = "\\{y\\}";
-    public static final String PATTERN_Y_YAHOO = "\\{!y\\}";
-    public static final String PATTERN_NEG_Y   = "\\{-y\\}";
-    public static final String PATTERN_SWITCH  = "\\{switch:([^}]+)\\}";
-    public static final String PATTERN_HEADER  = "\\{header\\(([^,]+),([^}]+)\\)\\}";
+    private static final String COOKIE_HEADER   = "Cookie";
+    private static final String PATTERN_ZOOM    = "\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}";
+    private static final String PATTERN_X       = "\\{x\\}";
+    private static final String PATTERN_Y       = "\\{y\\}";
+    private static final String PATTERN_Y_YAHOO = "\\{!y\\}";
+    private static final String PATTERN_NEG_Y   = "\\{-y\\}";
+    private static final String PATTERN_SWITCH  = "\\{switch:([^}]+)\\}";
+    private static final String PATTERN_HEADER  = "\\{header\\(([^,]+),([^}]+)\\)\\}";
 
-    public static final String[] ALL_PATTERNS = {
+    private static final String[] ALL_PATTERNS = {
         PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y,
         PATTERN_SWITCH
     };
 
+    /**
+     * Creates Templated TMS Tile Source based on ImageryInfo
+     * @param info
+     */
     public TemplatedTMSTileSource(TileSourceInfo info) {
         super(info);
@@ -84,3 +110,25 @@
         return r;
     }
+
+    /**
+     * Checks if url is acceptable by this Tile Source
+     * @param url
+     */
+    public static void checkUrl(String url) {
+        assert url != null && !"".equals(url): "URL cannot be null or empty";
+        Matcher m = Pattern.compile("\\{[^}]*\\}").matcher(url);
+        while (m.find()) {
+            boolean isSupportedPattern = false;
+            for (String pattern : ALL_PATTERNS) {
+                if (m.group().matches(pattern)) {
+                    isSupportedPattern = true;
+                    break;
+                }
+            }
+            if (!isSupportedPattern) {
+                throw new IllegalArgumentException(
+                        m.group() + " is not a valid TMS argument. Please check this server URL:\n" + url);
+            }
+        }
+    }
 }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java	(revision 31293)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java	(revision 31301)
@@ -33,5 +33,5 @@
 
     /** tile size of the displayed tiles */
-    private int tileSize = OsmMercator.DEFAUL_TILE_SIZE;
+    private int tileSize = OsmMercator.DEFAUL_TILE_SIZE; // FIXME: set to -1 for next release
 
     /** mapping &lt;header key, metadata key&gt; */
@@ -116,5 +116,5 @@
     /**
      * Request tile size of this tile source
-     * @return tile size provided by this tile source
+     * @return tile size provided by this tile source, or -1 when default value should be used
      */
     public int getTileSize() {
@@ -127,5 +127,5 @@
      */
     public void setTileSize(int tileSize) {
-        if (tileSize <= 0) {
+        if (tileSize == 0 || tileSize < -1) {
             throw new AssertionError("Invalid tile size: " + tileSize);
         }
