/*******************************************************************************
* Copyright (c) MOBAC developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package mobac.mapsources;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.imageio.ImageIO;
import mobac.exceptions.MapSourceInitializationException;
import mobac.exceptions.TileException;
import mobac.gui.mapview.JMapViewer;
import mobac.mapsources.mapspace.MercatorPower2MapSpace;
import mobac.program.download.TileDownLoader;
import mobac.program.interfaces.HttpMapSource;
import mobac.program.interfaces.MapSource;
import mobac.program.interfaces.MapSourceListener;
import mobac.program.interfaces.MapSpace;
import mobac.program.model.MapSourceLoaderInfo;
import mobac.program.model.TileImageType;
import mobac.program.tilestore.TileStore;
import mobac.program.tilestore.TileStoreEntry;
import org.apache.log4j.Logger;
/**
* Abstract base class for map sources.
*/
public abstract class AbstractHttpMapSource implements HttpMapSource {
protected Logger log;
private boolean initialized = false;
protected String name;
protected int minZoom;
protected int maxZoom;
protected TileImageType tileType;
protected HttpMapSource.TileUpdate tileUpdate;
protected MapSpace mapSpace = MercatorPower2MapSpace.INSTANCE_256;
protected MapSourceLoaderInfo loaderInfo = null;
public AbstractHttpMapSource(String name, int minZoom, int maxZoom, TileImageType tileType) {
this(name, minZoom, maxZoom, tileType, HttpMapSource.TileUpdate.None);
}
/**
* Do not use - for JAXB only
*/
protected AbstractHttpMapSource() {
}
public AbstractHttpMapSource(String name, int minZoom, int maxZoom, TileImageType tileType,
HttpMapSource.TileUpdate tileUpdate) {
log = Logger.getLogger(this.getClass());
this.name = name;
this.minZoom = minZoom;
this.maxZoom = Math.min(maxZoom, JMapViewer.MAX_ZOOM);
this.tileType = tileType;
this.tileUpdate = tileUpdate;
}
public boolean ignoreContentMismatch()
{
return false;
}
public HttpURLConnection getTileUrlConnection(int zoom, int tilex, int tiley) throws IOException {
String url = getTileUrl(zoom, tilex, tiley);
if (url == null)
return null;
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
prepareTileUrlConnection(conn);
return conn;
}
protected void prepareTileUrlConnection(HttpURLConnection conn) {
// Derived classes may override this method
}
public abstract String getTileUrl(int zoom, int tilex, int tiley);
/**
* Can be used to e.g. retrieve the url pattern before the first call
*/
protected final void initializeHttpMapSource() {
if (initialized)
return;
// Prevent multiple initializations in case of multi-threaded access
try {
synchronized (this) {
if (initialized)
// Another thread has already completed initialization while this one was blocked
return;
initernalInitialize();
initialized = true;
log.debug("Map source has been initialized");
}
} catch (Exception e) {
log.error("Map source initialization failed: " + e.getMessage(), e);
// TODO: inform user
}
initialized = true;
}
protected void initernalInitialize() throws MapSourceInitializationException {
}
public byte[] getTileData(int zoom, int x, int y, LoadMethod loadMethod) throws IOException, TileException,
InterruptedException {
if (loadMethod == LoadMethod.CACHE) {
TileStoreEntry entry = TileStore.getInstance().getTile(x, y, zoom, this);
if (entry == null)
return null;
byte[] data = entry.getData();
if (Thread.currentThread() instanceof MapSourceListener) {
((MapSourceListener) Thread.currentThread()).tileDownloaded(data.length);
}
return data;
} else if (loadMethod == LoadMethod.SOURCE) {
initializeHttpMapSource();
return TileDownLoader.downloadTileAndUpdateStore(x, y, zoom, this);
} else {
initializeHttpMapSource();
return TileDownLoader.getImage(x, y, zoom, this);
}
}
public BufferedImage getTileImage(int zoom, int x, int y, LoadMethod loadMethod) throws IOException, TileException,
InterruptedException {
byte[] data = getTileData(zoom, x, y, loadMethod);
if (data == null)
return null;
return ImageIO.read(new ByteArrayInputStream(data));
}
public int getMaxZoom() {
return maxZoom;
}
public int getMinZoom() {
return minZoom;
}
public String getName() {
return name;
}
public String getStoreName() {
return name;
}
@Override
public String toString() {
return name;
}
public TileImageType getTileImageType() {
return tileType;
}
public HttpMapSource.TileUpdate getTileUpdate() {
return tileUpdate;
}
public boolean allowFileStore() {
return true;
}
public MapSpace getMapSpace() {
return mapSpace;
}
public Color getBackgroundColor() {
return Color.BLACK;
}
public MapSourceLoaderInfo getLoaderInfo() {
return loaderInfo;
}
public void setLoaderInfo(MapSourceLoaderInfo loaderInfo) {
if (this.loaderInfo != null)
throw new RuntimeException("LoaderInfo already set");
this.loaderInfo = loaderInfo;
}
@Override
public int hashCode() {
return getName().hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof MapSource))
return false;
MapSource other = (MapSource) obj;
return other.getName().equals(getName());
}
@Override
public boolean getHiddenDefault() {
return false;
}
}