package com.jscape.filetransfer;

import com.jscape.util.IOTools;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

import static com.jscape.util.Parameters.assertNotNull;

/**
 * @author Alex Usun
 */
public class FileTransferPipedInputStream
        extends PipedInputStream
        implements Runnable {

    private final FileTransfer transfer;
    private final String remoteFile;
    private final long offset;
    private final PipedOutputStream out;
    private volatile Exception error;

    public static FileTransferPipedInputStream streamFor(FileTransfer transfer, String remoteFile, long offset)
            throws Exception {
        PipedOutputStream out = new PipedOutputStream();
        FileTransferPipedInputStream in = new FileTransferPipedInputStream(transfer, remoteFile, offset, out);
        out.connect(in);

        return in;
    }

    private FileTransferPipedInputStream(FileTransfer transfer, String remoteFile, long offset, PipedOutputStream out) {
        assertNotNull(transfer);
        this.transfer = transfer;

        assertNotNull(remoteFile);
        this.remoteFile = remoteFile;

        this.offset = offset;

        assertNotNull(out);
        this.out = out;
    }

    @Override
    public void run() {
        try {
            this.transfer.resumeDownload(this.out, this.remoteFile, this.offset);
        } catch (Exception e) {
            this.error = e;
        } finally {
            IOTools.close(this.out);
        }
    }

    @Override
    public synchronized int read()
            throws IOException {
        assertNoErrors();
        return super.read();
    }

    @Override
    public synchronized int read(byte[] buffer, int offset, int length)
            throws IOException {
        assertNoErrors();
        return super.read(buffer, offset, length);
    }

    private void assertNoErrors()
            throws IOException {
        if (this.error != null) {
            throw IOTools.ioException(this.error);
        }
    }
}
