void SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderUUID, const bool wantExtraDebugging) {

    // if the sender node has changed, reset all stats
    if (senderUUID != _lastSenderUUID) {
        qDebug() << "sequence number stats was reset due to new sender node";
        qDebug() << "previous:" << _lastSenderUUID << "current:" << senderUUID;
        reset();
        _lastSenderUUID = senderUUID;
    }

    // determine our expected sequence number... handle rollover appropriately
    quint16 expected = _stats._numReceived > 0 ? _lastReceived + (quint16)1 : incoming;

    _stats._numReceived++;

    if (incoming == expected) { // on time
        _lastReceived = incoming;
    } else { // out of order

        if (wantExtraDebugging) {
            qDebug() << "out of order... got:" << incoming << "expected:" << expected;
        }

        int incomingInt = (int)incoming;
        int expectedInt = (int)expected;

        // check if the gap between incoming and expected is reasonable, taking possible rollover into consideration
        int absGap = std::abs(incomingInt - expectedInt);
        if (absGap >= UINT16_RANGE - MAX_REASONABLE_SEQUENCE_GAP) {
            // rollover likely occurred between incoming and expected.
            // correct the larger of the two so that it's within [-UINT16_RANGE, -1] while the other remains within [0, UINT16_RANGE-1]
            if (incomingInt > expectedInt) {
                incomingInt -= UINT16_RANGE;
            } else {
                expectedInt -= UINT16_RANGE;
            }
        } else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) {
            // ignore packet if gap is unreasonable
            qDebug() << "ignoring unreasonable sequence number:" << incoming
                << "previous:" << _lastReceived;
            _stats._numUnreasonable++;
            return;
        }

        // now that rollover has been corrected for (if it occurred), incoming and expected can be
        // compared to each other directly, though one of them might be negative
        if (incomingInt > expectedInt) { // early
            if (wantExtraDebugging) {
                qDebug() << "this packet is earlier than expected...";
                qDebug() << ">>>>>>>> missing gap=" << (incomingInt - expectedInt);
            }

            _stats._numEarly++;
            _stats._numLost += (incomingInt - expectedInt);
            _lastReceived = incoming;

            // add all sequence numbers that were skipped to the missing sequence numbers list
            for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) {
                _missingSet.insert((quint16)(missingInt < 0 ? missingInt + UINT16_RANGE : missingInt));
            }
            
            // prune missing sequence list if it gets too big; sequence numbers that are older than MAX_REASONABLE_SEQUENCE_GAP
            // will be removed.
            if (_missingSet.size() > MAX_REASONABLE_SEQUENCE_GAP) {
                pruneMissingSet(wantExtraDebugging);
            }
        } else { // late
            if (wantExtraDebugging) {
                qDebug() << "this packet is later than expected...";
            }
            _stats._numLate++;

            // do not update _lastReceived; it shouldn't become smaller

            // remove this from missing sequence number if it's in there
            if (_missingSet.remove(incoming)) {
                if (wantExtraDebugging) {
                    qDebug() << "found it in _missingSet";
                }
                _stats._numLost--;
                _stats._numRecovered++;
            } else {
                if (wantExtraDebugging) {
                    qDebug() << "sequence:" << incoming << "was NOT found in _missingSet and is probably a duplicate";
                }
                _stats._numDuplicate++;
            }
        }
    }
}
SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(quint16 incoming, NetworkLocalID senderID, const bool wantExtraDebugging) {

    SequenceNumberStats::ArrivalInfo arrivalInfo;

    // if the sender node has changed, reset all stats
    if (senderID != _lastSenderID) {
        if (_stats._received > 0) {
            qCDebug(networking) << "sequence number stats was reset due to new sender node";
            qCDebug(networking) << "previous:" << _lastSenderID << "current:" << senderID;
            reset();
        }
        _lastSenderID = senderID;
    }

    // determine our expected sequence number... handle rollover appropriately
    quint16 expected = _stats._received > 0 ? _lastReceivedSequence + (quint16)1 : incoming;

    _stats._received++;

    if (incoming == expected) { // on time
        arrivalInfo._status = OnTime;
        _lastReceivedSequence = incoming;
        _stats._expectedReceived++;

    } else { // out of order

        if (wantExtraDebugging) {
            qCDebug(networking) << "out of order... got:" << incoming << "expected:" << expected;
        }

        int incomingInt = (int)incoming;
        int expectedInt = (int)expected;

        // check if the gap between incoming and expected is reasonable, taking possible rollover into consideration
        int absGap = abs(incomingInt - expectedInt);
        if (absGap >= UINT16_RANGE - MAX_REASONABLE_SEQUENCE_GAP) {
            // rollover likely occurred between incoming and expected.
            // correct the larger of the two so that it's within [-UINT16_RANGE, -1] while the other remains within [0, UINT16_RANGE-1]
            if (incomingInt > expectedInt) {
                incomingInt -= UINT16_RANGE;
            } else {
                expectedInt -= UINT16_RANGE;
            }
        } else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) {
            arrivalInfo._status = Unreasonable;

            HIFI_FCDEBUG(networking(), "unreasonable sequence number:" << incoming << "previous:" << _lastReceivedSequence);

            _stats._unreasonable++;
            
            receivedUnreasonable(incoming);
            return arrivalInfo;
        }


        // now that rollover has been corrected for (if it occurred), incomingInt and expectedInt can be
        // compared to each other directly, though one of them might be negative

        arrivalInfo._seqDiffFromExpected = incomingInt - expectedInt;

        if (incomingInt > expectedInt) { // early
            arrivalInfo._status = Early;

            if (wantExtraDebugging) {
                qCDebug(networking) << "this packet is earlier than expected...";
                qCDebug(networking) << ">>>>>>>> missing gap=" << (incomingInt - expectedInt);
            }
            int skipped = incomingInt - expectedInt;
            _stats._early++;
            _stats._lost += skipped;
            _stats._expectedReceived += (skipped + 1);
            _lastReceivedSequence = incoming;

            // add all sequence numbers that were skipped to the missing sequence numbers list
            for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) {
                _missingSet.insert((quint16)(missingInt < 0 ? missingInt + UINT16_RANGE : missingInt));
            }

            // prune missing sequence list if it gets too big; sequence numbers that are older than MAX_REASONABLE_SEQUENCE_GAP
            // will be removed.
            if (_missingSet.size() > MAX_REASONABLE_SEQUENCE_GAP) {
                pruneMissingSet(wantExtraDebugging);
            }
        } else { // late
            if (wantExtraDebugging) {
                qCDebug(networking) << "this packet is later than expected...";
            }

            _stats._late++;

            // do not update _lastReceived; it shouldn't become smaller

            // remove this from missing sequence number if it's in there
            if (_missingSet.remove(incoming)) {
                arrivalInfo._status = Recovered;

                if (wantExtraDebugging) {
                    qCDebug(networking) << "found it in _missingSet";
                }
                if (_stats._lost > 0) {
                    _stats._lost--;
                    _stats._recovered++;
                }
            } else {
                // this late seq num is not in our missing set.  it is possibly a duplicate, or possibly a late
                // packet that should have arrived before our first received packet.  we'll count these
                // as unreasonable.

                arrivalInfo._status = Unreasonable;

                HIFI_FCDEBUG(networking(), "unreasonable sequence number:" << incoming << "(possible duplicate)");

                _stats._unreasonable++;

                receivedUnreasonable(incoming);
                return arrivalInfo;
            }
        }
    }

    // if we've made it here, we received a reasonable seq number.
    _consecutiveUnreasonableOnTime = 0;

    return arrivalInfo;
}