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

package com.github.luben.zstd;

import com.github.luben.zstd.util.Native;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.io.FilterInputStream;

public class ZstdInputStreamNoFinalizer extends FilterInputStream
{
    private final long stream;
    private long dstPos;
    private long srcPos;
    private long srcSize;
    private boolean needRead;
    private final BufferPool bufferPool;
    private final ByteBuffer srcByteBuffer;
    private final byte[] src;
    private static final int srcBuffSize;
    private boolean isContinuous;
    private boolean frameFinished;
    private boolean isClosed;
    
    public static native long recommendedDInSize();
    
    public static native long recommendedDOutSize();
    
    private static native long createDStream();
    
    private static native int freeDStream(final long p0);
    
    private native int initDStream(final long p0);
    
    private native int decompressStream(final long p0, final byte[] p1, final int p2, final byte[] p3, final int p4);
    
    public ZstdInputStreamNoFinalizer(final InputStream inputStream) throws IOException {
        this(inputStream, NoPool.INSTANCE);
    }
    
    public ZstdInputStreamNoFinalizer(final InputStream in, final BufferPool bufferPool) throws IOException {
        super(in);
        this.dstPos = 0L;
        this.srcPos = 0L;
        this.srcSize = 0L;
        this.needRead = true;
        this.isContinuous = false;
        this.frameFinished = true;
        this.isClosed = false;
        this.bufferPool = bufferPool;
        this.srcByteBuffer = Zstd.getArrayBackedBuffer(bufferPool, ZstdInputStreamNoFinalizer.srcBuffSize);
        this.src = this.srcByteBuffer.array();
        synchronized (this) {
            this.initDStream(this.stream = createDStream());
        }
    }
    
    public synchronized ZstdInputStreamNoFinalizer setContinuous(final boolean isContinuous) {
        this.isContinuous = isContinuous;
        return this;
    }
    
    public synchronized boolean getContinuous() {
        return this.isContinuous;
    }
    
    public synchronized ZstdInputStreamNoFinalizer setDict(final byte[] array) throws IOException {
        final int loadDictDecompress = Zstd.loadDictDecompress(this.stream, array, array.length);
        if (Zstd.isError(loadDictDecompress)) {
            throw new ZstdIOException(loadDictDecompress);
        }
        return this;
    }
    
    public synchronized ZstdInputStreamNoFinalizer setDict(final ZstdDictDecompress zstdDictDecompress) throws IOException {
        zstdDictDecompress.acquireSharedLock();
        try {
            final int loadFastDictDecompress = Zstd.loadFastDictDecompress(this.stream, zstdDictDecompress);
            if (Zstd.isError(loadFastDictDecompress)) {
                throw new ZstdIOException(loadFastDictDecompress);
            }
        }
        finally {
            zstdDictDecompress.releaseSharedLock();
        }
        return this;
    }
    
    public synchronized ZstdInputStreamNoFinalizer setLongMax(final int n) throws IOException {
        final int setDecompressionLongMax = Zstd.setDecompressionLongMax(this.stream, n);
        if (Zstd.isError(setDecompressionLongMax)) {
            throw new ZstdIOException(setDecompressionLongMax);
        }
        return this;
    }
    
    public synchronized ZstdInputStreamNoFinalizer setRefMultipleDDicts(final boolean b) throws IOException {
        final int setRefMultipleDDicts = Zstd.setRefMultipleDDicts(this.stream, b);
        if (Zstd.isError(setRefMultipleDDicts)) {
            throw new ZstdIOException(setRefMultipleDDicts);
        }
        return this;
    }
    
    @Override
    public synchronized int read(final byte[] array, final int i, final int j) throws IOException {
        if (i < 0 || j > array.length - i) {
            throw new IndexOutOfBoundsException("Requested length " + j + " from offset " + i + " in buffer of size " + array.length);
        }
        if (j == 0) {
            return 0;
        }
        int k;
        for (k = 0; k == 0; k = this.readInternal(array, i, j)) {}
        return k;
    }
    
    int readInternal(final byte[] array, final int i, final int j) throws IOException {
        if (this.isClosed) {
            throw new IOException("Stream closed");
        }
        if (i < 0 || j > array.length - i) {
            throw new IndexOutOfBoundsException("Requested length " + j + " from offset " + i + " in buffer of size " + array.length);
        }
        final int n = i + j;
        this.dstPos = i;
        long dstPos = -1L;
        while (this.dstPos < n && dstPos < this.dstPos) {
            if (this.needRead && (this.in.available() > 0 || this.dstPos == i)) {
                this.srcSize = this.in.read(this.src, 0, ZstdInputStreamNoFinalizer.srcBuffSize);
                this.srcPos = 0L;
                if (this.srcSize < 0L) {
                    this.srcSize = 0L;
                    if (this.frameFinished) {
                        return -1;
                    }
                    if (!this.isContinuous) {
                        throw new ZstdIOException(Zstd.errCorruptionDetected(), "Truncated source");
                    }
                    this.srcSize = (int)(this.dstPos - i);
                    if (this.srcSize > 0L) {
                        return (int)this.srcSize;
                    }
                    return -1;
                }
                else {
                    this.frameFinished = false;
                }
            }
            dstPos = this.dstPos;
            final int decompressStream = this.decompressStream(this.stream, array, n, this.src, (int)this.srcSize);
            if (Zstd.isError(decompressStream)) {
                throw new ZstdIOException(decompressStream);
            }
            if (decompressStream == 0) {
                this.frameFinished = true;
                this.needRead = (this.srcPos == this.srcSize);
                return (int)(this.dstPos - i);
            }
            this.needRead = (this.dstPos < n);
        }
        return (int)(this.dstPos - i);
    }
    
    @Override
    public synchronized int read() throws IOException {
        byte[] array;
        int i;
        for (array = new byte[] { 0 }, i = 0; i == 0; i = this.readInternal(array, 0, 1)) {}
        if (i == 1) {
            return array[0] & 0xFF;
        }
        return -1;
    }
    
    @Override
    public synchronized int available() throws IOException {
        if (this.isClosed) {
            throw new IOException("Stream closed");
        }
        if (!this.needRead) {
            return 1;
        }
        return this.in.available();
    }
    
    @Override
    public boolean markSupported() {
        return false;
    }
    
    @Override
    public synchronized long skip(final long n) throws IOException {
        if (this.isClosed) {
            throw new IOException("Stream closed");
        }
        if (n <= 0L) {
            return 0L;
        }
        int n2 = (int)recommendedDOutSize();
        if (n2 > n) {
            n2 = (int)n;
        }
        final ByteBuffer arrayBackedBuffer = Zstd.getArrayBackedBuffer(this.bufferPool, n2);
        long b = n;
        try {
            final byte[] array = arrayBackedBuffer.array();
            while (b > 0L) {
                final int read = this.read(array, 0, (int)Math.min(n2, b));
                if (read < 0) {
                    break;
                }
                b -= read;
            }
        }
        finally {
            this.bufferPool.release(arrayBackedBuffer);
        }
        return n - b;
    }
    
    @Override
    public synchronized void close() throws IOException {
        if (this.isClosed) {
            return;
        }
        this.isClosed = true;
        this.bufferPool.release(this.srcByteBuffer);
        freeDStream(this.stream);
        this.in.close();
    }
    
    static {
        Native.load();
        srcBuffSize = (int)recommendedDInSize();
    }
}
