package com.nutiteq.task;
import java.io.IOException;
import java.io.InputStream;
import com.mgmaps.utils.Tools;
import com.nutiteq.components.MapTile;
import com.nutiteq.config.StoredMapConfig;
import com.nutiteq.fs.FileSystem;
import com.nutiteq.fs.FileSystemConnection;
import com.nutiteq.log.Log;
import com.nutiteq.maps.StoredMap;
import com.nutiteq.utils.IOUtils;
public class ReadStoredMapTileTask implements Task {
private final MapTileSearchTask mapTileSearchTask;
private final StoredMap map;
private final FileSystem fs;
private final MapTile[] toRetrieve;
public ReadStoredMapTileTask(final MapTileSearchTask mapTileSearchTask,
final MapTile[] toRetrieve, final StoredMap sMap, final FileSystem fileSystem) {
this.mapTileSearchTask = mapTileSearchTask;
this.toRetrieve = toRetrieve;
this.map = sMap;
this.fs = fileSystem;
}
public void execute() {
final MapTile tile = toRetrieve[0];
final int mx = tile.getX() / map.getTileSize() & ((1 << tile.getZoom()) - 1);
final int my = tile.getY() / map.getTileSize();
String filename = map.buildPath(tile.getX(), tile.getY(), tile.getZoom());
Log.debug("ReadStoredMapTileTask "+filename);
// TODO Jaak this could be incompatible with tilesperfile>1 config
final int areaParamIndex = filename.indexOf("|a=");
if (areaParamIndex > 0) {
filename = filename.substring(0, areaParamIndex);
}
Log.debug("ReadStoredMapTileTask fixed "+filename);
if ("".equals(filename)) {
mapTileSearchTask.retrieveErrorFor(toRetrieve);
return;
}
final byte[] filedata;
final StoredMapConfig conf = map.getConfig();
try {
if (conf.getTilesPerFile() > 1) {
filename = filename.substring(0, filename.indexOf('|'));
filedata = readMapTile(fs, filename, conf.getTilesPerFile(), mx % conf.getTpfx(), my
% conf.getTpfy());
} else {
filedata = fs.readFile(filename);
}
tile.setImagesData(new byte[][] { filedata });
mapTileSearchTask.retrieveSuccess();
} catch (final Exception e) {
Log.error("Error reading tile: " + e.getMessage());
Log.printStackTrace(e);
mapTileSearchTask.retrieveErrorFor(toRetrieve);
}
}
/**
* Read map tile from a file with multiple tiles.
*
* @param filename
* file to read from
* @param tilesPerFile
* maximum number of tiles stored in a file (power of two)
* @param dx
* x-index of tile in block stored in file
* @param dy
* y-index of tile in block stored in file
* @return map tile data
*/
private byte[] readMapTile(final FileSystem fs, final String filename, final int tilesPerFile,
final int dx, final int dy) throws IOException {
Log.debug("Loading file:///" + filename);
FileSystemConnection fconn = null;
InputStream is;
try {
fconn = fs.openConnectionToFile(filename);
is = fconn.openInputStream();
// read header
int toRead = 6 * tilesPerFile + 2;
final byte[] header = new byte[toRead];
long ch = 0;
int rd = 0;
while ((rd < toRead) && (ch >= 0)) {
ch = is.read(header, rd, toRead - rd);
if (ch > 0) {
rd += ch;
}
}
// search for the tile
final int numberOfTilesStored = (Tools.unsigned(header[0]) << 8) + Tools.unsigned(header[1]);
int offset = -1;
int offset2 = -1;
final int n6 = numberOfTilesStored * 6;
for (int i6 = 0; i6 < n6; i6 += 6) {
if ((header[2 + i6] == dx || header[2 + i6] + 256 == dx)
&& (header[3 + i6] == dy || header[3 + i6] + 256 == dy)) {
offset2 = (Tools.unsigned(header[4 + i6]) << 24) + (Tools.unsigned(header[5 + i6]) << 16)
+ (Tools.unsigned(header[6 + i6]) << 8) + (Tools.unsigned(header[7 + i6]));
offset = (i6 == 0) ? toRead : ((Tools.unsigned(header[i6 - 2]) << 24)
+ (Tools.unsigned(header[i6 - 1]) << 16) + (Tools.unsigned(header[i6]) << 8) + (Tools
.unsigned(header[i6 + 1])));
break;
}
}
if (offset < 0) {
throw new IllegalArgumentException("Tile not found");
}
// seek
IOUtils.skip(is, offset - toRead);
// read data
ch = 0;
rd = 0;
toRead = offset2 - offset;
final byte[] result = new byte[toRead];
while ((rd < toRead) && (ch >= 0)) {
ch = is.read(result, rd, (toRead - rd) > IOUtils.BUFSIZE ? IOUtils.BUFSIZE : (toRead - rd));
if (ch > 0) {
rd += ch;
}
}
return result;
} finally {
fconn.close();
}
}
}