package org.osmdroid.gpkg;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import org.osmdroid.api.IMapView;
import org.osmdroid.config.Configuration;
import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.MapTileRequestState;
import org.osmdroid.tileprovider.modules.IFilesystemCache;
import org.osmdroid.tileprovider.modules.MapTileModuleProviderBase;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.osmdroid.tileprovider.tilesource.XYTileSource;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import mil.nga.geopackage.GeoPackage;
import mil.nga.geopackage.GeoPackageManager;
import mil.nga.geopackage.factory.GeoPackageFactory;
import mil.nga.geopackage.tiles.retriever.GeoPackageTile;
import mil.nga.geopackage.tiles.retriever.GeoPackageTileRetriever;
import mil.nga.geopackage.tiles.user.TileDao;
/**
* This is called the GeoPackage Slowmo because it's damn slow.
* Created by alex on 10/29/15.
*/
public class GeoPackageMapTileModuleProvider extends MapTileModuleProviderBase {
//TileRetriever retriever;
IFilesystemCache tileWriter = null;
GeoPackageManager manager;
//GeoPackage geoPackage;
List<String> tiles;
ITileSource currentTileSource;
Set<GeoPackage> tileSources = new HashSet<>();
/**
* Compress format
*/
private static final Bitmap.CompressFormat COMPRESS_FORMAT = Bitmap.CompressFormat.PNG;
public GeoPackageMapTileModuleProvider(File[] pFile,
final Context context, IFilesystemCache cache) {
//int pThreadPoolSize, final int pPendingQueueSize
super(Configuration.getInstance().getTileFileSystemThreads(), Configuration.getInstance().getTileFileSystemMaxQueueSize());
tileWriter = cache;
// Get a manager
manager = GeoPackageFactory.getManager(context);
// Available databases
// Import database
for (int i = 0; i < pFile.length; i++) {
try {
boolean imported = manager.importGeoPackage((pFile[i]));
} catch (Exception ex) {
ex.printStackTrace();
}
}
// Available databases
List<String> databases = manager.databases();
// Open database
for (int i = 0; i < databases.size(); i++) {
tileSources.add(manager.open(databases.get(i)));
}
}
public Drawable getMapTile(MapTile pTile) {
Drawable tile = null;
String src = currentTileSource.name(); //table name
//String database = currentTileSource.getBaseUrls()[0]; //database name
GeoPackage next = null;
boolean found = false;
//find out db connection
Iterator<GeoPackage> iterator = tileSources.iterator();
while (iterator.hasNext()) {
next = iterator.next();
if (next.getTileTables().contains(src)) {
found = true;
break;
}
}
if (found) {
TileDao tileDao = next.getTileDao(src);
GeoPackageTileRetriever retriever = new GeoPackageTileRetriever(tileDao);
int zoom = pTile.getZoomLevel();
int x = pTile.getX();
int y = pTile.getY();
GeoPackageTile geoPackageTile = retriever.getTile(x, y, zoom);
if (geoPackageTile != null && geoPackageTile.data != null) {
byte[] image = geoPackageTile.data;
if (image != null) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.outHeight = 256; //360
opt.outWidth = 256;//248
Bitmap imageBitmap = BitmapFactory.decodeByteArray(image, 0, image.length, opt);
tile = new BitmapDrawable(imageBitmap);
/*Date dateExpires;
Long override=Configuration.getInstance().getExpirationOverrideDuration();
if (override!=null) {
dateExpires= new Date(System.currentTimeMillis() + override);
} else {
dateExpires = new Date(System.currentTimeMillis() + OpenStreetMapTileProviderConstants.DEFAULT_MAXIMUM_CACHED_FILE_AGE + Configuration.getInstance().getExpirationExtendedDuration());
}
pTile.setExpires(dateExpires);
tileWriter.saveFile(src, pTile, new ByteArrayInputStream(image));
*/
}
}
}
return tile;
}
public static class Container {
public String database;
public List<String> tiles;
public List<String> features;
}
public List<Container> getTileSources() {
List<Container> srcs = new ArrayList<>();
List<String> databases = manager.databases();
for (int i = 0; i < databases.size(); i++) {
GeoPackage handle = manager.open(databases.get(i));
Container c = new Container();
c.database = databases.get(i);
c.tiles = new ArrayList<>();
c.tiles.addAll(handle.getTileTables());
c.features = new ArrayList<>();
c.features.addAll(handle.getFeatureTables());
srcs.add(c);
}
return srcs;
}
@Override
public void detach() {
if (tileSources!=null) {
Iterator<GeoPackage> iterator = tileSources.iterator();
while (iterator.hasNext()) {
iterator.next().close();
}
tileSources.clear();
}
manager = null;
}
protected class TileLoader extends MapTileModuleProviderBase.TileLoader {
@Override
public Drawable loadTile(final MapTileRequestState pState) {
final MapTile pTile = pState.getMapTile();
try {
Drawable mapTile = getMapTile(pTile);
return mapTile;
} catch (final Throwable e) {
Log.e(IMapView.LOGTAG, "Error loading tile", e);
} finally {
}
return null;
}
}
@Override
protected String getName() {
return "Geopackage";
}
@Override
protected String getThreadGroupName() {
return getName();
}
@Override
protected Runnable getTileLoader() {
return new TileLoader();
}
@Override
public boolean getUsesDataConnection() {
return false;
}
@Override
public int getMinimumZoomLevel() {
return 0;
}
@Override
public int getMaximumZoomLevel() {
return 22;
}
@Override
public void setTileSource(ITileSource tileSource) {
currentTileSource = tileSource;
}
}