package au.gov.amsa.navigation; import static com.google.common.base.Optional.absent; import static com.google.common.base.Optional.of; import java.io.InputStreamReader; import java.io.Reader; import java.util.Map; import com.github.davidmoten.rx.Checked; import com.google.common.base.Charsets; import com.google.common.base.Optional; import au.gov.amsa.ais.message.AisShipStaticUtil; import au.gov.amsa.risky.format.AisClass; import au.gov.amsa.streams.Strings; import rx.Observable; public final class ShipStaticData { public static class Info { public final int mmsi; public final Optional<String> imo; public final AisClass cls; public final Optional<Integer> shipType; public final Optional<Float> maxDraftMetres; public final Optional<Integer> dimensionAMetres; public final Optional<Integer> dimensionBMetres; public final Optional<Integer> dimensionCMetres; public final Optional<Integer> dimensionDMetres; public final Optional<String> name; public Info(int mmsi, Optional<String> imo, AisClass cls, Optional<Integer> shipType, Optional<Float> maxDraftMetres, Optional<Integer> dimensionAMetres, Optional<Integer> dimensionBMetres, Optional<Integer> dimensionCMetres, Optional<Integer> dimensionDMetres, Optional<String> name) { this.mmsi = mmsi; this.imo = imo; this.cls = cls; this.shipType = shipType; this.maxDraftMetres = maxDraftMetres; this.dimensionAMetres = dimensionAMetres; this.dimensionBMetres = dimensionBMetres; this.dimensionCMetres = dimensionCMetres; this.dimensionDMetres = dimensionDMetres; this.name = name; } public Optional<Integer> lengthMetres() { return AisShipStaticUtil.lengthMetres(dimensionAMetres, dimensionBMetres, dimensionCMetres, dimensionDMetres); } public Optional<Integer> widthMetres() { return AisShipStaticUtil.widthMetres(dimensionAMetres, dimensionBMetres, dimensionCMetres, dimensionDMetres); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Info [mmsi="); builder.append(mmsi); builder.append(", imo="); builder.append(imo); builder.append(", cls="); builder.append(cls); builder.append(", shipType="); builder.append(shipType); builder.append(", maxDraftMetres="); builder.append(maxDraftMetres); builder.append(", dimensionAMetres="); builder.append(dimensionAMetres.or(-1)); builder.append(", dimensionBMetres="); builder.append(dimensionBMetres.or(-1)); builder.append(", dimensionCMetres="); builder.append(dimensionCMetres.or(-1)); builder.append(", dimensionDMetres="); builder.append(dimensionDMetres.or(-1)); builder.append(", name="); builder.append(name.or("")); builder.append("]"); return builder.toString(); } } public static Map<Integer, Info> getMapFromResource(String resource) { return getMapFromReader(new InputStreamReader( ShipStaticData.class.getResourceAsStream(resource), Charsets.UTF_8)); } public static Map<Integer, Info> getMapFromReader(Reader reader) { return ShipStaticData // read ship static data from classpath .from(reader) // make a map .toMap(info -> info.mmsi) // go .toBlocking().single(); } public static Observable<Info> fromAndClose(Reader reader) { return Observable.using(() -> reader, r -> from(r), Checked.a1(r -> r.close())); } public static Observable<Info> from(String resource) { return Observable.using( () -> new InputStreamReader(ShipStaticData.class.getResourceAsStream(resource)), r -> from(r), Checked.a1(r -> r.close())); } public static Observable<Info> from(Reader reader) { return Strings.lines(reader) // ignore comments .filter(line -> !line.startsWith("#")) // .map(line -> line.trim()) // .filter(line -> line.length() > 0) // .map(line -> line.split("\t")) // .map(items -> { int i = 0; int mmsi = Integer.parseInt(items[i++]); String imoTemp = items[i++]; Optional<String> imo; if (imoTemp.trim().length() == 0 || Integer.parseInt(imoTemp.trim()) == -1) imo = Optional.absent(); else imo = Optional.of(imoTemp); AisClass cls = items[i++].equals("A") ? AisClass.A : AisClass.B; int type = Integer.parseInt(items[i++]); Optional<Integer> shipType = type == -1 ? absent() : of(type); float draft = Float.parseFloat(items[i++]); Optional<Float> maxDraftMetres = draft == -1 ? absent() : of(draft); int a = Integer.parseInt(items[i++]); int b = Integer.parseInt(items[i++]); int c = Integer.parseInt(items[i++]); int d = Integer.parseInt(items[i++]); Optional<Integer> dimensionAMetres = a == -1 ? absent() : of(a); Optional<Integer> dimensionBMetres = b == -1 ? absent() : of(b); Optional<Integer> dimensionCMetres = c == -1 ? absent() : of(c); Optional<Integer> dimensionDMetres = d == -1 ? absent() : of(d); // skip length and width i += 2; Optional<String> name; if (i >= items.length || items[i].trim().length() == 0) name = Optional.absent(); else name = Optional.of(items[i].trim()); return new Info(mmsi, imo, cls, shipType, maxDraftMetres, dimensionAMetres, dimensionBMetres, dimensionCMetres, dimensionDMetres, name); }); } }