package au.gov.amsa.geo.distance;
import static au.gov.amsa.geo.distance.EffectiveSpeedChecker.effectiveSpeedOk;
import static com.google.common.base.Optional.of;
import rx.Observable.Operator;
import rx.Subscriber;
import au.gov.amsa.geo.model.SegmentOptions;
import au.gov.amsa.risky.format.Fix;
import com.google.common.base.Optional;
/**
* Given a sequence of fixes the first fix is consider to be the first fix that
* passes an effective speed check with its following fix. Having established
* the first fix then following fixes are discarded from the sequence that fail
* the effective speed check with the last confirmed fix.
*/
public class OperatorEffectiveSpeedChecker implements Operator<EffectiveSpeedCheck, Fix> {
private final SegmentOptions options;
public OperatorEffectiveSpeedChecker(SegmentOptions options) {
this.options = options;
}
@Override
public Subscriber<? super Fix> call(Subscriber<? super EffectiveSpeedCheck> child) {
Subscriber<Fix> parent = createSubscriber(child, options);
return parent;
}
private static Subscriber<Fix> createSubscriber(
final Subscriber<? super EffectiveSpeedCheck> child, final SegmentOptions options) {
return new Subscriber<Fix>(child) {
/**
* The last emitted fix.
*/
private Optional<Fix> previousFix = Optional.absent();
/**
* The latest fix.
*/
private Optional<Fix> first = Optional.absent();
@Override
public void onCompleted() {
child.onCompleted();
}
@Override
public void onError(Throwable e) {
child.onError(e);
}
@Override
public void onNext(Fix fix) {
if (!previousFix.isPresent()) {
if (!first.isPresent()) {
// buffer the very first fix. It will get emitted only
// if passes effective speed check with the following
// fix. If it does not then the next fix will be
// considered as the next candidate for being the first
// fix.
first = of(fix);
// because no emission we request again to honour
// backpressure
request(1);
} else if (effectiveSpeedOk(first.get(), fix, options)) {
previousFix = of(fix);
child.onNext(new EffectiveSpeedCheck(first.get(), true));
child.onNext(new EffectiveSpeedCheck(fix, true));
} else {
first = of(fix);
// because no emission we request again to honour
// backpressure
request(1);
}
} else if (effectiveSpeedOk(previousFix.get(), fix, options)) {
previousFix = of(fix);
child.onNext(new EffectiveSpeedCheck(fix, true));
} else {
// failed effective speed check
child.onNext(new EffectiveSpeedCheck(fix, false));
}
}
};
}
}