package dk.thoerup.traininfo.provider; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.URLEncoder; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import org.simpleframework.xml.Serializer; import org.simpleframework.xml.core.Persister; import android.content.Context; import android.location.Location; import android.util.Log; import dk.thoerup.android.traininfo.common.StationBean; import dk.thoerup.android.traininfo.common.StationEntry; import dk.thoerup.genericjavautils.HttpUtil; import dk.thoerup.traininfo.util.DownloadUtil; import dk.thoerup.traininfo.util.IntSet; import dk.thoerup.traininfo.util.XmlUtil; public class OfflineStationProvider implements StationProvider { StationBean stations = new StationBean(); public boolean loadStations(Context context) throws Exception { long start = System.currentTimeMillis(); stations.entries.clear(); //TODO: remove File parent = context.getFilesDir(); File stationsFile = new File(parent, "stations.bin"); if (!stationsFile.exists()) return false; /*int size = (int) stationsFile.length(); byte data[] = new byte[size]; RandomAccessFile raf = new RandomAccessFile(stationsFile, "r"); raf.readFully(data); Serializer serializer = new Persister(); stations = serializer.read(StationBean.class, new String(data, "ISO-8859-1") );*/ try { ObjectInputStream in = new ObjectInputStream( new FileInputStream(stationsFile) ); Object o; StationEntry e = null; while ( (o=in.readObject()) != null ) { e = (StationEntry) o; e.updateSearch(); stations.entries.add( e ); } in.close(); } catch (EOFException e) { //do nothing; } Log.e("OFFLINE", "loaded" + stations.entries.size()); logElapsedTime(start, "loadStations"); return true; } public void downloadStations(Context context) throws Exception { File parent = context.getFilesDir(); File stationsFile = new File(parent, "stations.bin"); byte data[] = HttpUtil.getContent(XmlUtil.SERVICE_BASE + "/LocateStations?dump=1", 5000); Serializer serializer = new Persister(); stations = serializer.read(StationBean.class, new String(data, "ISO-8859-1") ); ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(stationsFile) ); Log.e("OFFLINE", "data size" + data.length); for (StationEntry entry : stations.entries) { entry.updateSearch(); //prepare name fields for byName search out.writeObject(entry); } out.close(); } @Override public void purgeOldEntries() { } Comparator distanceComparator = new Comparator() { @Override public int compare(StationEntry object1, StationEntry object2) { if (object1.getCalcdist() == object2.getCalcdist()) return 0; if (object1.getCalcdist() > object2.getCalcdist()) return 1; else return -1; } }; @Override public StationBean lookupStationsByLocation(Location location) { statsByLocation(location); long start = System.currentTimeMillis(); Location tmpLoc = new Location("GPS"); LinkedList entries = new LinkedList() ; for (StationEntry entry : stations.entries) { tmpLoc.setLatitude(entry.getLatitude()); tmpLoc.setLongitude(entry.getLongitude()); int distance = (int) location.distanceTo(tmpLoc); if (entries.size() <8 || entries.getLast().getCalcdist() > distance) { entry.setCalcdist(distance); if (entries.size() == 8) entries.removeLast(); entries.addLast(entry); Collections.sort( entries, distanceComparator); } } logElapsedTime(start, "location_stage1"); Collections.sort( entries, distanceComparator); StationBean tmpStations = new StationBean(); for (int i = 0; i<8; i++) { tmpStations.entries.add( entries.get(i) ); } logElapsedTime(start, "location"); return tmpStations; } private void logElapsedTime(long start, String method) { long now = System.currentTimeMillis(); Log.i("TrainInfo", "Search by " + method + " elapsed " + (now-start) ); } @Override public StationBean lookupStationsByName(String name) { long start = System.currentTimeMillis(); name = name.toLowerCase(); StationBean tmpStations = new StationBean(); for (StationEntry entry : stations.entries) { if (entry.nameLower.startsWith(name) || entry.nameInternational.startsWith(name) ) { tmpStations.entries.add(entry); } } logElapsedTime(start, "name"); return tmpStations; } @Override public StationBean lookupStationsByIds(String ids) { statsByIds(ids); IntSet idset = new IntSet(); idset.fromString(ids); StationBean tmpStations = new StationBean(); for (StationEntry entry : stations.entries) { if (idset.contains( entry.getId() ) ) { tmpStations.entries.add(entry); } } return tmpStations; } private void statsByLocation(Location location) { double lat = XmlStationProvider.roundToPlaces(location.getLatitude(), 4); double lng = XmlStationProvider.roundToPlaces(location.getLongitude(), 4); final String url = XmlUtil.SERVICE_BASE + "/LocateStations?latitude=" + lat + "&longitude=" + lng + "&dummy=1"; Log.i("url", url); urlSender(url); } private void statsByName(String name) { try { name = URLEncoder.encode(name, "ISO8859-1"); } catch (Exception e) { Log.e("lookupStations", "Encoding failed", e);//if encoding fails use original and hope for the best } String url = XmlUtil.SERVICE_BASE + "/LocateStations?name=" + name + "&dummy=1"; Log.i("url", url); urlSender(url); } private void statsByIds(String ids) { final String url = XmlUtil.SERVICE_BASE + "/LocateStations?list=" + ids + "&dummy=1"; Log.i("url", url); urlSender(url); } private void urlSender(final String url) { Thread t = new Thread(new Runnable() { @Override public void run() { try { DownloadUtil.getContentString(url, 15000, "ISO-8859-1"); } catch (IOException e) { Log.e("TrainInfo", "stats failed"); } } }); t.start(); } }