View Javadoc
1   package au.gov.amsa.navigation;
2   
3   import static com.google.common.base.Optional.absent;
4   import static com.google.common.base.Optional.of;
5   
6   import java.io.InputStreamReader;
7   import java.io.Reader;
8   import java.util.Map;
9   
10  import com.github.davidmoten.rx.Checked;
11  import com.google.common.base.Charsets;
12  import com.google.common.base.Optional;
13  
14  import au.gov.amsa.ais.message.AisShipStaticUtil;
15  import au.gov.amsa.risky.format.AisClass;
16  import au.gov.amsa.streams.Strings;
17  import rx.Observable;
18  
19  public final class ShipStaticData {
20  
21      public static class Info {
22          public final int mmsi;
23          public final Optional<String> imo;
24          public final AisClass cls;
25          public final Optional<Integer> shipType;
26          public final Optional<Float> maxDraftMetres;
27          public final Optional<Integer> dimensionAMetres;
28          public final Optional<Integer> dimensionBMetres;
29          public final Optional<Integer> dimensionCMetres;
30          public final Optional<Integer> dimensionDMetres;
31          public final Optional<String> name;
32  
33          public Info(int mmsi, Optional<String> imo, AisClass cls, Optional<Integer> shipType,
34                  Optional<Float> maxDraftMetres, Optional<Integer> dimensionAMetres,
35                  Optional<Integer> dimensionBMetres, Optional<Integer> dimensionCMetres,
36                  Optional<Integer> dimensionDMetres, Optional<String> name) {
37              this.mmsi = mmsi;
38              this.imo = imo;
39              this.cls = cls;
40              this.shipType = shipType;
41              this.maxDraftMetres = maxDraftMetres;
42              this.dimensionAMetres = dimensionAMetres;
43              this.dimensionBMetres = dimensionBMetres;
44              this.dimensionCMetres = dimensionCMetres;
45              this.dimensionDMetres = dimensionDMetres;
46              this.name = name;
47          }
48  
49          public Optional<Integer> lengthMetres() {
50              return AisShipStaticUtil.lengthMetres(dimensionAMetres, dimensionBMetres,
51                      dimensionCMetres, dimensionDMetres);
52          }
53  
54          public Optional<Integer> widthMetres() {
55              return AisShipStaticUtil.widthMetres(dimensionAMetres, dimensionBMetres,
56                      dimensionCMetres, dimensionDMetres);
57          }
58  
59          @Override
60          public String toString() {
61              StringBuilder builder = new StringBuilder();
62              builder.append("Info [mmsi=");
63              builder.append(mmsi);
64              builder.append(", imo=");
65              builder.append(imo);
66              builder.append(", cls=");
67              builder.append(cls);
68              builder.append(", shipType=");
69              builder.append(shipType);
70              builder.append(", maxDraftMetres=");
71              builder.append(maxDraftMetres);
72              builder.append(", dimensionAMetres=");
73              builder.append(dimensionAMetres.or(-1));
74              builder.append(", dimensionBMetres=");
75              builder.append(dimensionBMetres.or(-1));
76              builder.append(", dimensionCMetres=");
77              builder.append(dimensionCMetres.or(-1));
78              builder.append(", dimensionDMetres=");
79              builder.append(dimensionDMetres.or(-1));
80              builder.append(", name=");
81              builder.append(name.or(""));
82              builder.append("]");
83              return builder.toString();
84          }
85  
86      }
87  
88      public static Map<Integer, Info> getMapFromResource(String resource) {
89          return getMapFromReader(new InputStreamReader(
90                  ShipStaticData.class.getResourceAsStream(resource), Charsets.UTF_8));
91      }
92  
93      public static Map<Integer, Info> getMapFromReader(Reader reader) {
94          return ShipStaticData
95                  // read ship static data from classpath
96                  .from(reader)
97                  // make a map
98                  .toMap(info -> info.mmsi)
99                  // go
100                 .toBlocking().single();
101     }
102 
103     public static Observable<Info> fromAndClose(Reader reader) {
104         return Observable.using(() -> reader, r -> from(r), Checked.a1(r -> r.close()));
105     }
106 
107     public static Observable<Info> from(String resource) {
108         return Observable.using(
109                 () -> new InputStreamReader(ShipStaticData.class.getResourceAsStream(resource)),
110                 r -> from(r), Checked.a1(r -> r.close()));
111     }
112 
113     public static Observable<Info> from(Reader reader) {
114         return Strings.lines(reader)
115                 // ignore comments
116                 .filter(line -> !line.startsWith("#"))
117                 //
118                 .map(line -> line.trim())
119                 //
120                 .filter(line -> line.length() > 0)
121                 //
122                 .map(line -> line.split("\t"))
123                 //
124                 .map(items -> {
125                     int i = 0;
126                     int mmsi = Integer.parseInt(items[i++]);
127                     String imoTemp = items[i++];
128                     Optional<String> imo;
129                     if (imoTemp.trim().length() == 0 || Integer.parseInt(imoTemp.trim()) == -1)
130                         imo = Optional.absent();
131                     else
132                         imo = Optional.of(imoTemp);
133                     AisClass cls = items[i++].equals("A") ? AisClass.A : AisClass.B;
134                     int type = Integer.parseInt(items[i++]);
135                     Optional<Integer> shipType = type == -1 ? absent() : of(type);
136                     float draft = Float.parseFloat(items[i++]);
137                     Optional<Float> maxDraftMetres = draft == -1 ? absent() : of(draft);
138                     int a = Integer.parseInt(items[i++]);
139                     int b = Integer.parseInt(items[i++]);
140                     int c = Integer.parseInt(items[i++]);
141                     int d = Integer.parseInt(items[i++]);
142                     Optional<Integer> dimensionAMetres = a == -1 ? absent() : of(a);
143                     Optional<Integer> dimensionBMetres = b == -1 ? absent() : of(b);
144                     Optional<Integer> dimensionCMetres = c == -1 ? absent() : of(c);
145                     Optional<Integer> dimensionDMetres = d == -1 ? absent() : of(d);
146                     // skip length and width
147                     i += 2;
148                     Optional<String> name;
149                     if (i >= items.length || items[i].trim().length() == 0)
150                         name = Optional.absent();
151                     else
152                         name = Optional.of(items[i].trim());
153                     return new Info(mmsi, imo, cls, shipType, maxDraftMetres, dimensionAMetres,
154                             dimensionBMetres, dimensionCMetres, dimensionDMetres, name);
155                 });
156     }
157 }