package au.gov.amsa.ihs.reader;
import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.of;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.joda.time.DateTime;
import com.google.common.base.Optional;
import au.gov.amsa.ihs.model.Ship;
import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Subscriber;
public class IhsReader {
public Observable<Map<String, String>> from(InputStream is, String parentElementName) {
return Observable.just(is).lift(new OperatorIhsReader(parentElementName));
}
public static Observable<Map<String, String>> fromZip(File file) {
return shipDataFilesAsInputStreamFromZip(file).lift(new OperatorIhsReader("ShipData"));
}
public static Observable<Map<String, Map<String, String>>> fromZipAsMapByImo(File file) {
return fromZip(file).toMap(map -> map.get(Key.LRIMOShipNo.name()));
}
public static Observable<Map<String, Map<String, String>>> fromZipAsMapByMmsi(File file) {
return fromZip(file)
// only ships with an mmsi
.filter(map -> map.get(Key.MaritimeMobileServiceIdentityMMSINumber.name()) != null)
// as map
.toMap(map -> map.get(Key.MaritimeMobileServiceIdentityMMSINumber.name()));
}
private static Observable<InputStream> shipDataFilesAsInputStreamFromZip(final File file) {
return Observable.create(new OnSubscribe<InputStream>() {
@Override
public void call(Subscriber<? super InputStream> subscriber) {
ZipFile zip = null;
try {
zip = new ZipFile(file);
Enumeration<? extends ZipEntry> en = zip.entries();
while (en.hasMoreElements() && !subscriber.isUnsubscribed()) {
ZipEntry entry = en.nextElement();
if (entry.getName().startsWith("ShipData")
&& entry.getName().endsWith(".xml")) {
InputStream is = zip.getInputStream(entry);
System.out.println(entry.getName());
subscriber.onNext(is);
}
}
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
} finally {
try {
if (zip != null)
zip.close();
} catch (IOException e) {
// don't care
}
}
}
});
}
public static Ship toShip(Map<String, String> values) {
return new ShipCreator(values).buildShip();
}
private static class ShipCreator {
private final Map<String, String> values;
ShipCreator(Map<String, String> values) {
this.values = values;
}
Ship buildShip() {
return Ship.builder().classificationSocietyCode(value("ClassificationSocietyCode"))
.countryOfBuildCode(value("CountryOfBuildCode"))
.yearOfBuild(toYearOfBuild(value("DateOfBuild")))
.monthOfBuild(toMonthOfBuild(value("DateOfBuild"))).flagCode(value("FlagCode"))
.grossTonnage(toLong(value("GrossTonnage")))
.groupBeneficialOwnerCompanyCode(value("GroupBeneficialOwnerCompanyCode"))
.groupBeneficialOwnerCountryOfDomicileCode(
value("GroupBeneficialOwnerCountryofDomicileCode"))
.imo(value("LRIMOShipNo").get())
.mmsi(value("MaritimeMobileServiceIdentityMMSINumber"))
.type2(value("ShiptypeLevel2")).type3(value("ShiptypeLevel3"))
.type4(value("ShiptypeLevel4")).type5(value("ShiptypeLevel5"))
.deadweightTonnage(toFloat(value("FormulaDWT"))).statCode5(value("StatCode5"))
.lengthOverallMetres(toFloat(value("LengthOverallLOA")))
.breadthMetres(toFloat(value("Breadth")))
.displacementTonnage(toFloat(value("Displacement")))
.draughtMetres(toFloat(value("Draught"))).speedKnots(toFloat(value("Speed")))
.lastUpdateTime(toDateTime(value("LastUpdateDate"))).name(value("ShipName"))
.shipBuilderCompanyCode(value("ShipbuilderCompanyCode"))
// build it
.build();
}
private Optional<String> value(String name) {
String val = values.get(name);
if (val == null)
return absent();
else if (val.trim().length() == 0)
return absent();
else
return Optional.fromNullable(val.trim());
}
}
private static Optional<DateTime> toDateTime(Optional<String> value) {
if (!value.isPresent())
return absent();
else {
try {
return of(DateTime.parse(value.get()));
} catch (RuntimeException e) {
return absent();
}
}
}
private static Optional<Integer> toYearOfBuild(Optional<String> value) {
if (!value.isPresent())
return absent();
else {
try {
return of(Integer.parseInt(value.get().substring(0, 4)));
} catch (RuntimeException e) {
return absent();
}
}
}
private static Optional<Integer> toMonthOfBuild(Optional<String> value) {
if (!value.isPresent())
return absent();
else {
int month = Integer.parseInt(value.get().substring(4, 6));
if (month > 0)
return of(month);
else
return absent();
}
}
private static Optional<Long> toLong(Optional<String> value) {
if (!value.isPresent())
return Optional.absent();
else {
return Optional.of(Long.parseLong(value.get()));
}
}
private static Optional<Float> toFloat(Optional<String> value) {
if (!value.isPresent())
return Optional.absent();
else {
return Optional.of(Float.parseFloat(value.get()));
}
}
}