/*
   * (non-Javadoc)
   *
   * @see poke.server.election.Election#process(eye.Comm.LeaderElection)
   *
   * @return The Management instance returned represents the message to send
   * on. If null, no action is required. Not a great choice to convey to the
   * caller; can be improved upon easily.
   */
  @Override
  public Management process(Management mgmt) {
    if (!mgmt.hasElection()) return null;

    LeaderElection req = mgmt.getElection();
    if (req.getExpires() <= System.currentTimeMillis()) {
      // election has expired without a conclusion?
    }

    Management rtn = null;

    if (req.getAction().getNumber() == ElectAction.DECLAREELECTION_VALUE) {
      // an election is declared!

      // required to eliminate duplicate messages - on a declaration,
      // should not happen if the network does not have cycles
      List<VectorClock> rtes = mgmt.getHeader().getPathList();
      for (VectorClock rp : rtes) {
        if (rp.getNodeId() == this.nodeId) {
          // message has already been sent to me, don't use and
          // forward
          return null;
        }
      }

      // I got here because the election is unknown to me

      // this 'if debug is on' should cover the below dozen or so
      // println()s. It is here to help with seeing when an election
      // occurs.
      if (logger.isDebugEnabled()) {}

      System.out.println("\n\n*********************************************************");
      System.out.println("   RAFT ELECTION: Election declared");
      System.out.println("   Election ID:  " + req.getElectId());
      System.out.println("   Rcv from:     Node " + mgmt.getHeader().getOriginator());
      System.out.println("   Expires:      " + new Date(req.getExpires()));
      System.out.println("   Nominates:    Node " + req.getCandidateId());
      System.out.println("   Desc:         " + req.getDesc());
      System.out.print("   Routing tbl:  [");
      for (VectorClock rp : rtes)
        System.out.print(
            "Node " + rp.getNodeId() + " (" + rp.getVersion() + "," + rp.getTime() + "), ");
      System.out.println("]");
      System.out.println("*********************************************************\n\n");

      // sync master IDs to current election
      ElectionIDGenerator.setMasterID(req.getElectId());

      /**
       * a new election can be declared over an existing election.
       *
       * <p>TODO need to have an monotonically increasing ID that we can test
       */
      boolean isNew = updateCurrent(req);
      rtn = castVote(mgmt, isNew);

    } else if (req.getAction().getNumber() == ElectAction.DECLAREVOID_VALUE) {
      // no one was elected, I am dropping into standby mode
      logger.info("TODO: no one was elected, I am dropping into standby mode");
      this.clear();
      notify(false, null);
    } else if (req.getAction().getNumber() == ElectAction.DECLAREWINNER_VALUE) {
      // some node declared itself the leader
      logger.info(
          "Election "
              + req.getElectId()
              + ": Node "
              + req.getCandidateId()
              + " is declared the leader");
      updateCurrent(mgmt.getElection());
      current.active = false; // it's over
      notify(true, req.getCandidateId());
    } else if (req.getAction().getNumber() == ElectAction.ABSTAIN_VALUE) {
      // for some reason, a node declines to vote - therefore, do nothing
    } else if (req.getAction().getNumber() == ElectAction.NOMINATE_VALUE) {
      boolean isNew = updateCurrent(mgmt.getElection());
      rtn = castVote(mgmt, isNew);
    } else {
      // this is me!
    }

    return rtn;
  }
 @Override
 public Integer createElectionID() {
   return ElectionIDGenerator.nextID();
 }