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

package com.github.luben.zstd;

import com.github.luben.zstd.util.Native;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.io.Flushable;
import java.io.Closeable;

public class ZstdDirectBufferCompressingStreamNoFinalizer implements Closeable, Flushable
{
    private ByteBuffer target;
    private final long stream;
    private int consumed;
    private int produced;
    private boolean closed;
    private boolean initialized;
    private int level;
    private byte[] dict;
    private ZstdDictCompress fastDict;
    
    protected ByteBuffer flushBuffer(final ByteBuffer byteBuffer) throws IOException {
        return byteBuffer;
    }
    
    public ZstdDirectBufferCompressingStreamNoFinalizer(final ByteBuffer target, final int level) throws IOException {
        this.consumed = 0;
        this.produced = 0;
        this.closed = false;
        this.initialized = false;
        this.level = Zstd.defaultCompressionLevel();
        this.dict = null;
        this.fastDict = null;
        if (!target.isDirect()) {
            throw new IllegalArgumentException("Target buffer should be a direct buffer");
        }
        this.target = target;
        this.level = level;
        this.stream = createCStream();
    }
    
    public static int recommendedOutputBufferSize() {
        return (int)recommendedCOutSize();
    }
    
    private static native long recommendedCOutSize();
    
    private static native long createCStream();
    
    private static native long freeCStream(final long p0);
    
    private native long initCStream(final long p0, final int p1);
    
    private native long initCStreamWithDict(final long p0, final byte[] p1, final int p2, final int p3);
    
    private native long initCStreamWithFastDict(final long p0, final ZstdDictCompress p1);
    
    private native long compressDirectByteBuffer(final long p0, final ByteBuffer p1, final int p2, final int p3, final ByteBuffer p4, final int p5, final int p6);
    
    private native long flushStream(final long p0, final ByteBuffer p1, final int p2, final int p3);
    
    private native long endStream(final long p0, final ByteBuffer p1, final int p2, final int p3);
    
    public ZstdDirectBufferCompressingStreamNoFinalizer setDict(final byte[] dict) {
        if (this.initialized) {
            throw new IllegalStateException("Change of parameter on initialized stream");
        }
        this.dict = dict;
        this.fastDict = null;
        return this;
    }
    
    public ZstdDirectBufferCompressingStreamNoFinalizer setDict(final ZstdDictCompress fastDict) {
        if (this.initialized) {
            throw new IllegalStateException("Change of parameter on initialized stream");
        }
        this.dict = null;
        this.fastDict = fastDict;
        return this;
    }
    
    public void compress(final ByteBuffer byteBuffer) throws IOException {
        if (!byteBuffer.isDirect()) {
            throw new IllegalArgumentException("Source buffer should be a direct buffer");
        }
        if (this.closed) {
            throw new IOException("Stream closed");
        }
        if (!this.initialized) {
            long n = 0L;
            final ZstdDictCompress fastDict = this.fastDict;
            if (fastDict != null) {
                fastDict.acquireSharedLock();
                try {
                    n = this.initCStreamWithFastDict(this.stream, fastDict);
                }
                finally {
                    fastDict.releaseSharedLock();
                }
            }
            else if (this.dict != null) {
                n = this.initCStreamWithDict(this.stream, this.dict, this.dict.length, this.level);
            }
            else {
                n = this.initCStream(this.stream, this.level);
            }
            if (Zstd.isError(n)) {
                throw new ZstdIOException(n);
            }
            this.initialized = true;
        }
        while (byteBuffer.hasRemaining()) {
            if (!this.target.hasRemaining()) {
                this.target = this.flushBuffer(this.target);
                if (!this.target.isDirect()) {
                    throw new IllegalArgumentException("Target buffer should be a direct buffer");
                }
                if (!this.target.hasRemaining()) {
                    throw new IOException("The target buffer has no more space, even after flushing, and there are still bytes to compress");
                }
            }
            final long compressDirectByteBuffer = this.compressDirectByteBuffer(this.stream, this.target, this.target.position(), this.target.remaining(), byteBuffer, byteBuffer.position(), byteBuffer.remaining());
            if (Zstd.isError(compressDirectByteBuffer)) {
                throw new ZstdIOException(compressDirectByteBuffer);
            }
            this.target.position();
            byteBuffer.position();
        }
    }
    
    @Override
    public void flush() throws IOException {
        if (this.closed) {
            throw new IOException("Already closed");
        }
        if (this.initialized) {
            long flushStream;
            do {
                flushStream = this.flushStream(this.stream, this.target, this.target.position(), this.target.remaining());
                if (Zstd.isError(flushStream)) {
                    throw new ZstdIOException(flushStream);
                }
                this.target.position();
                this.target = this.flushBuffer(this.target);
                if (!this.target.isDirect()) {
                    throw new IllegalArgumentException("Target buffer should be a direct buffer");
                }
                if (flushStream > 0L && !this.target.hasRemaining()) {
                    throw new IOException("The target buffer has no more space, even after flushing, and there are still bytes to compress");
                }
            } while (flushStream > 0L);
        }
    }
    
    @Override
    public void close() throws IOException {
        if (!this.closed) {
            try {
                if (this.initialized) {
                    long endStream;
                    do {
                        endStream = this.endStream(this.stream, this.target, this.target.position(), this.target.remaining());
                        if (Zstd.isError(endStream)) {
                            throw new ZstdIOException(endStream);
                        }
                        this.target.position();
                        this.target = this.flushBuffer(this.target);
                        if (!this.target.isDirect()) {
                            throw new IllegalArgumentException("Target buffer should be a direct buffer");
                        }
                        if (endStream > 0L && !this.target.hasRemaining()) {
                            throw new IOException("The target buffer has no more space, even after flushing, and there are still bytes to compress");
                        }
                    } while (endStream > 0L);
                }
            }
            finally {
                freeCStream(this.stream);
                this.closed = true;
                this.initialized = false;
                this.target = null;
            }
        }
    }
    
    static {
        Native.load();
    }
}
