package geniusweb.progress; import java.util.Date; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; /** * progress in terms of number of rounds. The round has to be updated by the * user of this class, calling {@link #advance()}. immutable. */ @JsonTypeName("rounds") public class ProgressRounds implements Progress { private final Integer duration; private final Integer currentRound; private final Date endtime; /** * * @param deadline length max number of rounds, must be positive (not 0) * @param currentRound the current round number (can be from 0 to deadlne). * When = deadline, it means the progress has gone past * the deadline. * @param end the termination time of this session. */ @JsonCreator public ProgressRounds(@JsonProperty("duration") Integer deadline, @JsonProperty("currentRound") Integer currentRound, @JsonProperty("endtime") Date end) { if (deadline <= 0) throw new IllegalArgumentException( "deadline must be positive but is " + deadline); if (currentRound < 0 || currentRound > deadline) { throw new IllegalArgumentException( "current round must be inside [0," + deadline + "]"); } this.duration = deadline; this.currentRound = currentRound; this.endtime = end; } @Override public Date getTerminationTime() { return endtime; } /** * * @return the current round. First round is 0. It is recommended that you * use the functions in {@link Progress} instead of this, to ensure * your code works with all implementations of Progress including * future developments. */ public Integer getCurrentRound() { return currentRound; } /** * * @return total number of rounds. It is recommended that you use the * functions in {@link Progress} instead of this, to ensure your * code works with all implementations of Progress including future * developments. */ public Integer getTotalRounds() { return duration; } @Override public Double get(Long currentTimeMs) { // deadline and current both are limited to MAXINT is 32 bits; double // fits 52 // bits so this should not result in accuracy issues double ratio = (double) currentRound / (double) duration; if (ratio > 1d) ratio = 1d; else if (ratio < 0d) ratio = 0d; return ratio; } @Override public boolean isPastDeadline(Long currentTimeMs) { return currentRound >= duration || currentTimeMs > endtime.getTime(); } /** * * @return new ProgressRounds with round 1 advanced (or this, if * currentRound= duration). This is up to the user, as it is up to * the used protocol what exactly is a round. */ public ProgressRounds advance() { if (duration == currentRound) return this; return new ProgressRounds(duration, currentRound + 1, endtime); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((currentRound == null) ? 0 : currentRound.hashCode()); result = prime * result + ((duration == null) ? 0 : duration.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; ProgressRounds other = (ProgressRounds) obj; if (currentRound == null) { if (other.currentRound != null) return false; } else if (!currentRound.equals(other.currentRound)) return false; if (duration == null) { if (other.duration != null) return false; } else if (!duration.equals(other.duration)) return false; return true; } @Override public String toString() { return "ProgressRounds[" + currentRound + " of " + duration + "]"; } }