package au.gov.amsa.risky.format;
import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import com.github.davidmoten.rx.Functions;
import rx.Observable;
import rx.Observable.Transformer;
import rx.functions.Action2;
import rx.functions.Func1;
/**
* Assumes input stream is in time order.
*/
public class Downsample<T extends HasFix> implements Transformer<T, T> {
private final long minTimeBetweenFixesMs;
private final Func1<T, Boolean> selector;
public Downsample(long minTimeBetweenFixesMs, Func1<T, Boolean> selector) {
this.minTimeBetweenFixesMs = minTimeBetweenFixesMs;
this.selector = selector;
}
public static <T extends HasFix> Downsample<T> minTimeStep(long duration, TimeUnit unit) {
return new Downsample<T>(unit.toMillis(duration), Functions.<T> alwaysFalse());
}
public static <T extends HasFix> Downsample<T> minTimeStep(long duration, TimeUnit unit,
Func1<T, Boolean> selector) {
return new Downsample<T>(unit.toMillis(duration), selector);
}
@Override
public Observable<T> call(Observable<T> fixes) {
Observable<T> result = fixes.scan((latest, fix) -> {
if (fix.fix().mmsi() != latest.fix().mmsi())
throw new RuntimeException("can only downsample a single vessel");
else if (fix.fix().time() < latest.fix().time())
throw new RuntimeException("not in ascending time order!");
else if (fix.fix().time() - latest.fix().time() >= minTimeBetweenFixesMs
|| selector.call(fix))
return fix;
else
return latest;
});
if (minTimeBetweenFixesMs > 0)
// throw away repeats
result = result.distinctUntilChanged(f -> f.fix().time());
return result;
}
public static Observable<Integer> downsample(final File input, final File output,
Pattern pattern, final long duration, final TimeUnit unit) {
return Formats.transform(input, output, pattern, Downsample.minTimeStep(duration, unit),
FIXES_WRITER_WITHOUT_MMSI, Functions.<String> identity());
}
private static Action2<List<HasFix>, File> FIXES_WRITER_WITHOUT_MMSI = (list, file) -> {
BinaryFixesWriter.writeFixes(list, file, false, false, BinaryFixesFormat.WITHOUT_MMSI);
};
}