8b1b2ee522b28588643047813d01c621fc454dbb
[Sone.git] / src / main / java / net / pterodactylus / sone / core / SoneModificationDetector.java
1 package net.pterodactylus.sone.core;
2
3 import static com.google.common.base.Optional.absent;
4 import static com.google.common.base.Optional.of;
5 import static com.google.common.base.Ticker.systemTicker;
6 import static java.util.concurrent.TimeUnit.NANOSECONDS;
7
8 import java.util.concurrent.atomic.AtomicInteger;
9
10 import net.pterodactylus.sone.data.Sone;
11
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Ticker;
15
16 /**
17  * Class that detects {@link Sone} modifications (as per their {@link
18  * Sone#getFingerprint() fingerprints} and determines when a modified Sone may
19  * be inserted.
20  *
21  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
22  */
23 class SoneModificationDetector {
24
25         private final Ticker ticker;
26         private final LockableFingerprintProvider lockableFingerprintProvider;
27         private final AtomicInteger insertionDelay;
28         private Optional<Long> lastModificationTime;
29         private String originalFingerprint;
30         private String lastFingerprint;
31
32         SoneModificationDetector(LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
33                 this(systemTicker(), lockableFingerprintProvider, insertionDelay);
34         }
35
36         @VisibleForTesting
37         SoneModificationDetector(Ticker ticker, LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
38                 this.ticker = ticker;
39                 this.lockableFingerprintProvider = lockableFingerprintProvider;
40                 this.insertionDelay = insertionDelay;
41                 originalFingerprint = lockableFingerprintProvider.getFingerprint();
42                 lastFingerprint = originalFingerprint;
43         }
44
45         public boolean isEligibleForInsert() {
46                 if (lockableFingerprintProvider.isLocked()) {
47                         lastModificationTime = absent();
48                         lastFingerprint = "";
49                         return false;
50                 }
51                 String fingerprint = lockableFingerprintProvider.getFingerprint();
52                 if (originalFingerprint.equals(fingerprint)) {
53                         lastModificationTime = absent();
54                         lastFingerprint = fingerprint;
55                         return false;
56                 }
57                 if (!lastFingerprint.equals(fingerprint)) {
58                         lastModificationTime = of(ticker.read());
59                         lastFingerprint = fingerprint;
60                         return false;
61                 }
62                 return insertionDelayHasPassed();
63         }
64
65         public String getOriginalFingerprint() {
66                 return originalFingerprint;
67         }
68
69         public void setFingerprint(String fingerprint) {
70                 originalFingerprint = fingerprint;
71                 lastFingerprint = originalFingerprint;
72                 lastModificationTime = absent();
73         }
74
75         private boolean insertionDelayHasPassed() {
76                 return NANOSECONDS.toSeconds(ticker.read() - lastModificationTime.get()) >= insertionDelay.get();
77         }
78
79         public boolean isModified() {
80                 return !lockableFingerprintProvider.getFingerprint().equals(originalFingerprint);
81         }
82
83         /**
84          * Provider for a fingerprint and the information if a {@link Sone} is locked. This
85          * prevents us from having to lug a Sone object around.
86          *
87          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
88          */
89         static interface LockableFingerprintProvider {
90
91                 boolean isLocked();
92                 String getFingerprint();
93
94         }
95
96 }