View Javadoc
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   * Decoder for AIS ship static and voyage related data (message type 5).
16   * 
17   * @author dxm
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; // lazy set
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 }