// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.util.io;

import com.hypixel.hytale.common.util.BitSetUtil;
import com.hypixel.hytale.unsafe.UnsafeUtil;
import java.util.BitSet;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nonnull;
import io.netty.buffer.ByteBuf;

public class ByteBufUtil
{
    private static int MAX_UNSIGNED_SHORT_VALUE;
    
    public static void writeUTF(@Nonnull final ByteBuf buf, @Nonnull final String string) {
        if (io.netty.buffer.ByteBufUtil.utf8MaxBytes(string) >= ByteBufUtil.MAX_UNSIGNED_SHORT_VALUE) {
            throw new IllegalArgumentException("String is too large");
        }
        final int before = buf.writerIndex();
        buf.writeShort(-1);
        final int length = buf.writeCharSequence(string, StandardCharsets.UTF_8);
        if (length < 0 || length >= ByteBufUtil.MAX_UNSIGNED_SHORT_VALUE) {
            throw new IllegalArgumentException("Serialized string is too large");
        }
        final int after = buf.writerIndex();
        buf.writerIndex(before);
        buf.writeShort(length);
        buf.writerIndex(after);
    }
    
    @Nonnull
    public static String readUTF(@Nonnull final ByteBuf buf) {
        final int length = buf.readUnsignedShort();
        return buf.readCharSequence(length, StandardCharsets.UTF_8).toString();
    }
    
    public static void writeByteArray(@Nonnull final ByteBuf buf, @Nonnull final byte[] arr) {
        writeByteArray(buf, arr, 0, arr.length);
    }
    
    public static void writeByteArray(@Nonnull final ByteBuf buf, final byte[] arr, final int src, final int length) {
        if (length <= 0 || length >= ByteBufUtil.MAX_UNSIGNED_SHORT_VALUE) {
            throw new IllegalArgumentException("length is too large");
        }
        buf.writeShort(length);
        buf.writeBytes(arr, src, length);
    }
    
    public static byte[] readByteArray(@Nonnull final ByteBuf buf) {
        final int length = buf.readUnsignedShort();
        final byte[] bytes = new byte[length];
        buf.readBytes(bytes);
        return bytes;
    }
    
    public static byte[] getBytesRelease(@Nonnull final ByteBuf buf) {
        try {
            return io.netty.buffer.ByteBufUtil.getBytes(buf, 0, buf.writerIndex(), false);
        }
        finally {
            buf.release();
        }
    }
    
    public static void writeNumber(@Nonnull final ByteBuf buf, final int bytes, final int value) {
        switch (bytes) {
            case 1: {
                buf.writeByte(value);
                break;
            }
            case 2: {
                buf.writeShort(value);
                break;
            }
            case 4: {
                buf.writeInt(value);
                break;
            }
        }
    }
    
    public static int readNumber(@Nonnull final ByteBuf buf, final int bytes) {
        return switch (bytes) {
            case 1 -> buf.readByte() & 0xFF;
            case 2 -> buf.readShort() & 0xFFFF;
            case 4 -> buf.readInt();
            default -> 0;
        };
    }
    
    public static void writeBitSet(@Nonnull final ByteBuf buf, @Nonnull final BitSet bitset) {
        long[] words;
        int wordsInUse;
        if (UnsafeUtil.UNSAFE == null) {
            words = bitset.toLongArray();
            wordsInUse = words.length;
        }
        else {
            wordsInUse = UnsafeUtil.UNSAFE.getInt(bitset, BitSetUtil.WORDS_IN_USE_OFFSET);
            words = (long[])UnsafeUtil.UNSAFE.getObject(bitset, BitSetUtil.WORDS_OFFSET);
        }
        buf.writeInt(wordsInUse);
        for (int i = 0; i < wordsInUse; ++i) {
            buf.writeLong(words[i]);
        }
    }
    
    public static void readBitSet(@Nonnull final ByteBuf buf, @Nonnull final BitSet bitset) {
        final int wordsInUse = buf.readInt();
        if (UnsafeUtil.UNSAFE == null) {
            final long[] words = new long[wordsInUse];
            for (int i = 0; i < wordsInUse; ++i) {
                words[i] = buf.readLong();
            }
            bitset.clear();
            bitset.or(BitSet.valueOf(words));
            return;
        }
        UnsafeUtil.UNSAFE.putInt(bitset, BitSetUtil.WORDS_IN_USE_OFFSET, wordsInUse);
        long[] words = (long[])UnsafeUtil.UNSAFE.getObject(bitset, BitSetUtil.WORDS_OFFSET);
        if (wordsInUse > words.length) {
            words = new long[wordsInUse];
            UnsafeUtil.UNSAFE.putObject(bitset, BitSetUtil.WORDS_OFFSET, words);
        }
        for (int i = 0; i < wordsInUse; ++i) {
            words[i] = buf.readLong();
        }
    }
    
    static {
        ByteBufUtil.MAX_UNSIGNED_SHORT_VALUE = 65535;
    }
}
