package com.voxelwind.server.network.raknet.packets;

import com.google.common.collect.ImmutableList;
import com.voxelwind.server.network.NetworkPackage;
import com.voxelwind.server.network.raknet.datastructs.IntRange;
import io.netty.buffer.ByteBuf;
import lombok.Data;

import java.nio.ByteOrder;
import java.util.*;

@Data
public abstract class BaseAckPacket implements NetworkPackage {
    private final List<IntRange> ids = new ArrayList<>();

    public static List<IntRange> intoRanges(Collection<Integer> knownIds) {
        if (knownIds.isEmpty()) {
            throw new NoSuchElementException();
        }

        List<IntRange> ranges = new ArrayList<>();
        List<Integer> ids = new ArrayList<>(knownIds);
        if (ids.size() == 1) {
            return ImmutableList.of(new IntRange(ids.get(0)));
        }
        Collections.sort(ids);

        int start = ids.get(0);
        int cur = start;

        for (Integer id : ids.subList(1, ids.size())) {
            if (cur + 1 == id) {
                cur = id;
            } else {
                ranges.add(new IntRange(start, cur));
                start = id;
                cur = id;
            }
        }

        if (start == cur) {
            ranges.add(new IntRange(start));
        } else {
            ranges.add(new IntRange(start, cur));
        }

        return ranges;
    }

    @Override
    public void decode(ByteBuf buffer) {
        short size = buffer.readShort();
        for (int i = 0; i < size; i++) {
            boolean isSingleton = buffer.readBoolean();
            int lower = buffer.order(ByteOrder.LITTLE_ENDIAN).readMedium();
            if (isSingleton) {
                ids.add(new IntRange(lower, lower));
            } else {
                int upper = buffer.order(ByteOrder.LITTLE_ENDIAN).readMedium();
                ids.add(new IntRange(lower, upper));
            }
        }
    }

    @Override
    public void encode(ByteBuf buffer) {
        buffer.writeShort(ids.size());
        for (IntRange id : ids) {
            boolean singleton = id.getStart() == id.getEnd();
            buffer.writeBoolean(singleton);
            buffer.order(ByteOrder.LITTLE_ENDIAN).writeMedium(id.getStart());
            if (!singleton) {
                buffer.order(ByteOrder.LITTLE_ENDIAN).writeMedium(id.getEnd());
            }
        }
    }
}

@@ -208,24 +208,56 @@
 s.IntRange;%0A
+import gnu.trove.list.TIntList;%0A
 import io.ne
@@ -276,16 +276,16 @@
 yteBuf;%0A
-
 import l
@@ -522,34 +522,18 @@
 ges(
-Collection%3CInteger%3E knownI
+TIntList i
 ds) 
@@ -546,22 +546,17 @@
     if (
-knownI
+i
 ds.isEmp
@@ -677,63 +677,8 @@
 ();%0A
-        List%3CInteger%3E ids = new ArrayList%3C%3E(knownIds);%0A
     
@@ -789,28 +789,17 @@
     
-Collection
+id
 s.sort(
-ids
 );%0A%0A
@@ -873,15 +873,11 @@
 or (
-I
+i
 nt
-eger
  id 
@@ -904,16 +904,26 @@
 .size())
+.toArray()
 ) %7B%0A    

Convert BaseAckPacket.intoRanges() to use Trove