/* Copyright (c) 2011 Danish Maritime Authority.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dk.dma.ais.packet;
import static java.util.Objects.requireNonNull;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import net.jcip.annotations.NotThreadSafe;
import dk.dma.ais.binary.SixbitException;
import dk.dma.ais.message.AisMessage;
import dk.dma.ais.message.AisMessageException;
import dk.dma.ais.message.IPositionMessage;
import dk.dma.ais.sentence.SentenceException;
import dk.dma.ais.sentence.Vdm;
import dk.dma.enav.model.geometry.Position;
import dk.dma.enav.model.geometry.PositionTime;
/**
* Encapsulation of the VDM lines containing a single AIS message including leading proprietary tags and comment/tag
* blocks.
*
* @author Kasper Nielsen
*/
@NotThreadSafe
public class AisPacket implements Comparable<AisPacket> {
private final String rawMessage;
private transient Vdm vdm;
private transient AisPacketTags tags;
private AisMessage message;
private volatile long timestamp = Long.MIN_VALUE;
private AisPacket(String stringMessage) {
this.rawMessage = requireNonNull(stringMessage);
}
AisPacket(Vdm vdm, String stringMessage) {
this(stringMessage);
this.vdm = vdm;
}
public static AisPacket fromByteBuffer(ByteBuffer buffer) {
int cap = buffer.remaining();
byte[] buf = new byte[cap];
buffer.get(buf);
return fromByteArray(buf);
}
public static AisPacket fromByteArray(byte[] array) {
return from(new String(array, StandardCharsets.US_ASCII));
}
public byte[] toByteArray() {
return rawMessage.getBytes(StandardCharsets.US_ASCII);
}
/**
* Returns the timestamp of the packet, or -1 if no timestamp is available.
*
* @return the timestamp of the packet, or -1 if no timestamp is available
*/
public long getBestTimestamp() {
long timestamp = this.timestamp;
if (timestamp == Long.MIN_VALUE) {
Date date = getTimestamp();
this.timestamp = timestamp = date == null ? -1 : date.getTime();
}
return timestamp;
}
public String getStringMessage() {
return rawMessage;
}
public List<String> getStringMessageLines() {
return Arrays.asList(rawMessage.split("\\r?\\n"));
}
/**
* Get existing VDM or parse one from message string
*
* @return Vdm
*/
public Vdm getVdm() {
if (vdm == null) {
AisPacket packet;
try {
packet = readFromString(rawMessage);
if (packet != null) {
vdm = packet.getVdm();
}
} catch (SentenceException e) {
e.printStackTrace();
return null;
}
}
return vdm;
}
/**
* Returns the tags of the packet.
*
* @return the tags of the packet
*/
public AisPacketTags getTags() {
AisPacketTags tags = this.tags;
if (tags == null) {
return this.tags = AisPacketTags.parse(getVdm());
}
return tags;
}
// TODO fizx
public AisMessage tryGetAisMessage() {
try {
return getAisMessage();
} catch (AisMessageException | SixbitException ignore) {
return null;
}
}
/**
* Try to get AIS message from packet
*
* @return
* @throws SixbitException
* @throws AisMessageException
*/
public AisMessage getAisMessage() throws AisMessageException, SixbitException {
if (message != null || getVdm() == null) {
return message;
}
return this.message = AisMessage.getInstance(getVdm());
}
/**
* Check if VDM contains a valid AIS message
*
* @return
*/
public boolean isValidMessage() {
return tryGetAisMessage() != null;
}
/**
* Try to get timestamp for packet.
*
* @return
*/
public Date getTimestamp() {
if (getVdm() == null) {
return null;
}
return vdm.getTimestamp();
}
public PositionTime tryGetPositionTime() {
AisMessage m = tryGetAisMessage();
if (m instanceof IPositionMessage) {
Position p = ((IPositionMessage) m).getPos().getGeoLocation();
return p == null ? null : PositionTime.create(p, getBestTimestamp());
}
return null;
}
public static AisPacket from(String stringMessage) {
return new AisPacket(stringMessage);
}
/**
* Construct AisPacket from raw packet string
*
* @param messageString
* @param optional
* factory
* @return
* @throws SentenceException
*/
public static AisPacket readFromString(String messageString) throws SentenceException {
AisPacket packet = null;
AisPacketParser packetReader = new AisPacketParser();
// String[] lines = StringUtils.split(messageString, "\n");
String[] lines = messageString.split("\\r?\\n");
for (String line : lines) {
packet = packetReader.readLine(line);
if (packet != null) {
return packet;
}
}
return null;
}
/** {@inheritDoc} */
@Override
public int compareTo(AisPacket p) {
return Long.compare(getBestTimestamp(), p.getBestTimestamp());
}
}