package au.gov.amsa.ais; import static java.lang.Integer.parseInt; import java.util.Calendar; import java.util.regex.Pattern; import au.gov.amsa.util.nmea.NmeaMessage; import au.gov.amsa.util.nmea.NmeaMessageParseException; import au.gov.amsa.util.nmea.NmeaUtil; import com.google.common.annotations.VisibleForTesting; /** * Parses a custom ExactEarth NMEA line for AMSA so that we can obtain the * actual timestamp of an AIS Position Report (types 1,2,3). * * @author dxm * */ public class NmeaMessageExactEarthTimestamp { private final NmeaMessage nmea; private final long time; private final String followingSequenceChecksum; /** * Constructor. * * @param line */ public NmeaMessageExactEarthTimestamp(String line) { nmea = NmeaUtil.parseNmea(line); try { Util.checkArgument(isPghp(line), "not an ExactEarth timestamp: " + line); getFollowingSequenceChecksum(); int year = parseInt(getItem(2)); int month = parseInt(getItem(3)); int day = parseInt(getItem(4)); int hour = parseInt(getItem(5)); int minute = parseInt(getItem(6)); int second = parseInt(getItem(7)); int millisecond = parseInt(getItem(8)); time = getTime(year, month, day, hour, minute, second, millisecond); followingSequenceChecksum = extractFollowingSequenceChecksum(); } catch (RuntimeException e) { throw new AisParseException(e); } } private static final Pattern pghpPattern = Pattern .compile("^(\\\\.*\\\\)?\\$PGHP.*$"); /** * Returns true if and only if the given NMEA line is a PGHP line. Remember * that the line can start with a tag block. * * @param line * @return */ @VisibleForTesting static boolean isPghp(String line) { if (line == null) return false; else // return Pattern.matches("^(\\\\.*\\\\)?\\$PGHP.*$", line); return pghpPattern.matcher(line).matches(); } /** * Returns true if the given line is a custom ExactEarth timestamp. * * @param line * @return */ public static boolean isExactEarthTimestamp(String line) { try { new NmeaMessageExactEarthTimestamp(line); return true; } catch (AisParseException e) { return false; } catch (NmeaMessageParseException e) { return false; } } /** * Returns the item at index, zero based. * * @param index * @return */ private String getItem(int index) { return nmea.getItems().get(index); } /** * Returns the epoch time in ms. * * @return */ private static long getTime(int year, int month, int day, int hour, int minute, int second, int millisecond) { Calendar cal = Calendar.getInstance(Util.TIME_ZONE_UTC); cal.set(year, month - 1, day, hour, minute, second); cal.set(Calendar.MILLISECOND, millisecond); return cal.getTimeInMillis(); } /** * Returns the time in epoch ms. * * @return */ public long getTime() { return time; } /** * Returns the checksum of the message that this timestamp line refers to. * * @return */ public String getFollowingSequenceChecksum() { return followingSequenceChecksum; } /** * Returns the checksum of the message that this timestamp refers to. * * @return */ private String extractFollowingSequenceChecksum() { return getItem(13); } }