package geniusweb.protocol.session.shaop; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonCreator; import geniusweb.actions.Action; import geniusweb.actions.PartyId; import geniusweb.progress.Progress; import geniusweb.protocol.ProtocolException; import geniusweb.protocol.partyconnection.ProtocolToPartyConnections; import geniusweb.protocol.session.SessionResult; import geniusweb.protocol.session.SessionSettings; import geniusweb.protocol.session.SessionState; import geniusweb.references.PartyWithProfile; /** * The state without all the "with" functioality to make this more readable. * immutable. json-serializable. */ public abstract class BareSHAOPState implements SessionState { protected final List actions; protected final transient ProtocolToPartyConnections connections; protected final Progress progress; protected final SHAOPSettings settings; protected final ProtocolException error; protected final int teamNr; protected final Map partyNumbers; protected final Map totalSpent; /** * * @param actions value for actions done so far. null equals to empty list * @param conns the currently existing connections. Can be empty/null. * Each connection represents another party. Normally the * connections are in the order SHAOP1,COB1,SHAOP2,COB2,.. * so 2 parties for each team. The protocol should check * this. * @param progr the {@link Progress} that governs this session. Can be * null if session did not yet start. * @param settings the settings used for the session * @param e the exception that occured, usually null. All errors * occuring due to faulty {@link Action}s translate to * {@link ProtocolException}s. All errors in our own code * are bugs (not ProtocolExceptions) and should result in a * throw. * @param teamNr the teamnr (0,1,2..) that has the turn. 2* gives index * {@link #connections} and settings * @param partyNrs a map for each known PartyId to a number. The number is * the index in both {@link SHAOPSettings#getTeams()} and in * {@link #connections}. null is empyt map. * @param spent total accumulated elicitation costs so far for each * party. only SHAOP parties accumulate costs. null = empty * map */ @JsonCreator public BareSHAOPState(List actions, ProtocolToPartyConnections conns, Progress progr, SHAOPSettings settings, ProtocolException e, int teamNr, Map partyNrs, Map spent) { if (conns == null) { this.connections = new ProtocolToPartyConnections( Collections.emptyList()); } else { this.connections = conns; } if (actions == null) { this.actions = new LinkedList<>(); } else { this.actions = actions; } if (partyNrs == null) { this.partyNumbers = Collections.emptyMap(); } else { this.partyNumbers = partyNrs; } if (spent == null) { this.totalSpent = Collections.emptyMap(); } else { this.totalSpent = spent; } if (!connections.allunique()) { throw new IllegalArgumentException( "There can not be multiple connections for a party:" + conns); } this.progress = progr; this.settings = settings; this.error = e; this.teamNr = teamNr; } public ProtocolToPartyConnections getConnections() { return connections; } /** * * @return party ID of current team leader (SHAOP party) */ public PartyId getCurrentTeam() { return connections.get(2 * teamNr).getParty(); } /** * @param id the {@link PartyId} * @return the PartyWithProfile associated with that id. */ public PartyWithProfile getPartyProfile(PartyId id) { return settings.getAllParties().get(partyNumbers.get(id)); } /** * * @return the index of each party */ public Map getPartyNumbers() { return Collections.unmodifiableMap(partyNumbers); } /** * * @return unmodifyable list of actions done so far. */ @Override public List getActions() { return Collections.unmodifiableList(actions); } @Override public Progress getProgress() { return progress; } @Override public SessionSettings getSettings() { return settings; } @Override public boolean isFinal(long currentTimeMs) { return error != null || (progress != null && progress.isPastDeadline(currentTimeMs)); } public ProtocolException getError() { return error; } @Override public String toString() { return this.getClass().getSimpleName() + "[" + actions + "," + connections + "," + progress + "," + settings + "," + error + "]"; } @Override public List getResults() { Map penalties = new HashMap<>(); for (PartyId party : partyNumbers.keySet()) { Double spent = totalSpent.get(party); if (spent == null) { spent = 0d; } else { spent = Math.max(0, Math.min(1.0, spent)); } penalties.put(party, spent); } Map allparties = partyNumbers.keySet() .stream().collect(Collectors.toMap(pid -> pid, pid -> settings .getAllParties().get(partyNumbers.get(pid)))); return Arrays.asList(new SessionResult(allparties, getAgreements(), penalties, getError())); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((actions == null) ? 0 : actions.hashCode()); result = prime * result + ((error == null) ? 0 : error.hashCode()); result = prime * result + ((partyNumbers == null) ? 0 : partyNumbers.hashCode()); result = prime * result + ((progress == null) ? 0 : progress.hashCode()); result = prime * result + ((settings == null) ? 0 : settings.hashCode()); result = prime * result + teamNr; result = prime * result + ((totalSpent == null) ? 0 : totalSpent.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; BareSHAOPState other = (BareSHAOPState) obj; if (actions == null) { if (other.actions != null) return false; } else if (!actions.equals(other.actions)) return false; if (error == null) { if (other.error != null) return false; } else if (!error.equals(other.error)) return false; if (partyNumbers == null) { if (other.partyNumbers != null) return false; } else if (!partyNumbers.equals(other.partyNumbers)) return false; if (progress == null) { if (other.progress != null) return false; } else if (!progress.equals(other.progress)) return false; if (settings == null) { if (other.settings != null) return false; } else if (!settings.equals(other.settings)) return false; if (teamNr != other.teamNr) return false; if (totalSpent == null) { if (other.totalSpent != null) return false; } else if (!totalSpent.equals(other.totalSpent)) return false; return true; } }