package tim.prune.gui.map;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import tim.prune.GpsPrune;
/**
* Class to asynchronously download a tile from a url
* and populate an Image object with the contents
*/
public class TileDownloader implements Runnable
{
private MapTileManager _manager = null;
private URL _url = null;
private int _layer = 0;
private int _x = 0, _y = 0;
private int _zoom = 0;
/** Hashset of all blocked / 404 tiles to avoid requesting them again */
private static final HashSet<String> BLOCKED_URLS = new HashSet<String>();
/** Hashset of all currently loading tiles to avoid requesting them again */
private static final HashSet<String> LOADING_URLS = new HashSet<String>();
/**
* Constructor (private)
* @param inManager parent manager for callback
* @param inUrl URL to load
* @param inLayer layer index from 0
* @param inX x coordinate of tile
* @param inY y coordinate of tile
* @param inZoom zoom level
*/
private TileDownloader(MapTileManager inManager, URL inUrl, int inLayer, int inX, int inY, int inZoom)
{
_manager = inManager;
_url = inUrl;
_layer = inLayer;
_x = inX; _y = inY;
_zoom = inZoom;
}
/**
* Trigger a download in a new thread
* @param inManager manager to callback when image is loaded
* @param inUrl URL to load
* @param inLayer layer index from 0
* @param inX x coordinate of tile
* @param inY y coordinate of tile
* @param inZoom current zoom level
*/
public static synchronized void triggerLoad(MapTileManager inManager, URL inUrl, int inLayer,
int inX, int inY, int inZoom)
{
if (inManager != null && inUrl != null)
{
String url = inUrl.toString();
// System.out.println("Trigger load: " + url);
if (!BLOCKED_URLS.contains(url) && !LOADING_URLS.contains(url))
{
// System.out.println("Not blocked: " + url);
LOADING_URLS.add(url);
new Thread(new TileDownloader(inManager, inUrl, inLayer, inX, inY, inZoom)).start();
}
}
}
/**
* Run method, called in separate thread
*/
public void run()
{
InputStream in = null;
try
{
// System.out.println("TD Running thread to get: " + _url.toString());
// Set http user agent on connection
URLConnection conn = _url.openConnection();
conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
in = conn.getInputStream();
int len = conn.getContentLength();
if (len > 0)
{
byte[] data = new byte[len];
int totalRead = 0;
while (totalRead < len)
{
int numRead = in.read(data, totalRead, len-totalRead);
totalRead += numRead;
}
Image tile = Toolkit.getDefaultToolkit().createImage(data);
in.close();
// Pass back to manager so it can be stored in its memory cache
_manager.notifyImageLoaded(tile, _layer, _x, _y, _zoom);
}
}
catch (IOException e)
{
System.err.println("IOE: " + e.getClass().getName() + " - " + e.getMessage());
synchronized(this.getClass())
{
BLOCKED_URLS.add(_url.toString());
}
try {in.close();} catch (Exception e2) {}
}
LOADING_URLS.remove(_url.toString());
}
}