package net.osmand.plus;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.MessageFormat;
import net.osmand.Algoritms;
import net.osmand.LogUtil;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
import net.osmand.map.TileSourceManager.TileSourceTemplate;
import org.apache.commons.logging.Log;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDiskIOException;
import android.database.sqlite.SQLiteStatement;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class SQLiteTileSource implements ITileSource {
public static final String EXT = ".sqlitedb"; //$NON-NLS-1$
private static final Log log = LogUtil.getLog(SQLiteTileSource.class);
private ITileSource base;
private String urlTemplate = null;
private String name;
private SQLiteDatabase db;
private final File file;
private int minZoom = 1;
private int maxZoom = 17;
public SQLiteTileSource(File f){
this.file = f;
int i = f.getName().lastIndexOf('.');
name = f.getName().substring(0, i);
i = name.lastIndexOf('.');
if(i > 0){
String sourceName = name.substring(i+1);
for(TileSourceTemplate is : TileSourceManager.getKnownSourceTemplates()){
if(is.getName().equalsIgnoreCase(sourceName)){
base = is;
urlTemplate = is.getUrlTemplate();
break;
}
}
}
}
@Override
public int getBitDensity() {
return base != null ? base.getBitDensity() : 16;
}
@Override
public int getMaximumZoomSupported() {
getDatabase();
return base != null ? base.getMaximumZoomSupported() : maxZoom;
}
@Override
public int getMinimumZoomSupported() {
getDatabase();
return base != null ? base.getMinimumZoomSupported() : minZoom;
}
@Override
public String getName() {
return name;
}
@Override
public String getTileFormat() {
return base != null ? base.getTileFormat() : ".png"; //$NON-NLS-1$
}
@Override
public int getTileSize() {
return base != null ? base.getTileSize() : 256;
}
@Override
public String getUrlToLoad(int x, int y, int zoom) {
SQLiteDatabase db = getDatabase();
if(db == null || db.isReadOnly() || urlTemplate == null){
return null;
}
return MessageFormat.format(urlTemplate, zoom+"", x+"", y+""); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((base == null) ? 0 : base.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SQLiteTileSource other = (SQLiteTileSource) obj;
if (base == null) {
if (other.base != null)
return false;
} else if (!base.equals(other.base))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
private SQLiteDatabase getDatabase(){
if(db == null && file.exists()){
db = SQLiteDatabase.openDatabase(file.getAbsolutePath(), null, 0);
try {
String template = db.compileStatement("SELECT url FROM info").simpleQueryForString(); //$NON-NLS-1$
if(!Algoritms.isEmpty(template)){
urlTemplate = template;
}
} catch (RuntimeException e) {
}
try {
long z;
z = db.compileStatement("SELECT minzoom FROM info").simpleQueryForLong(); //$NON-NLS-1$
if (z < 17 && z >= 0)
maxZoom = 17 - (int)z;
z = db.compileStatement("SELECT maxzoom FROM info").simpleQueryForLong(); //$NON-NLS-1$
if (z < 17 && z >= 0)
minZoom = 17 - (int)z;
} catch (RuntimeException e) {
}
}
return db;
}
public boolean exists(int x, int y, int zoom) {
SQLiteDatabase db = getDatabase();
if(db == null){
return false;
}
long time = System.currentTimeMillis();
Cursor cursor = db.rawQuery("SELECT 1 FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
try {
boolean e = cursor.moveToFirst();
cursor.close();
if (log.isDebugEnabled()) {
log.debug("Checking tile existance x = " + x + " y = " + y + " z = " + zoom + " for " + (System.currentTimeMillis() - time)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
return e;
} catch (SQLiteDiskIOException e) {
return false;
}
}
public Bitmap getImage(int x, int y, int zoom) {
SQLiteDatabase db = getDatabase();
if(db == null){
return null;
}
Cursor cursor = db.rawQuery("SELECT image FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
byte[] blob = null;
if(cursor.moveToFirst()) {
blob = cursor.getBlob(0);
}
cursor.close();
if(blob != null){
return BitmapFactory.decodeByteArray(blob, 0, blob.length);
}
return null;
}
public ITileSource getBase() {
return base;
}
public void deleteImage(int x, int y, int zoom) {
SQLiteDatabase db = getDatabase();
if(db == null || db.isReadOnly()){
return;
}
db.execSQL("DELETE FROM tiles WHERE x = ? AND y = ? AND z = ?", new String[] {x+"", y+"",(17 - zoom)+""}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
}
private final int BUF_SIZE = 1024;
public void insertImage(int x, int y, int zoom, File fileToSave) throws IOException {
SQLiteDatabase db = getDatabase();
if(db == null || db.isReadOnly()){
return;
}
if(exists(x, y, zoom)){
return;
}
ByteBuffer buf = ByteBuffer.allocate((int) fileToSave.length());
FileInputStream is = new FileInputStream(fileToSave);
int i = 0;
byte[] b = new byte[BUF_SIZE];
while((i=is.read(b, 0, BUF_SIZE)) > - 1){
buf.put(b, 0, i);
}
SQLiteStatement statement = db.compileStatement("INSERT INTO tiles VALUES(?, ?, ?, ?, ?)"); //$NON-NLS-1$
statement.bindLong(1, x);
statement.bindLong(2, y);
statement.bindLong(3, 17 - zoom);
statement.bindLong(4, 0);
statement.bindBlob(5, buf.array());
statement.execute();
statement.close();
}
public void closeDB(){
if(db != null){
db.close();
db = null;
}
}
@Override
public boolean couldBeDownloadedFromInternet() {
if(getDatabase() == null || getDatabase().isReadOnly()){
return false;
}
return urlTemplate != null;
}
}