package net.osmand.plus;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import net.osmand.IProgress;
import net.osmand.LogUtil;
import net.osmand.data.MapObject;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import org.apache.commons.logging.Log;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
public class BaseLocationIndexRepository<T extends MapObject> {
private static final Log log = LogUtil.getLog(BaseLocationIndexRepository.class);
protected SQLiteDatabase db;
protected double dataTopLatitude;
protected double dataBottomLatitude;
protected double dataLeftLongitude;
protected double dataRightLongitude;
protected String name;
protected List<T> cachedObjects = new ArrayList<T>();
protected double cTopLatitude;
protected double cBottomLatitude;
protected double cLeftLongitude;
protected double cRightLongitude;
protected int cZoom;
public synchronized void clearCache(){
cachedObjects.clear();
cTopLatitude = 0;
cBottomLatitude = 0;
cRightLongitude = 0;
cLeftLongitude = 0;
cZoom = 0;
}
public boolean initialize(final IProgress progress, File file, int version, String tableLocation, boolean searchX31) {
long start = System.currentTimeMillis();
if(db != null){
// close previous db
db.close();
}
db = SQLiteDatabase.openOrCreateDatabase(file, null);
name = file.getName().substring(0, file.getName().indexOf('.'));
if(db.getVersion() != version){
db.close();
db = null;
return false;
}
String metaTable = "loc_meta_"+tableLocation; //$NON-NLS-1$
Cursor cursor = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='"+metaTable+"'", null); //$NON-NLS-1$ //$NON-NLS-2$
boolean dbExist = cursor.moveToFirst();
cursor.close();
boolean found = false;
boolean write = true;
if(dbExist){
cursor = db.rawQuery("SELECT MAX_LAT, MAX_LON, MIN_LAT, MIN_LON FROM " +metaTable, null); //$NON-NLS-1$
if(cursor.moveToFirst()){
dataTopLatitude = cursor.getDouble(0);
dataRightLongitude = cursor.getDouble(1);
dataBottomLatitude = cursor.getDouble(2);
dataLeftLongitude = cursor.getDouble(3);
found = true;
} else {
found = false;
}
cursor.close();
} else {
try {
db.execSQL("CREATE TABLE " + metaTable + " (MAX_LAT DOUBLE, MAX_LON DOUBLE, MIN_LAT DOUBLE, MIN_LON DOUBLE)"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (RuntimeException e) {
// case when database is in readonly mode
write = false;
}
}
if (!found) {
if(searchX31){
Cursor query = db.query(tableLocation,
new String[] { "MIN(y)", "MAX(x)", "MAX(y)", "MIN(x)" }, null, null, null, null, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
if (query.moveToFirst()) {
dataTopLatitude = MapUtils.get31LatitudeY(query.getInt(0)) + 1;
dataRightLongitude = MapUtils.get31LongitudeX(query.getInt(1)) + 1.5;
dataBottomLatitude = MapUtils.get31LatitudeY(query.getInt(2)) - 1;
dataLeftLongitude = MapUtils.get31LongitudeX(query.getInt(3)) - 1.5;
}
query.close();
} else {
Cursor query = db
.query(
tableLocation,
new String[] { "MAX(latitude)", "MAX(longitude)", "MIN(latitude)", "MIN(longitude)" }, null, null, null, null, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
if (query.moveToFirst()) {
dataTopLatitude = query.getDouble(0) + 1;
dataRightLongitude = query.getDouble(1) + 1.5;
dataBottomLatitude = query.getDouble(2) - 1;
dataLeftLongitude = query.getDouble(3) - 1.5;
}
query.close();
}
if (write) {
db.execSQL("INSERT INTO " + metaTable + " VALUES (?, ?, ? ,?)", new Double[]{dataTopLatitude, dataRightLongitude, dataBottomLatitude, dataLeftLongitude}); //$NON-NLS-1$ //$NON-NLS-2$
}
}
if (log.isDebugEnabled()) {
log.debug("Initializing db " + file.getAbsolutePath() + " " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
return true;
}
public synchronized void close() {
if (db != null) {
db.close();
dataRightLongitude = dataLeftLongitude = dataBottomLatitude = dataTopLatitude = 0;
clearCache();
db = null;
}
}
public String getName() {
return name;
}
protected void bindString(SQLiteStatement s, int i, String v){
if(v == null){
s.bindNull(i);
} else {
s.bindString(i, v);
}
}
public boolean checkCachedObjects(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List<T> toFill){
return checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, false);
}
public synchronized boolean checkCachedObjects(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List<T> toFill, boolean fillFound){
if (db == null) {
return true;
}
boolean inside = cTopLatitude >= topLatitude && cLeftLongitude <= leftLongitude && cRightLongitude >= rightLongitude
&& cBottomLatitude <= bottomLatitude && cZoom == zoom;
boolean noNeedToSearch = inside;
if((inside || fillFound) && toFill != null){
for(T a : cachedObjects){
LatLon location = a.getLocation();
if (location.getLatitude() <= topLatitude && location.getLongitude() >= leftLongitude && location.getLongitude() <= rightLongitude
&& location.getLatitude() >= bottomLatitude) {
toFill.add(a);
}
}
}
return noNeedToSearch;
}
public boolean checkContains(double latitude, double longitude){
if(latitude < dataTopLatitude && latitude > dataBottomLatitude && longitude > dataLeftLongitude && longitude < dataRightLongitude){
return true;
}
return false;
}
public boolean checkContains(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude){
if(rightLongitude < dataLeftLongitude || leftLongitude > dataRightLongitude){
return false;
}
if(topLatitude < dataBottomLatitude || bottomLatitude > dataTopLatitude){
return false;
}
return true;
}
}