001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.io.IOException;
007import java.io.InputStream;
008import java.net.URLConnection;
009
010import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
011import org.openstreetmap.josm.gui.progress.ProgressMonitor;
012
013/**
014 * Read from an other reader and increment an progress counter while on the way.
015 * @author Imi
016 */
017public class ProgressInputStream extends InputStream {
018
019    private final InputStream in;
020    private int readSoFar = 0;
021    private int lastDialogUpdate = 0;
022    private boolean sizeKnown;
023    private final URLConnection connection;
024    private final ProgressMonitor progressMonitor;
025
026    public ProgressInputStream(URLConnection con, ProgressMonitor progressMonitor) throws OsmTransferException {
027        this.connection = con;
028        if (progressMonitor == null) {
029            progressMonitor = NullProgressMonitor.INSTANCE;
030        }
031        this.progressMonitor = progressMonitor;
032        progressMonitor.beginTask(tr("Contacting OSM Server..."), 1);
033        progressMonitor.indeterminateSubTask(null);
034
035        try {
036            this.in = con.getInputStream();
037        } catch (IOException e) {
038            progressMonitor.finishTask();
039            if (con.getHeaderField("Error") != null)
040                throw new OsmTransferException(tr(con.getHeaderField("Error")));
041            throw new OsmTransferException(e);
042        }
043
044        updateSize();
045        if (!sizeKnown) {
046            progressMonitor.indeterminateSubTask(tr("Downloading OSM data..."));
047        }
048    }
049
050    @Override public void close() throws IOException {
051        try {
052            in.close();
053        } finally {
054            progressMonitor.finishTask();
055        }
056    }
057
058    @Override public int read(byte[] b, int off, int len) throws IOException {
059        int read = in.read(b, off, len);
060        if (read != -1) {
061            advanceTicker(read);
062        } else {
063            progressMonitor.finishTask();
064        }
065        return read;
066    }
067
068    @Override public int read() throws IOException {
069        int read = in.read();
070        if (read != -1) {
071            advanceTicker(1);
072        } else {
073            progressMonitor.finishTask();
074        }
075        return read;
076    }
077
078    /**
079     * Increase ticker (progress counter and displayed text) by the given amount.
080     * @param amount
081     */
082    private void advanceTicker(int amount) {
083        readSoFar += amount;
084        updateSize();
085
086        if (readSoFar / 1024 != lastDialogUpdate) {
087            lastDialogUpdate++;
088            if (sizeKnown) {
089                progressMonitor.setTicks(readSoFar);
090            }
091            progressMonitor.setExtraText(readSoFar/1024 + " KB");
092        }
093    }
094
095    private void updateSize() {
096        if (!sizeKnown && connection.getContentLength() > 0) {
097            sizeKnown = true;
098            progressMonitor.subTask(tr("Downloading OSM data..."));
099            progressMonitor.setTicksCount(connection.getContentLength());
100        }
101    }
102}