--- /dev/null
+package tim.prune.gui.map;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.ImageObserver;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import tim.prune.config.Config;
+
+/**
+ * Class responsible for managing the map tiles,
+ * including invoking the correct memory cacher(s) and/or disk cacher(s)
+ */
+public class MapTileManager implements ImageObserver
+{
+ /** Parent object to inform when tiles received */
+ private MapCanvas _parent = null;
+ /** Current map source */
+ private MapSource _mapSource = null;
+ /** Array of tile caches, one per layer */
+ private MemTileCacher[] _tempCaches = null;
+ /** Number of layers */
+ private int _numLayers = -1;
+ /** Current zoom level */
+ private int _zoom = 0;
+
+
+ /**
+ * Constructor
+ * @param inParent parent canvas to be informed of updates
+ */
+ public MapTileManager(MapCanvas inParent)
+ {
+ _parent = inParent;
+ resetConfig();
+ }
+
+ /**
+ * Recentre the map
+ * @param inZoom zoom level
+ * @param inTileX x coord of central tile
+ * @param inTileY y coord of central tile
+ */
+ public void centreMap(int inZoom, int inTileX, int inTileY)
+ {
+ _zoom = inZoom;
+ // Pass params onto all memory cachers
+ if (_tempCaches != null) {
+ for (int i=0; i<_tempCaches.length; i++) {
+ _tempCaches[i].centreMap(inZoom, inTileX, inTileY);
+ }
+ }
+ }
+
+ /**
+ * @return true if zoom is too high for tiles
+ */
+ public boolean isOverzoomed()
+ {
+ // Ask current map source what maximum zoom is
+ int maxZoom = (_mapSource == null?0:_mapSource.getMaxZoomLevel());
+ return (_zoom > maxZoom);
+ }
+
+ /**
+ * Clear all the memory caches due to changed config / zoom
+ */
+ public void clearMemoryCaches()
+ {
+ int numLayers = _mapSource.getNumLayers();
+ if (_tempCaches == null || _tempCaches.length != numLayers) {
+ // Ccahers don't match, so need to create the right number of them
+ _tempCaches = new MemTileCacher[numLayers];
+ for (int i=0; i<numLayers; i++) {
+ _tempCaches[i] = new MemTileCacher();
+ }
+ }
+ else {
+ // Cachers already there, just need to be cleared
+ for (int i=0; i<numLayers; i++) {
+ _tempCaches[i].clearAll();
+ }
+ }
+ }
+
+ /**
+ * Reset the map source configuration, apparently it has changed
+ */
+ public void resetConfig()
+ {
+ int sourceNum = Config.getConfigInt(Config.KEY_MAPSOURCE_INDEX);
+ _mapSource = MapSourceLibrary.getSource(sourceNum);
+ if (_mapSource == null) {_mapSource = MapSourceLibrary.getSource(0);}
+ clearMemoryCaches();
+ _numLayers = _mapSource.getNumLayers();
+ }
+
+ /**
+ * @return the number of layers in the map
+ */
+ public int getNumLayers()
+ {
+ return _numLayers;
+ }
+
+ /**
+ * @param inLayer layer number, starting from 0
+ * @param inX x index of tile
+ * @param inY y index of tile
+ * @return selected tile if already loaded, or null otherwise
+ */
+ public Image getTile(int inLayer, int inX, int inY)
+ {
+ // Check first in memory cache for tile
+ MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
+ Image tile = tempCache.getTile(inX, inY);
+ if (tile != null) {
+ return tile;
+ }
+
+ // Tile wasn't in memory, but maybe it's in disk cache (if there is one)
+ String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
+ boolean useDisk = (diskCachePath != null);
+ boolean onlineMode = Config.getConfigBoolean(Config.KEY_ONLINE_MODE);
+ if (useDisk)
+ {
+ tile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), onlineMode);
+ if (tile != null) {
+ // Pass tile to memory cache
+ tempCache.setTile(tile, inX, inY);
+ if (tile.getWidth(this) > 0) {return tile;}
+ return null;
+ }
+ }
+ // Tile wasn't in memory or on disk, so if online let's get it
+ if (onlineMode)
+ {
+ try
+ {
+ URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
+ if (useDisk) {
+ // Copy image directly from URL stream to disk cache
+ DiskTileCacher.saveTile(tileUrl, diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this);
+ }
+ else {
+ // Load image asynchronously, using observer
+ tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
+ // Pass to memory cache
+ _tempCaches[inLayer].setTile(tile, inX, inY);
+ if (tile.getWidth(this) > 0) {return tile;}
+ }
+ }
+ catch (MalformedURLException urle) {} // ignore
+ }
+ return null;
+ }
+
+ /**
+ * Method called by image loader to inform of updates to the tiles
+ * @param img the image
+ * @param infoflags flags describing how much of the image is known
+ * @param x ignored
+ * @param y ignored
+ * @param width ignored
+ * @param height ignored
+ * @return false to carry on loading, true to stop
+ */
+ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
+ {
+ boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
+ boolean error = (infoflags & ImageObserver.ERROR) > 0;
+ if (loaded || error) {
+ _parent.tilesUpdated(loaded);
+ }
+ return !loaded;
+ }
+}