@Override
  public void handleAccepted(PaxosMessage proposal) {
    ensureSize(chosen, proposal.getInstanceNum() + 1); // Prevent NPE

    if (chosen.get(proposal.getInstanceNum()) != null)
      return; // Something has already been chosen so I dont care anymore.

    List<PaxosMessage> acceptedVotes = proposalAcceptedVotes.get(proposal.getInstanceNum());
    if (acceptedVotes == null) {
      acceptedVotes = new ArrayList<PaxosMessage>();
      acceptedVotes.add(proposal);
      proposalAcceptedVotes.put(proposal.getInstanceNum(), acceptedVotes);
    } else {
      for (PaxosMessage acceptedVote : acceptedVotes) {
        if (proposal.getProposerId() == acceptedVote.getProposerId())
          return; // This person is reaffirming their acceptance of this instances proposal.
      }
      acceptedVotes.add(proposal);
      proposalAcceptedVotes.put(proposal.getInstanceNum(), acceptedVotes);
    }
    // handle being chosen
    if (proposalAcceptedVotes.get(proposal.getInstanceNum()).size() >= serverSet.getQuorumSize()) {
      onChosen(proposal);
    }
  }
  /**
   * Work through the chosen messages sending what we have left and stopping once we get to an
   * unfilled slot or the end of the array.
   */
  private void onChosen(PaxosMessage proposal) {
    chosen.set(proposal.getInstanceNum(), (ChatMessage) proposal.getValue());
    if (proposal.getInstanceNum() >= nextInstance) nextInstance = proposal.getInstanceNum() + 1;

    while (lastSent + 1 < chosen.size()) {
      ChatMessage toSend = chosen.get(lastSent + 1);
      if (toSend != null) {
        if (nodeIsLeader()) sendToClients(toSend);
        lastSent++;
      } else {
        break; // There is still a missing slot.
      }
    }
  }
  @Override
  public void handlePropose(PaxosMessage proposal) {
    if (preparedFor > proposal.getProposeNum()) return;

    ensureSize(accepted, proposal.getInstanceNum() + 1);
    ensureSize(chosen, proposal.getInstanceNum() + 1);

    accepted.set(proposal.getInstanceNum(), (ChatMessage) proposal.getValue());
    // Send accept to all
    /* sendAllMessage(new DefaultPaxosMessage(proposal.getInstanceNum(),
    proposal.getProposeNum(),
    id,
    PaxosMessageType.ACCEPTED,
    proposal.getValue())); */
    // Silently accept proposals
  }
  @Override
  public void handlePrepareResponse(PaxosMessage response) {
    if (!prepareResponseFrom.contains(response.getProposerId()))
      prepareResponseFrom.add(
          response.getProposerId()); // This is a new server accepted our prepare request.

    List<ChatMessage> remoteAccepted = (List<ChatMessage>) response.getValue();
    for (int i = 0; i < remoteAccepted.size(); i++) {
      if (chosen.size() > i && chosen.get(i) != null) continue;
      if (remoteAccepted.get(i) != null) {
        propose(
            new DefaultPaxosMessage(
                i, nextPropose, id, PaxosMessageType.PROPOSE, remoteAccepted.get(i)));
        if (i > nextInstance) nextInstance = i;
      }
    }
  }
 private void handleRecoveryResponse(PaxosMessage recoveryResponse) {
   ArrayList<ChatMessage> newChosen = (ArrayList<ChatMessage>) recoveryResponse.getValue();
   ensureSize(chosen, newChosen.size());
   for (int i = 0; i < newChosen.size(); i++) {
     if (chosen.get(i) == null) {
       chosen.set(i, newChosen.get(i));
     } else if (!chosen.get(i).equals(newChosen.get(i))) {
       System.out.println("We have an error, two servers conflict in their chosen values.");
     }
   }
 }
 public void messageReceived(IoSession ioSession, Object message) throws Exception {
   if (message instanceof DefaultPaxosMessage) {
     PaxosMessage paxosMessage = (DefaultPaxosMessage) message;
     switch (paxosMessage.getType()) {
       case PROPOSE:
         handlePropose(paxosMessage);
         break;
       case ACCEPTED:
         handleAccepted(paxosMessage);
         break;
       case PREPARE:
         handlePrepare(
             (Integer) paxosMessage.getValue(),
             paxosMessage.getProposerId()); // PSN and consensus instance dont matter
         break;
       case PREPARE_RESP:
         handlePrepareResponse(paxosMessage);
         break;
       case RECOVERY:
         handleRecovery(paxosMessage);
         break;
       case RECOVERY_RESP:
         handleRecoveryResponse(paxosMessage);
         break;
       case PING:
         if (paxosMessage.getProposerId() == getLeader()) // Leaders HeartBeat
         leaderLastHeard = new Date();
         else if (((Integer) paxosMessage.getValue())
             > preparedFor) { // I came alive and the leader is not who I thought.
           preparedFor = ((Integer) paxosMessage.getValue());
           handlePrepare(preparedFor, getLeader());
           sendRecovery();
         }
         break;
       default:
         throw new Exception(
             "received PaxosMessage of unknown type" + paxosMessage.getType().name());
     }
   } else if (message instanceof ChatMessage) { // Some client sent or some server forwarded.
     if (nodeIsLeader()) {
       propose(
           new DefaultPaxosMessage(
               nextInstance, nextPropose, id, PaxosMessageType.PROPOSE, (ChatMessage) message));
       nextInstance++;
     } else {
       sendToLeader((ChatMessage) message);
     }
   } else {
     throw new Exception("Unknown message type:" + message.getClass().getSimpleName());
   }
 }
 private void handleRecovery(PaxosMessage recoveryRequest) {
   PaxosMessage recoveryResponse =
       new DefaultPaxosMessage(-1, -1, id, PaxosMessageType.RECOVERY_RESP, chosen);
   sendMessage(recoveryResponse, recoveryRequest.getProposerId());
 }