package com.subgraph.orchid.directory;
import java.util.Date;
import com.subgraph.orchid.Directory;
import com.subgraph.orchid.GuardEntry;
import com.subgraph.orchid.Router;
import com.subgraph.orchid.data.HexDigest;
public class GuardEntryImpl implements GuardEntry {
private final static String NL = System.getProperty("line.separator");
private final Directory directory;
private final StateFile stateFile;
private final String nickname;
private final String identity;
private final Object lock = new Object();
private String version;
private Date createdTime;
private boolean isAdded;
private Date unlistedSince;
private Date downSince;
private Date lastConnect;
GuardEntryImpl(Directory directory, StateFile stateFile, String nickname, String identity) {
this.directory = directory;
this.stateFile = stateFile;
this.nickname = nickname;
this.identity = identity;
}
void setAddedFlag() {
isAdded = true;
}
void setVersion(String version) {
this.version = version;
}
void setCreatedTime(Date date) {
this.createdTime = date;
}
void setUnlistedSince(Date date) {
synchronized(lock) {
unlistedSince = date;
}
}
void setDownSince(Date downSince, Date lastTried) {
synchronized (lock) {
this.downSince = downSince;
this.lastConnect = lastTried;
}
}
public boolean isAdded() {
return isAdded;
}
public void markAsDown() {
synchronized(lock) {
final Date now = new Date();
if(downSince == null) {
downSince = now;
} else {
lastConnect = now;
}
}
if(isAdded) {
stateFile.writeFile();
}
}
public void clearDownSince() {
synchronized (lock) {
downSince = null;
lastConnect = null;
}
if(isAdded) {
stateFile.writeFile();
}
}
public void clearUnlistedSince() {
synchronized (lock) {
unlistedSince = null;
}
if(isAdded) {
stateFile.writeFile();
}
}
public String getNickname() {
return nickname;
}
public String getIdentity() {
return identity;
}
public String getVersion() {
return version;
}
public Date getCreatedTime() {
synchronized (lock) {
return dup(createdTime);
}
}
public Date getDownSince() {
synchronized (lock) {
return dup(downSince);
}
}
public Date getLastConnectAttempt() {
synchronized (lock) {
return dup(lastConnect);
}
}
public Date getUnlistedSince() {
synchronized (lock) {
return dup(unlistedSince);
}
}
private Date dup(Date date) {
if(date == null) {
return null;
} else {
return new Date(date.getTime());
}
}
public String writeToString() {
final StringBuilder sb = new StringBuilder();
synchronized (lock) {
appendEntryGuardLine(sb);
appendEntryGuardAddedBy(sb);
if(downSince != null) {
appendEntryGuardDownSince(sb);
}
if(unlistedSince != null) {
appendEntryGuardUnlistedSince(sb);
}
}
return sb.toString();
}
private void appendEntryGuardLine(StringBuilder sb) {
sb.append(StateFile.KEYWORD_ENTRY_GUARD);
sb.append(" ");
sb.append(nickname);
sb.append(" ");
sb.append(identity);
sb.append(NL);
}
private void appendEntryGuardAddedBy(StringBuilder sb) {
sb.append(StateFile.KEYWORD_ENTRY_GUARD_ADDED_BY);
sb.append(" ");
sb.append(identity);
sb.append(" ");
sb.append(version);
sb.append(" ");
sb.append(formatDate(createdTime));
sb.append(NL);
}
private void appendEntryGuardDownSince(StringBuilder sb) {
if(downSince == null) {
return;
}
sb.append(StateFile.KEYWORD_ENTRY_GUARD_DOWN_SINCE);
sb.append(" ");
sb.append(formatDate(downSince));
if(lastConnect != null) {
sb.append(" ");
sb.append(formatDate(lastConnect));
}
sb.append(NL);
}
private void appendEntryGuardUnlistedSince(StringBuilder sb) {
if(unlistedSince == null) {
return;
}
sb.append(StateFile.KEYWORD_ENTRY_GUARD_UNLISTED_SINCE);
sb.append(" ");
sb.append(formatDate(unlistedSince));
sb.append(NL);
}
private String formatDate(Date date) {
return stateFile.formatDate(date);
}
public Router getRouterForEntry() {
final HexDigest id = HexDigest.createFromString(identity);
return directory.getRouterByIdentity(id);
}
public boolean testCurrentlyUsable() {
final Router router = getRouterForEntry();
boolean isUsable = router != null && router.isValid() && router.isPossibleGuard() && router.isRunning();
if(isUsable) {
markUsable();
return true;
} else {
markUnusable();
return false;
}
}
private void markUsable() {
synchronized (lock) {
if(unlistedSince != null) {
unlistedSince = null;
if(isAdded) {
stateFile.writeFile();
}
}
}
}
private synchronized void markUnusable() {
synchronized (lock) {
if(unlistedSince == null) {
unlistedSince = new Date();
if(isAdded) {
stateFile.writeFile();
}
}
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((identity == null) ? 0 : identity.hashCode());
result = prime * result
+ ((nickname == null) ? 0 : nickname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
GuardEntryImpl other = (GuardEntryImpl) obj;
if (identity == null) {
if (other.identity != null)
return false;
} else if (!identity.equals(other.identity))
return false;
if (nickname == null) {
if (other.nickname != null)
return false;
} else if (!nickname.equals(other.nickname))
return false;
return true;
}
}