1 package org.wikimedia.search.extra.superdetectnoop;
2
3 import static java.lang.Math.abs;
4 import static org.wikimedia.search.extra.superdetectnoop.ChangeHandler.TypeSafe.nullAndTypeSafe;
5
6 import javax.annotation.Nonnull;
7
8
9
10
11 public class WithinPercentageHandler implements ChangeHandler.NonnullChangeHandler<Number> {
12 public static class Recognizer implements ChangeHandler.Recognizer {
13 private static final String PREFIX = "within ";
14 private static final String SUFFIX = "%";
15
16 @Override
17 public ChangeHandler<Object> build(String description) {
18 if (!description.startsWith(PREFIX)) {
19 return null;
20 }
21 if (!description.endsWith(SUFFIX)) {
22 return null;
23 }
24 try {
25 double percentage = Double.parseDouble(description.substring(PREFIX.length(), description.length() - SUFFIX.length()));
26 return nullAndTypeSafe(Number.class, new WithinPercentageHandler(percentage / 100));
27 } catch (NumberFormatException e) {
28
29 return null;
30 }
31 }
32 }
33
34 private final double absoluteDifference;
35
36 public WithinPercentageHandler(double absoluteDifference) {
37 this.absoluteDifference = absoluteDifference;
38 }
39
40 @Override
41 public ChangeHandler.Result handle(@Nonnull Number oldValue, @Nonnull Number newValue) {
42 if (oldValue.doubleValue() == 0) {
43 return ChangeHandler.Changed.forBoolean(newValue.doubleValue() == 0, newValue);
44 }
45 return ChangeHandler.Changed.forBoolean(
46 abs((newValue.doubleValue() - oldValue.doubleValue()) / oldValue.doubleValue()) < absoluteDifference, newValue);
47 }
48 }