/** FIXME clients can undo each others moves. FIXME information about the principal is lost. */
  public void undoLastMove() {
    if (moveStack.size() > 0) {
      Move m = (Move) moveStack.removeLast();
      MoveStatus ms;

      synchronized (world) {
        ms = m.undoMove(world, Player.NOBODY);
      }

      if (ms != MoveStatus.MOVE_OK) {
        logger.log(Level.INFO, "Couldn't undo move!");

        /* push it back on the stack to prevent further
         * out-of-order undos */
        moveStack.add(m);
      }

      forwardMove(m, ms);
    } else {
      logger.log(Level.INFO, "No moves on stack.");
    }
  }
  void processMove(Move move, FreerailsPrincipal p) {
    /*
     * if the server is submitting the move, then act on behalf of whoever
     * move was submitted for
     */
    if (p.equals(Player.AUTHORITATIVE)) p = move.getPrincipal();

    moveStack.add(move);

    if (moveStack.size() > MAX_UNDOS) {
      moveStack.removeFirst();
    }

    MoveStatus ms;

    synchronized (world) {
      ms = move.doMove(world, p);
    }

    if (ms != MoveStatus.MOVE_OK)
      logger.log(Level.INFO, "Server rejected move because " + ms + ": " + move);

    forwardMove(move, ms);
  }
 /** @see MoveReceiver#processMove(Move) */
 public void processMove(Move move) {
   processMove(move, move.getPrincipal());
 }