/*******************************************************************************
* 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.custom;
import java.awt.Color;
import java.awt.Graphics;
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 javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlList;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import mobac.exceptions.UnrecoverableDownloadException;
import mobac.mapsources.MapSourceTools;
import mobac.mapsources.mapspace.MapSpaceFactory;
import mobac.program.download.TileDownLoader;
import mobac.program.interfaces.HttpMapSource;
import mobac.program.interfaces.MapSourceListener;
import mobac.program.interfaces.MapSpace;
import mobac.program.interfaces.MapSpace.MapSpaceType;
import mobac.program.jaxb.ColorAdapter;
import mobac.program.model.MapSourceLoaderInfo;
import mobac.program.model.TileImageType;
import mobac.program.tilestore.TileStore;
import mobac.program.tilestore.TileStoreEntry;
/**
* Custom tile store provider, configurable via settings.xml.
*/
@XmlRootElement
public class CustomMapSource implements HttpMapSource {
@XmlElement(nillable = false, defaultValue = "Custom")
private String name = "Custom";
@XmlElement(defaultValue = "0")
private int minZoom = 0;
@XmlElement(required = true)
private int maxZoom = 0;
@XmlElement(defaultValue = "PNG")
protected TileImageType tileType = TileImageType.PNG;
@XmlElement(defaultValue = "NONE")
private HttpMapSource.TileUpdate tileUpdate;
@XmlElement(required = true, nillable = false)
protected String url = "http://127.0.0.1/{$x}_{$y}_{$z}";
@XmlElement(defaultValue = "false")
private boolean invertYCoordinate = false;
@XmlElement(defaultValue = "#000000")
@XmlJavaTypeAdapter(ColorAdapter.class)
private Color backgroundColor = Color.BLACK;
@XmlElement(required = false, defaultValue = "false")
private boolean ignoreErrors = false;
@XmlElement(required = false, defaultValue = "")
@XmlList
private String[] serverParts = null;
private int currentServerPart = 0;
// @XmlElement(required = false, defaultValue = "false")
// protected boolean ignoreContentMismatch = false;
@XmlElement(defaultValue = "256")
private int tileSize = 256;
@XmlElement(defaultValue = "msMercatorSpherical")
private MapSpaceType mapSpaceType = MapSpaceType.msMercatorSpherical;
@XmlElement(defaultValue = "")
private String httpHeadReferer = "";
@XmlElement(defaultValue = "")
private String httpHeadUserAgent = "";
@XmlElement(defaultValue = "false")
private boolean hiddenDefault = false;
private MapSourceLoaderInfo loaderInfo = null;
/**
* Constructor without parameters - required by JAXB
*/
protected CustomMapSource() {
}
public CustomMapSource(String name, String url) {
this.name = name;
this.url = url;
}
// public boolean ignoreContentMismatch()
// {
// return ignoreContentMismatch;
// }
public TileUpdate getTileUpdate() {
return tileUpdate;
}
public int getMaxZoom() {
return maxZoom;
}
public int getMinZoom() {
return minZoom;
}
public String getName() {
return name;
}
public String getStoreName() {
return name;
}
public TileImageType getTileImageType() {
return tileType;
}
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();
if (!httpHeadReferer.equals(""))
conn.addRequestProperty("Referer", httpHeadReferer);
if (!httpHeadUserAgent.equals(""))
conn.addRequestProperty("User-Agent", httpHeadUserAgent);
return conn;
}
public String getTileUrl(int zoom, int tilex, int tiley) {
if (serverParts == null || serverParts.length == 0) {
return MapSourceTools.formatMapUrl(url, zoom, tilex, tiley);
} else {
currentServerPart = (currentServerPart + 1) % serverParts.length;
String serverPart = serverParts[currentServerPart];
return MapSourceTools.formatMapUrl(url, serverPart, zoom, tilex, tiley);
}
}
public byte[] getTileData(int zoom, int x, int y, LoadMethod loadMethod) throws IOException,
UnrecoverableDownloadException, InterruptedException {
if (invertYCoordinate)
y = ((1 << zoom) - y - 1);
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;
}
if (ignoreErrors) {
try {
return TileDownLoader.getImage(x, y, zoom, this);
} catch (Exception e) {
return null;
}
} else {
return TileDownLoader.getImage(x, y, zoom, this);
}
}
public BufferedImage getTileImage(int zoom, int x, int y, LoadMethod loadMethod) throws IOException,
UnrecoverableDownloadException, InterruptedException {
byte[] data = getTileData(zoom, x, y, loadMethod);
if (data == null) {
if (!ignoreErrors)
return null;
else {
int tileSize = this.getMapSpace().getTileSize();
BufferedImage image = new BufferedImage(tileSize, tileSize, BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = (Graphics) image.getGraphics();
try {
g.setColor(backgroundColor);
g.fillRect(0, 0, tileSize, tileSize);
} finally {
g.dispose();
}
return image;
}
} else {
return ImageIO.read(new ByteArrayInputStream(data));
}
}
@Override
public String toString() {
return name;
}
public MapSpace getMapSpace() {
//return MercatorPower2MapSpace.INSTANCE_256;
return MapSpaceFactory.getInstance(tileSize, mapSpaceType);
}
public Color getBackgroundColor() {
return backgroundColor;
}
@XmlTransient
public MapSourceLoaderInfo getLoaderInfo() {
return loaderInfo;
}
public void setLoaderInfo(MapSourceLoaderInfo loaderInfo) {
if (this.loaderInfo != null)
throw new RuntimeException("LoaderInfo already set");
this.loaderInfo = loaderInfo;
}
public int getTileSize() {
return tileSize;
}
public MapSpaceType getMapSpaceType() {
return mapSpaceType;
}
public String getHttpHeadReferer() {
return httpHeadReferer;
}
public String getHttpHeadUserAgent() {
return httpHeadUserAgent;
}
@Override
public boolean getHiddenDefault() {
return hiddenDefault;
}
}