package net.md_5.bungee.jni.zlib;

import io.netty.buffer.ByteBuf;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

public class JavaZlib implements BungeeZlib
{

    private static final ThreadLocal<byte[]> heapInLocal = new ThreadLocal<byte[]>() {
        @Override
        protected byte[] initialValue() {
            return new byte[0];
        }
    };
    private static final ThreadLocal<byte[]> heapOutLocal = new ThreadLocal<byte[]>() {
        @Override
        protected byte[] initialValue() {
            return new byte[8192];
        }
    };
    //
    private boolean compress;
    private Deflater deflater;
    private Inflater inflater;

    @Override
    public void init(boolean compress, int level)
    {
        this.compress = compress;
        free();

        if ( compress )
        {
            deflater = new Deflater( level );
        } else
        {
            inflater = new Inflater();
        }
    }

    @Override
    public void free()
    {
        if ( deflater != null )
        {
            deflater.end();
        }
        if ( inflater != null )
        {
            inflater.end();
        }
    }

    @Override
    public void process(ByteBuf in, ByteBuf out) throws DataFormatException
    {
        byte[] inData = bufToByte( in );
        byte[] buffer = heapOutLocal.get();

        if ( compress )
        {
            deflater.setInput( inData );
            deflater.finish();

            while ( !deflater.finished() )
            {
                int count = deflater.deflate(buffer);
                out.writeBytes(buffer, 0, count );
            }

            deflater.reset();
        } else
        {
            inflater.setInput( inData );

            while ( !inflater.finished() )
            {
                int count = inflater.inflate(buffer);
                out.writeBytes(buffer, 0, count );
            }

            inflater.reset();
        }
    }

    private byte[] bufToByte(ByteBuf in)
    {
        byte[] heapIn = heapInLocal.get();
        int readableBytes = in.readableBytes();
        if ( heapIn.length < readableBytes )
        {
            heapIn = new byte[ readableBytes ];
            heapInLocal.set( heapIn );
        }
        in.readBytes( heapIn, 0, readableBytes );
        return heapIn;
    }
}

@@ -228,390 +228,46 @@
 ate 
-static final ThreadLocal%3Cbyte%5B%5D%3E heapInLocal = new ThreadLocal%3Cbyte%5B%5D%3E() %7B%0A        @Override%0A        protected byte%5B%5D initialValue() %7B%0A            return new byte%5B0%5D;%0A        %7D%0A    %7D;%0A    private static final ThreadLocal%3Cbyte%5B%5D%3E heapOutLocal = new ThreadLocal%3Cbyte%5B%5D%3E() %7B%0A        @Override%0A        protected byte%5B%5D initialValue() %7B%0A            return new byte%5B8192%5D;%0A        %7D%0A    %7D
+final byte%5B%5D buffer = new byte%5B 8192 %5D
 ;%0A  
@@ -980,66 +980,69 @@
 a = 
-bufToByte( in );%0A        byte%5B%5D buffer = heapOutLocal.get(
+new byte%5B in.readableBytes() %5D;%0A        in.readBytes( inData 
 );%0A%0A
@@ -1246,30 +1246,32 @@
 ter.deflate(
+ 
 buffer
+ 
 );%0A         
@@ -1284,32 +1284,33 @@
  out.writeBytes(
+ 
 buffer, 0, count
@@ -1527,22 +1527,24 @@
 inflate(
+ 
 buffer
+ 
 );%0A     
@@ -1569,16 +1569,17 @@
 teBytes(
+ 
 buffer, 
@@ -1654,377 +1654,7 @@
    %7D
-%0A%0A    private byte%5B%5D bufToByte(ByteBuf in)%0A    %7B%0A        byte%5B%5D heapIn = heapInLocal.get();%0A        int readableBytes = in.readableBytes();%0A        if ( heapIn.length %3C readableBytes )%0A        %7B%0A            heapIn = new byte%5B readableBytes %5D;%0A            heapInLocal.set( heapIn );%0A        %7D%0A        in.readBytes( heapIn, 0, readableBytes );%0A        return heapIn;%0A    %7D
 %0A%7D%0A

Revert "ReduceJavaZlib GC similar to what is implemented in JavaCipher"