package au.gov.amsa.navigation; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.zip.GZIPInputStream; import com.github.davidmoten.rx.Checked; import com.google.common.base.Optional; import au.gov.amsa.risky.format.AisClass; import au.gov.amsa.risky.format.FixImpl; import au.gov.amsa.risky.format.NavigationalStatus; import au.gov.amsa.streams.Strings; import rx.Observable; import rx.functions.Action1; import rx.functions.Func0; import rx.functions.Func1; public final class DriftCandidates { public static Observable<DriftCandidate> fromCsv(Reader reader) { return Strings.lines(reader) // remove blank lines .filter(nonBlankLinesOnly()) // parse candidate .map(line -> toDriftCandidate(line)); } private static DriftCandidate toDriftCandidate(String line) { String[] items = line.split(","); int i = 0; int mmsi = Integer.parseInt(items[i++]); float lat = Float.parseFloat(items[i++]); float lon = Float.parseFloat(items[i++]); long time = Long.parseLong(items[i++]); String cls = items[i++]; float course = Float.parseFloat(items[i++]); float heading = Float.parseFloat(items[i++]); float speedKnots = Float.parseFloat(items[i++]); String status = items[i++]; long driftingSince = Long.parseLong(items[i++]); final Optional<NavigationalStatus> navigationalStatus; if (status.trim().length() == 0) navigationalStatus = Optional.absent(); else navigationalStatus = Optional.of(NavigationalStatus.valueOf(status)); final AisClass aisClass; if (cls.trim().length() == 0) throw new RuntimeException("cls should not be empty"); else if (AisClass.A.name().equals(cls)) aisClass = AisClass.A; else aisClass = AisClass.B; FixImpl fix = new FixImpl(mmsi, lat, lon, time, Optional.<Integer> absent(), Optional.<Short> absent(), navigationalStatus, Optional.of(speedKnots), Optional.of(course), Optional.of(heading), aisClass); return new DriftCandidate(fix, driftingSince); } public static Observable<DriftCandidate> fromCsv(final File file, boolean zipped) { Action1<Reader> disposeAction = reader -> { try { reader.close(); } catch (IOException e) { // ignore } }; Func0<Reader> resourceFactory = Checked.f0(() -> { InputStream is; if (zipped) is = new GZIPInputStream(new FileInputStream(file)); else is = new FileInputStream(file); return new InputStreamReader(is); }); Func1<Reader, Observable<DriftCandidate>> obFactory = reader -> fromCsv(reader); return Observable.using(resourceFactory, obFactory, disposeAction, true); } private static Func1<String, Boolean> nonBlankLinesOnly() { return line -> line.trim().length() > 0; } }