package org.osmtools.srtm;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class SrtmTile {
private static final Pattern filePattern = Pattern.compile("(N|S)(..)(W|E)(...).*");
private File file;
private SoftReference<ByteBuffer> bufferReference;
private int lat;
private int lon;
public SrtmTile(File file) {
this.file = file;
Matcher matcher = filePattern.matcher(file.getName());
if (matcher.matches()) {
String latDir = matcher.group(1);
lat = Integer.parseInt(matcher.group(2));
if (latDir.equalsIgnoreCase("s"))
lat *= -1;
String lonDir = matcher.group(3);
lon = Integer.parseInt(matcher.group(4));
if (lonDir.equalsIgnoreCase("w"))
lon *= -1;
}
else {
throw new IllegalArgumentException("File name does not match pattern");
}
}
public SrtmTile(InputStream in, int lon, int lat) {
this.lon = lon;
this.lat = lat;
try {
bufferReference = new SoftReference<ByteBuffer>(createBuffer(in));
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
public boolean hasData(double lon, double lat) {
return (int)lon == this.lon && (int)lat == this.lat;
}
private ByteBuffer initData() {
try {
if (file.getAbsolutePath().toLowerCase().endsWith(".zip")) {
ZipFile zipFile = new ZipFile(file);
ZipEntry firstEntry = zipFile.entries().nextElement();
ByteBuffer byteBuffer = createBuffer(zipFile.getInputStream(firstEntry));
zipFile.close();
return byteBuffer;
}
else {
InputStream in = new FileInputStream(file);
ByteBuffer byteBuffer = createBuffer(in);
in.close();
return byteBuffer;
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private ByteBuffer createBuffer(InputStream in) throws IOException {
byte[] readBuffer = new byte[1201 * 1201 * 2];
int offset = 0;
while (in.available() > 0) {
int read = in.read(readBuffer, offset, readBuffer.length - offset);
offset += read;
}
ByteBuffer buffer = ByteBuffer.wrap(readBuffer);
buffer.order(ByteOrder.BIG_ENDIAN);
return buffer;
}
private ByteBuffer getBuffer() {
ByteBuffer buffer = bufferReference == null ? null : bufferReference.get();
if (buffer == null) {
buffer = initData();
bufferReference = new SoftReference<ByteBuffer>(buffer);
}
return buffer;
}
public int getElevation(double lon, double lat) {
int x = (int)Math.round((lon - this.lon) * 1200);
int y = (int)Math.round((lat - this.lat) * 1200);
int pos = (1200 - y) * (1201 * 2) + (x * 2);
return getBuffer().getShort(pos);
}
public int getLat() {
return lat;
}
public int getLon() {
return lon;
}
}