* @param unit The <code>Unit</code> that is trading.
     * @param settlement The <code>Settlement</code> to trade with.
     * @param agreement The <code>DiplomaticTrade</code> to consider.
     * @return An <code>Element</code> encapsulating this action.
     */
    public Element diplomaticTrade(ServerPlayer serverPlayer, Unit unit,
                                   Settlement settlement,
                                   DiplomaticTrade agreement) {
        ChangeSet cs = new ChangeSet();
        ServerPlayer otherPlayer = (ServerPlayer) settlement.getOwner();
        DiplomacySession session
            = TransactionSession.lookup(DiplomacySession.class,
                unit, settlement);
        TradeStatus status;
        Player.makeContact(serverPlayer, otherPlayer);

        switch (status = agreement.getStatus()) {
        case PROPOSE_TRADE:
            if (session == null) {
                Unit.MoveType mt = unit.getMoveType(settlement.getTile());
                switch (mt) {
                case ENTER_FOREIGN_COLONY_WITH_SCOUT:
                case ENTER_SETTLEMENT_WITH_CARRIER_AND_GOODS:
                    break;
                default:
                    return DOMMessage.clientError("Unable to enter "
                        + settlement.getId() + ": " + mt.whyIllegal());
                }
                session = new DiplomacySession(unit, settlement);
                unit.setMovesLeft(0);
                cs.addPartial(See.only(serverPlayer), unit, "movesLeft");
            }
            session.setAgreement(agreement);
            break;
        case ACCEPT_TRADE:
            if (session == null) {
                return DOMMessage.clientError("Accept-trade with no session");
            }
            agreement = session.getAgreement();
            agreement.setStatus(status);
            csAcceptTrade(unit, settlement, agreement, cs);
            break;
        case REJECT_TRADE:
            if (session == null) {
                return DOMMessage.clientError("Reject-trade with no session");
            }
            agreement = session.getAgreement();
            agreement.setStatus(status);
            break;
        default:
            return DOMMessage.clientError("Bogus trade status: " + status);
        }

        DOMMessage reply = askTimeout(otherPlayer,
            new DiplomacyMessage(unit, settlement, agreement));
        DiplomaticTrade theirAgreement = (reply instanceof DiplomacyMessage)
            ? ((DiplomacyMessage)reply).getAgreement()
            : null;
        if (status != TradeStatus.PROPOSE_TRADE) {
            session.complete(cs);
            sendToOthers(serverPlayer, cs);
            return cs.build(serverPlayer);
        }
        status = (theirAgreement == null) ? TradeStatus.REJECT_TRADE
            : theirAgreement.getStatus();
        switch (status) {
        case PROPOSE_TRADE:
            session.setAgreement(agreement = theirAgreement);
            break;
        case ACCEPT_TRADE:
            agreement.setStatus(status);
            csAcceptTrade(unit, settlement, agreement, cs);
            session.complete(cs);
            break;
        case REJECT_TRADE:
            agreement.setStatus(status);
            session.complete(cs);
            break;
        default:
            logger.warning("Bogus trade status: " + status);
            break;
        }
        // Update *everyone* with the result, *and* return a
        // DiplomacyMessage to the originating player because that is
        // what ServerAPI.askDiplomacy is expecting.
        sendToAll(cs);

        return new ChangeSet()
            .add(See.only(serverPlayer), ChangePriority.CHANGE_LATE,
                new DiplomacyMessage(unit, settlement, agreement))
            .build(serverPlayer);
    }