filebot/source/net/filebot/ui/sfv/ChecksumRow.java

195 lines
4.1 KiB
Java

package net.filebot.ui.sfv;
import static net.filebot.hash.VerificationUtilities.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.event.SwingPropertyChangeSupport;
import net.filebot.hash.HashType;
class ChecksumRow {
private String name;
private Map<File, ChecksumCell> hashes = new HashMap<File, ChecksumCell>(4);
private State state = State.UNKNOWN;
/**
* Checksum that is embedded in the file name (e.g. Test[49A93C5F].txt)
*/
private String embeddedChecksum;
public static enum State {
UNKNOWN,
OK,
WARNING,
ERROR
}
public ChecksumRow(String name) {
this.name = name;
this.embeddedChecksum = getEmbeddedChecksum(name);
}
public String getName() {
return name;
}
public State getState() {
return state;
}
protected void setState(State newValue) {
State oldValue = this.state;
this.state = newValue;
pcs.firePropertyChange("state", oldValue, newValue);
}
public ChecksumCell getChecksum(File root) {
return hashes.get(root);
}
public Collection<ChecksumCell> values() {
return Collections.unmodifiableCollection(hashes.values());
}
public ChecksumCell put(ChecksumCell cell) {
ChecksumCell old = hashes.put(cell.getRoot(), cell);
// update state immediately, don't fire property change
state = getState(hashes.values());
// keep state up-to-date
cell.addPropertyChangeListener(updateStateListener);
return old;
}
public void dispose() {
// clear property change support
for (PropertyChangeListener listener : pcs.getPropertyChangeListeners()) {
pcs.removePropertyChangeListener(listener);
}
for (ChecksumCell cell : hashes.values()) {
cell.dispose();
}
name = null;
embeddedChecksum = null;
hashes = null;
state = null;
pcs = null;
}
protected State getState(Collection<ChecksumCell> cells) {
// check states before we bother comparing the hash values
for (ChecksumCell cell : cells) {
if (cell.getState() == ChecksumCell.State.ERROR) {
// one error cell -> error state
return State.ERROR;
} else if (cell.getState() != ChecksumCell.State.READY) {
// one cell that is not ready yet -> unknown state
return State.UNKNOWN;
}
}
// compare hash values
Set<String> checksumSet = new HashSet<String>(2);
Set<State> verdictSet = EnumSet.noneOf(State.class);
for (HashType type : HashType.values()) {
checksumSet.clear();
for (ChecksumCell cell : cells) {
String checksum = cell.getChecksum(type);
if (checksum != null) {
checksumSet.add(checksum.toLowerCase());
}
}
verdictSet.add(getVerdict(checksumSet));
}
// ERROR > WARNING > OK > UNKOWN
return Collections.max(verdictSet);
}
protected State getVerdict(Set<String> checksumSet) {
if (checksumSet.size() < 1) {
// no hash values
return State.UNKNOWN;
} else if (checksumSet.size() > 1) {
// hashes don't match, something is wrong
return State.ERROR;
} else {
// all hashes match
if (embeddedChecksum != null) {
String checksum = checksumSet.iterator().next();
if (checksum.length() == embeddedChecksum.length() && !checksum.equalsIgnoreCase(embeddedChecksum)) {
return State.WARNING;
}
}
return State.OK;
}
}
@Override
public String toString() {
return String.format("%s %s %s", state, name, hashes);
}
private final PropertyChangeListener updateStateListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())) {
setState(getState(hashes.values()));
}
}
};
private SwingPropertyChangeSupport pcs = new SwingPropertyChangeSupport(this, true);
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
}