package org.jabref.logic.net;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;

/**
 * An input stream that keeps track of the amount of bytes already read.
 * Code based on http://stackoverflow.com/a/1339589/873661, but converted to use JavaFX properties instead of listeners
 */
public class ProgressInputStream extends FilterInputStream {

    private final long maxNumBytes;
    private final LongProperty totalNumBytesRead;
    private final LongProperty progress;

    public ProgressInputStream(InputStream in, long maxNumBytes) {
        super(in);
        this.totalNumBytesRead = new SimpleLongProperty(0);
        this.progress = new SimpleLongProperty(0);

        this.maxNumBytes = maxNumBytes <= 0 ? 1 : maxNumBytes;
        this.progress.bind(totalNumBytesRead.divide(this.maxNumBytes));
    }

    public long getTotalNumBytesRead() {
        return totalNumBytesRead.get();
    }

    public LongProperty totalNumBytesReadProperty() {
        return totalNumBytesRead;
    }

    public long getProgress() {
        return progress.get();
    }

    public LongProperty progressProperty() {
        return progress;
    }

    public long getMaxNumBytes() {
        return maxNumBytes;
    }

    @Override
    public int read() throws IOException {
        int b = super.read();
        updateProgress(1);
        return b;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        return (int) updateProgress(super.read(b, off, len));
    }

    @Override
    public long skip(long n) throws IOException {
        return updateProgress(super.skip(n));
    }

    @Override
    public void mark(int readlimit) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void reset() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean markSupported() {
        return false;
    }

    private long updateProgress(long numBytesRead) {
        if (numBytesRead > 0) {
            totalNumBytesRead.set(totalNumBytesRead.get() + numBytesRead);
        }

        return numBytesRead;
    }
}
