View Javadoc
1   package au.gov.amsa.ais.message;
2   
3   import com.google.common.base.Optional;
4   
5   import au.gov.amsa.ais.AisExtractor;
6   import au.gov.amsa.ais.AisExtractorFactory;
7   import au.gov.amsa.ais.AisMessageType;
8   import au.gov.amsa.ais.Util;
9   
10  public class AisPositionBExtended implements AisPosition, AisShipStatic {
11  
12      private static final Integer TRUE_HEADING_NOT_AVAILABLE = 511;
13      private static final Integer COG_NOT_AVAILABLE = 3600;
14      private static final Integer SOG_NOT_AVAILABLE = 1023;
15      private static final Integer LONGITUDE_NOT_AVAILABLE = 181 * 600000; // 108600000;
16      private static final Integer LATITUDE_NOT_AVAILABLE = 91 * 600000; // 54600000;
17      private final AisExtractor extractor;
18      private final String source;
19      private final int messageId;
20      private final int repeatIndicator;
21      private final int mmsi;
22      private final Double speedOverGroundKnots;
23      private final Double courseOverGround;
24      private final Double latitude;
25      private final Double longitude;
26      private final Integer trueHeading;
27      private final String name;
28      private final int shipType;
29      private final int dimensionA;
30      private final int dimensionB;
31      private final int dimensionC;
32      private final int dimensionD;
33      private final int timeSecondsOnly;
34      private final boolean isHighAccuracyPosition;
35      private final boolean isUsingRAIM;
36  
37      public AisPositionBExtended(String message, int padBits) {
38          this(message, null, padBits);
39      }
40  
41      public AisPositionBExtended(String message, String source, int padBits) {
42          this(Util.getAisExtractorFactory(), message, source, padBits);
43      }
44  
45      public AisPositionBExtended(AisExtractorFactory factory, String message, String source,
46              int padBits) {
47          this.source = source;
48          this.extractor = factory.create(message, 301, padBits);
49          messageId = extractor.getMessageId();
50          Util.checkMessageId(getMessageId(), AisMessageType.POSITION_REPORT_CLASS_B_EXTENDED);
51          repeatIndicator = extractor.getValue(6, 8);
52          mmsi = extractor.getValue(8, 38);
53          speedOverGroundKnots = extractSpeedOverGround(extractor);
54          isHighAccuracyPosition = Util.areEqual(extractor.getValue(56, 57), 1);
55          longitude = extractLongitude(extractor);
56          latitude = extractLatitude(extractor);
57          courseOverGround = extractCourseOverGround(extractor);
58          trueHeading = extractTrueHeading(extractor);
59          timeSecondsOnly = extractor.getValue(133, 139);
60          name = extractor.getString(143, 263);
61          shipType = extractor.getValue(263, 271);
62          dimensionA = extractor.getValue(271, 280);
63          dimensionB = extractor.getValue(280, 289);
64          dimensionC = extractor.getValue(289, 295);
65          dimensionD = extractor.getValue(295, 301);
66          isUsingRAIM = Util.areEqual(extractor.getValue(305, 306), 1);
67      }
68  
69      static Integer extractTrueHeading(AisExtractor extractor) {
70          int val = extractor.getValue(124, 133);
71          if (val == TRUE_HEADING_NOT_AVAILABLE)
72              return null;
73          else
74              return val;
75      }
76  
77      static Double extractCourseOverGround(AisExtractor extractor) {
78          int val = extractor.getValue(112, 124);
79          if (val == COG_NOT_AVAILABLE)
80              return null;
81          else
82              return val / 10.0;
83      }
84  
85      static Double extractSpeedOverGround(AisExtractor extractor) {
86          int val = extractor.getValue(46, 56);
87          if (val == SOG_NOT_AVAILABLE)
88              return null;
89          else
90              return val / 10.0;
91      }
92  
93      static Double extractLongitude(AisExtractor extractor) {
94          int val = extractor.getSignedValue(57, 85);
95          if (val == LONGITUDE_NOT_AVAILABLE) {
96              return null;
97          } else {
98              Util.checkLong(val / 600000.0);
99              return val / 600000.0;
100         }
101     }
102 
103     static Double extractLatitude(AisExtractor extractor) {
104         int val = extractor.getSignedValue(85, 112);
105         if (val == LATITUDE_NOT_AVAILABLE) {
106             return null;
107         } else {
108             Util.checkLat(val / 600000.0);
109             return val / 600000.0;
110         }
111     }
112 
113     @Override
114     public int getMessageId() {
115         return messageId;
116     }
117 
118     @Override
119     public int getRepeatIndicator() {
120         return repeatIndicator;
121     }
122 
123     @Override
124     public int getMmsi() {
125         return mmsi;
126     }
127 
128     @Override
129     public Double getSpeedOverGroundKnots() {
130         return speedOverGroundKnots;
131     }
132 
133     @Override
134     public Double getLongitude() {
135         return longitude;
136     }
137 
138     @Override
139     public Double getLatitude() {
140         return latitude;
141     }
142 
143     @Override
144     public Double getCourseOverGround() {
145         return courseOverGround;
146     }
147 
148     @Override
149     public Integer getTrueHeading() {
150         return trueHeading;
151     }
152 
153     @Override
154     public int getTimeSecondsOnly() {
155         return timeSecondsOnly;
156     }
157 
158     @Override
159     public String getName() {
160         return name;
161 
162     }
163 
164     @Override
165     public int getShipType() {
166         return shipType;
167     }
168 
169     @Override
170     public Optional<Integer> getDimensionA() {
171         if (dimensionA == 0)
172             return Optional.absent();
173         else
174             return Optional.of(dimensionA);
175     }
176 
177     @Override
178     public Optional<Integer> getDimensionB() {
179         if (dimensionB == 0)
180             return Optional.absent();
181         else
182             return Optional.of(dimensionB);
183     }
184 
185     @Override
186     public Optional<Integer> getDimensionC() {
187         if (dimensionC == 0)
188             return Optional.absent();
189         else
190             return Optional.of(dimensionC);
191     }
192 
193     @Override
194     public Optional<Integer> getDimensionD() {
195         if (dimensionD == 0)
196             return Optional.absent();
197         else
198             return Optional.of(dimensionD);
199     }
200 
201     @Override
202     public Optional<Integer> getLengthMetres() {
203         Optional<Integer> a = getDimensionA();
204         if (!a.isPresent())
205             return Optional.absent();
206         Optional<Integer> b = getDimensionB();
207         if (!b.isPresent())
208             return Optional.absent();
209         return Optional.of(a.get() + b.get());
210     }
211 
212     @Override
213     public Optional<Integer> getWidthMetres() {
214         Optional<Integer> c = getDimensionC();
215         if (!c.isPresent())
216             return Optional.absent();
217         Optional<Integer> d = getDimensionD();
218         if (!d.isPresent())
219             return Optional.absent();
220         return Optional.of(c.get() + d.get());
221     }
222 
223     @Override
224     public String getSource() {
225         return source;
226     }
227 
228     @Override
229     public boolean isHighAccuracyPosition() {
230         return isHighAccuracyPosition;
231     }
232 
233     @Override
234     public boolean isUsingRAIM() {
235         return isUsingRAIM;
236     }
237 
238     @Override
239     public String toString() {
240         StringBuilder builder = new StringBuilder();
241         builder.append("AisPositionBExtended [source=");
242         builder.append(source);
243         builder.append(", messageId=");
244         builder.append(messageId);
245         builder.append(", mmsi=");
246         builder.append(mmsi);
247         builder.append(", repeatIndicator=");
248         builder.append(getRepeatIndicator());
249         builder.append(", speedOverGroundKnots=");
250         builder.append(getSpeedOverGroundKnots());
251         builder.append(", isHighAccuracyPosition=");
252         builder.append(isHighAccuracyPosition());
253         builder.append(", courseOverGround=");
254         builder.append(getCourseOverGround());
255         builder.append(", latitude=");
256         builder.append(getLatitude());
257         builder.append(", longitude=");
258         builder.append(getLongitude());
259         builder.append(", trueHeading=");
260         builder.append(getTrueHeading());
261         builder.append(", name=");
262         builder.append(getName());
263         builder.append(", shipType=");
264         builder.append(getShipType());
265         builder.append(", dimensionA=");
266         builder.append(getDimensionA());
267         builder.append(", dimensionB=");
268         builder.append(getDimensionB());
269         builder.append(", dimensionC=");
270         builder.append(getDimensionC());
271         builder.append(", dimensionD=");
272         builder.append(getDimensionD());
273         builder.append(", timeSecondsOnly=");
274         builder.append(getTimeSecondsOnly());
275         builder.append("]");
276         return builder.toString();
277     }
278 
279 }