package com.skr.mdm.manager.oss;

import lombok.extern.slf4j.Slf4j;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;

@Slf4j
public class ProgressInputStream extends FilterInputStream {

    private final UploadListener monitor;
    private long nread = 0;
    private long size = 0;

    /**
     * Creates a <code>FilterInputStream</code>
     * by assigning the  argument <code>in</code>
     * to the field <code>this.in</code> so as
     * to remember it for later use.
     *
     * @param in the underlying input stream, or <code>null</code> if
     *           this instance is to be created without an underlying stream.
     */
    protected ProgressInputStream(InputStream in, UploadListener listener) {
        super(in);
        try {
            size = in.available();
        } catch (IOException ioe) {
            size = 0;
        }
        monitor = listener;
    }

    /**
     * Get the ProgressMonitor object being used by this stream. Normally
     * this isn't needed unless you want to do something like change the
     * descriptive text partway through reading the file.
     *
     * @return the ProgressMonitor object used by this object
     */
    public UploadListener getListener() {
        return monitor;
    }


    /**
     * Overrides <code>FilterInputStream.read</code>
     * to update the progress monitor after the read.
     */
    @Override
    public int read() throws IOException {
        int c = in.read();
        if (c >= 0) {
            notifyProcess(++nread);
        }
        return c;
    }


    /**
     * Overrides <code>FilterInputStream.read</code>
     * to update the progress monitor after the read.
     */
    @Override
    public int read(byte[] b) throws IOException {
        int nr = in.read(b);
        if (nr > 0) {
            notifyProcess(nread += nr);
        }

        return nr;
    }


    /**
     * Overrides <code>FilterInputStream.read</code>
     * to update the progress monitor after the read.
     */
    @Override
    public int read(byte[] b,
                    int off,
                    int len) throws IOException {
        int nr = in.read(b, off, len);
        if (nr > 0) {
            notifyProcess(nread += nr);
        }
        return nr;
    }


    /**
     * Overrides <code>FilterInputStream.skip</code>
     * to update the progress monitor after the skip.
     */
    @Override
    public long skip(long n) throws IOException {
        long nr = in.skip(n);
        if (nr > 0) {
            notifyProcess(nread += nr);
        }
        return nr;
    }


    /**
     * Overrides <code>FilterInputStream.close</code>
     * to close the progress monitor as well as the stream.
     */
    @Override
    public void close() throws IOException {
        in.close();
    }


    /**
     * Overrides <code>FilterInputStream.reset</code>
     * to reset the progress monitor as well as the stream.
     */
    @Override
    public synchronized void reset() throws IOException {
        in.reset();
        nread = size - in.available();

    }

    private void notifyProcess(long read) {
        if (monitor != null) {
            BigDecimal divide = BigDecimal.valueOf(read * 100).divide(BigDecimal.valueOf(size), 2, RoundingMode.HALF_UP);
            monitor.onProgress(Double.parseDouble(divide.toString()));
        }
    }
}
