// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/util/FastLog.java
// public final class FastLog {
//     /*
//      * See http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
//      */
//     private final static long b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000L};
//     private final static int S[] = {1, 2, 4, 8, 16, 32};
// 
//     public final static int log2(long v) {
//         int r = 0; // result of log2(v) will go here
//         for (int i = 5; i >= 0; i--) {
//             if ((v & b[i]) != 0) {
//                 v >>= S[i];
//                 r |= S[i];
//             }
//         }
//         return r;
//     }
// 
//     public final static int log2(int v) {
//         int r = 0; // result of log2(v) will go here
//         for (int i = 4; i >= 0; i--) {
//             if ((v & b[i]) != 0) {
//                 v >>= S[i];
//                 r |= S[i];
//             }
//         }
//         return r;
//     }
// }
// 
// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/util/SystemClock.java
// public interface SystemClock {
//     long getTimeNow();
// }
// 
// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/util/BitConstants.java
// public static final long LSB = 0x1L;
// 
// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/util/BitConstants.java
// public static final int OFFSET = 1;


import com.github.mucaho.jnetrobust.util.FastLog;
import com.github.mucaho.jnetrobust.util.SystemClock;
import java.nio.ByteBuffer;
import static com.github.mucaho.jnetrobust.util.BitConstants.LSB;
import static com.github.mucaho.jnetrobust.util.BitConstants.OFFSET;
/*
 * Copyright (c) 2014 mucaho (https://github.com/mucaho).
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package com.github.mucaho.jnetrobust.control;




public class SentMapControl extends AbstractMapControl {
    public interface TransmissionSuccessListener {
        void handleAckedData(short dataId, ByteBuffer ackedData);
        void handleUnackedData(short dataId, ByteBuffer unackedData);
    }

    private TransmissionSuccessListener listener;

    public SentMapControl(TransmissionSuccessListener listener, int maxEntries, int maxEntryOffset,
                          int maxEntryOccurrences, long maxEntryTimeout, SystemClock systemClock) {
        super(maxEntries, maxEntryOffset, maxEntryOccurrences, maxEntryTimeout, systemClock);
        this.listener = listener;
    }

    @Override
    protected AbstractSegmentMap createMap() {
        return new SentSegmentMap();
    }

    public void addToSent(Short transmissionId, Segment segment) {
        // add to pending map
        dataMap.put(transmissionId, segment);
    }

    public void removeFromSent(Short transmissionId, long precedingTransmissionIds) {
        // remove multiple (oldest until newest) from pending map
        removeFromSentOnBits(transmissionId, precedingTransmissionIds);

        // remove newest from pending map
        notifyAcked(transmissionId, dataMap.removeAll(transmissionId), true);
    }

    private void removeFromSentOnBits(Short transmissionId, long precedingTransmissionIds) {
        Short precedingTransmissionId;
        int msbIndex;
        while (precedingTransmissionIds != 0) {
// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/util/FastLog.java
// public final class FastLog {
//     /*
//      * See http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
//      */
//     private final static long b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000L};
//     private final static int S[] = {1, 2, 4, 8, 16, 32};
// 
//     public final static int log2(long v) {
//         int r = 0; // result of log2(v) will go here
//         for (int i = 5; i >= 0; i--) {
//             if ((v & b[i]) != 0) {
//                 v >>= S[i];
//                 r |= S[i];
//             }
//         }
//         return r;
//     }
// 
//     public final static int log2(int v) {
//         int r = 0; // result of log2(v) will go here
//         for (int i = 4; i >= 0; i--) {
//             if ((v & b[i]) != 0) {
//                 v >>= S[i];
//                 r |= S[i];
//             }
//         }
//         return r;
//     }
// }
// 
// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/util/SystemClock.java
// public interface SystemClock {
//     long getTimeNow();
// }
// 
// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/util/BitConstants.java
// public static final long LSB = 0x1L;
// 
// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/util/BitConstants.java
// public static final int OFFSET = 1;


// Path: jnetrobust-core/src/main/java/com/github/mucaho/jnetrobust/control/SentMapControl.java
import com.github.mucaho.jnetrobust.util.FastLog;
import com.github.mucaho.jnetrobust.util.SystemClock;
import java.nio.ByteBuffer;
import static com.github.mucaho.jnetrobust.util.BitConstants.LSB;
import static com.github.mucaho.jnetrobust.util.BitConstants.OFFSET;

/*
 * Copyright (c) 2014 mucaho (https://github.com/mucaho).
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package com.github.mucaho.jnetrobust.control;




public class SentMapControl extends AbstractMapControl {
    public interface TransmissionSuccessListener {
        void handleAckedData(short dataId, ByteBuffer ackedData);
        void handleUnackedData(short dataId, ByteBuffer unackedData);
    }

    private TransmissionSuccessListener listener;

    public SentMapControl(TransmissionSuccessListener listener, int maxEntries, int maxEntryOffset,
                          int maxEntryOccurrences, long maxEntryTimeout, SystemClock systemClock) {
        super(maxEntries, maxEntryOffset, maxEntryOccurrences, maxEntryTimeout, systemClock);
        this.listener = listener;
    }

    @Override
    protected AbstractSegmentMap createMap() {
        return new SentSegmentMap();
    }

    public void addToSent(Short transmissionId, Segment segment) {
        // add to pending map
        dataMap.put(transmissionId, segment);
    }

    public void removeFromSent(Short transmissionId, long precedingTransmissionIds) {
        // remove multiple (oldest until newest) from pending map
        removeFromSentOnBits(transmissionId, precedingTransmissionIds);

        // remove newest from pending map
        notifyAcked(transmissionId, dataMap.removeAll(transmissionId), true);
    }

    private void removeFromSentOnBits(Short transmissionId, long precedingTransmissionIds) {
        Short precedingTransmissionId;
        int msbIndex;
        while (precedingTransmissionIds != 0) {
            msbIndex = FastLog.log2(precedingTransmissionIds);