1 package au.gov.amsa.ais.message;
2
3 import java.util.Calendar;
4 import java.util.TimeZone;
5
6 import com.google.common.annotations.VisibleForTesting;
7 import com.google.common.base.Optional;
8
9 import au.gov.amsa.ais.AisExtractor;
10 import au.gov.amsa.ais.AisExtractorFactory;
11 import au.gov.amsa.ais.AisMessageType;
12 import au.gov.amsa.ais.Util;
13
14
15
16
17
18
19
20 public class AisShipStaticA implements AisShipStatic {
21
22 private final String source;
23 private final int messageId;
24 private Integer repeatIndicator;
25 private final int mmsi;
26 private Integer aisVersionIndicator;
27 private Integer imo;
28 private String callsign;
29 private String name;
30 private Integer dimensionA;
31 private Integer dimensionB;
32 private Integer dimensionC;
33 private Integer dimensionD;
34 private Integer typeOfElectronicPositionFixingDevice;
35 private Long expectedTimeOfArrival;
36 private Long expectedTimeOfArrivalUnprocessed;
37 private Double maximumPresentStaticDraughtMetres;
38 private String destination;
39 private Boolean dataTerminalAvailable;
40 private Integer spare;
41 private Integer shipType;
42 private final AisExtractor extractor;
43
44 public AisShipStaticA(String message, String source, int padBits) {
45 this(Util.getAisExtractorFactory(), message, source, padBits);
46 }
47
48 public AisShipStaticA(AisExtractorFactory factory, String message, String source, int padBits) {
49 this.source = source;
50 extractor = factory.create(message, 421, padBits);
51 messageId = extractor.getValue(0, 6);
52 Util.checkMessageId(getMessageId(), AisMessageType.STATIC_AND_VOYAGE_RELATED_DATA);
53 mmsi = extractor.getValue(8, 38);
54 }
55
56 @Override
57 public int getMessageId() {
58 return messageId;
59 }
60
61 @Override
62 public int getRepeatIndicator() {
63 if (repeatIndicator == null)
64 repeatIndicator = extractor.getValue(6, 8);
65 return repeatIndicator;
66 }
67
68 @Override
69 public int getMmsi() {
70 return mmsi;
71 }
72
73 public int getAisVersionIndicator() {
74 if (aisVersionIndicator == null)
75 aisVersionIndicator = extractor.getValue(38, 40);
76 return aisVersionIndicator;
77 }
78
79 public Optional<Integer> getImo() {
80 if (imo == null)
81 imo = extractor.getValue(40, 70);
82 if (imo == 0)
83 return Optional.absent();
84 else
85 return Optional.of(imo);
86 }
87
88 public String getCallsign() {
89 if (callsign == null)
90 callsign = extractor.getString(70, 112);
91 return callsign;
92 }
93
94 @Override
95 public String getName() {
96 if (name == null)
97 name = extractor.getString(112, 232);
98 return name;
99 }
100
101 @Override
102 public int getShipType() {
103 if (shipType == null)
104 shipType = extractor.getValue(232, 240);
105 return shipType;
106 }
107
108 @Override
109 public Optional<Integer> getDimensionA() {
110 if (dimensionA == null)
111 dimensionA = extractor.getValue(240, 249);
112 if (dimensionA == 0)
113 return Optional.absent();
114 else
115 return Optional.of(dimensionA);
116 }
117
118 @Override
119 public Optional<Integer> getDimensionB() {
120 if (dimensionB == null)
121 dimensionB = extractor.getValue(249, 258);
122 if (dimensionB == 0)
123 return Optional.absent();
124 else
125 return Optional.of(dimensionB);
126 }
127
128 @Override
129 public Optional<Integer> getDimensionC() {
130 if (dimensionC == null)
131 dimensionC = extractor.getValue(258, 264);
132 if (dimensionC == 0)
133 return Optional.absent();
134 else
135 return Optional.of(dimensionC);
136 }
137
138 @Override
139 public Optional<Integer> getDimensionD() {
140 if (dimensionD == null)
141 dimensionD = extractor.getValue(264, 270);
142 if (dimensionD == 0)
143 return Optional.absent();
144 else
145 return Optional.of(dimensionD);
146 }
147
148 @Override
149 public Optional<Integer> getLengthMetres() {
150 Optional<Integer> a = getDimensionA();
151 Optional<Integer> b = getDimensionB();
152 if (a.isPresent() && b.isPresent())
153 return Optional.of(a.get() + b.get());
154 else {
155 Optional<Integer> c = getDimensionC();
156 Optional<Integer> d = getDimensionD();
157 if (!a.isPresent() && !c.isPresent() && b.isPresent() && d.isPresent())
158 return b;
159 else
160 return Optional.absent();
161 }
162 }
163
164 @Override
165 public Optional<Integer> getWidthMetres() {
166 Optional<Integer> c = getDimensionC();
167 Optional<Integer> d = getDimensionD();
168 if (c.isPresent() && d.isPresent())
169 return Optional.of(c.get() + d.get());
170 else {
171 Optional<Integer> a = getDimensionA();
172 Optional<Integer> b = getDimensionB();
173 if (!a.isPresent() && !c.isPresent() && b.isPresent() && d.isPresent())
174 return d;
175 else
176 return Optional.absent();
177 }
178 }
179
180 public int getTypeOfElectronicPositionFixingDevice() {
181 if (typeOfElectronicPositionFixingDevice == null)
182 typeOfElectronicPositionFixingDevice = extractor.getValue(270, 274);
183 return typeOfElectronicPositionFixingDevice;
184 }
185
186 private static long getExpectedTimeOfArrival(int month, int day, int hour, int minute) {
187 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
188 int year = cal.get(Calendar.YEAR);
189 return getExpectedTimeOfArrival(year, month, day, hour, minute);
190 }
191
192 @VisibleForTesting
193 static long getExpectedTimeOfArrival(int year, int month, int day, int hour, int minute) {
194 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
195 cal.clear();
196 cal.set(year, month - 1, day, hour, minute);
197 cal.set(Calendar.MILLISECOND, 0);
198 return cal.getTimeInMillis();
199 }
200
201 public long getExpectedTimeOfArrival() {
202 if (expectedTimeOfArrival == null) {
203 int month = extractor.getValue(274, 278);
204 int day = extractor.getValue(278, 283);
205 int hour = extractor.getValue(283, 288);
206 int minute = extractor.getValue(288, 294);
207 expectedTimeOfArrival = getExpectedTimeOfArrival(month, day, hour, minute);
208 }
209 return expectedTimeOfArrival;
210 }
211
212 public long getExpectedTimeOfArrivalUnprocessed() {
213 if (expectedTimeOfArrivalUnprocessed == null)
214 expectedTimeOfArrivalUnprocessed = (long) extractor.getValue(274, 294);
215 return expectedTimeOfArrivalUnprocessed;
216 }
217
218 public double getMaximumPresentStaticDraughtMetres() {
219 if (maximumPresentStaticDraughtMetres == null)
220 maximumPresentStaticDraughtMetres = extractor.getValue(294, 302) / 10.0;
221 return maximumPresentStaticDraughtMetres;
222 }
223
224 public String getDestination() {
225 if (destination == null)
226 destination = extractor.getString(302, 422);
227 return destination;
228 }
229
230 public boolean getDataTerminalAvailable() {
231 if (dataTerminalAvailable == null)
232 dataTerminalAvailable = Util.areEqual(extractor.getValue(422, 423), 0);
233 return dataTerminalAvailable;
234 }
235
236 public int getSpare() {
237 if (spare == null)
238 spare = extractor.getValue(423, 424);
239 return spare;
240 }
241
242 @Override
243 public String getSource() {
244 return source;
245 }
246
247 @Override
248 public String toString() {
249 StringBuilder b = new StringBuilder();
250 b.append("AisShipStaticA [source=");
251 b.append(source);
252 b.append(", messageId=");
253 b.append(getMessageId());
254 b.append(", repeatIndicator=");
255 b.append(getRepeatIndicator());
256 b.append(", mmsi=");
257 b.append(mmsi);
258 b.append(", aisVersionIndicator=");
259 b.append(getAisVersionIndicator());
260 b.append(", imo=");
261 b.append(getImo());
262 b.append(", callsign=");
263 b.append(getCallsign());
264 b.append(", name=");
265 b.append(getName());
266 b.append(", dimensionA=");
267 b.append(getDimensionA());
268 b.append(", dimensionB=");
269 b.append(getDimensionB());
270 b.append(", dimensionC=");
271 b.append(getDimensionC());
272 b.append(", dimensionD=");
273 b.append(getDimensionD());
274 b.append(", typeOfElectronicPositionFixingDevice=");
275 b.append(getTypeOfElectronicPositionFixingDevice());
276 b.append(", expectedTimeOfArrival=");
277 b.append(getExpectedTimeOfArrival());
278 b.append(", expectedTimeOfArrivalUnprocessed=");
279 b.append(getExpectedTimeOfArrivalUnprocessed());
280 b.append(", maximumPresentStaticDraughtMetres=");
281 b.append(getMaximumPresentStaticDraughtMetres());
282 b.append(", destination=");
283 b.append(getDestination());
284 b.append(", dataTerminalAvailable=");
285 b.append(getDataTerminalAvailable());
286 b.append(", spare=");
287 b.append(getSpare());
288 b.append(", shipType=");
289 b.append(getShipType());
290 b.append("]");
291 return b.toString();
292 }
293
294 }