package net.pterodactylus.sone.core;
import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.of;
import static com.google.common.base.Ticker.systemTicker;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.atomic.AtomicInteger;
import net.pterodactylus.sone.data.Sone;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Ticker;
/**
* Class that detects {@link Sone} modifications (as per their {@link
* Sone#getFingerprint() fingerprints} and determines when a modified Sone may
* be inserted.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
class SoneModificationDetector {
private final Ticker ticker;
private final LockableFingerprintProvider lockableFingerprintProvider;
private final AtomicInteger insertionDelay;
private Optional<Long> lastModificationTime;
private String lastInsertFingerprint;
private String lastCheckFingerprint;
SoneModificationDetector(LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
this(systemTicker(), lockableFingerprintProvider, insertionDelay);
}
@VisibleForTesting
SoneModificationDetector(Ticker ticker, LockableFingerprintProvider lockableFingerprintProvider, AtomicInteger insertionDelay) {
this.ticker = ticker;
this.lockableFingerprintProvider = lockableFingerprintProvider;
this.insertionDelay = insertionDelay;
lastCheckFingerprint = lastInsertFingerprint;
}
public boolean isEligibleForInsert() {
if (lockableFingerprintProvider.isLocked()) {
lastModificationTime = absent();
lastCheckFingerprint = "";
return false;
}
String fingerprint = lockableFingerprintProvider.getFingerprint();
if (fingerprint.equals(lastInsertFingerprint)) {
lastModificationTime = absent();
lastCheckFingerprint = fingerprint;
return false;
}
if (!Objects.equal(lastCheckFingerprint, fingerprint)) {
lastModificationTime = of(ticker.read());
lastCheckFingerprint = fingerprint;
return false;
}
return insertionDelayHasPassed();
}
public String getLastInsertFingerprint() {
return lastInsertFingerprint;
}
public void setFingerprint(String fingerprint) {
lastInsertFingerprint = fingerprint;
lastCheckFingerprint = lastInsertFingerprint;
lastModificationTime = absent();
}
private boolean insertionDelayHasPassed() {
return NANOSECONDS.toSeconds(ticker.read() - lastModificationTime.get()) >= insertionDelay.get();
}
public boolean isModified() {
return !Objects.equal(lockableFingerprintProvider.getFingerprint(), lastInsertFingerprint);
}
/**
* Provider for a fingerprint and the information if a {@link Sone} is locked. This
* prevents us from having to lug a Sone object around.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
static interface LockableFingerprintProvider {
boolean isLocked();
String getFingerprint();
}
}