package cn.hjf.downloader;

import android.os.Process;

import java.io.BufferedInputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.Callable;

/**
 * Created by huangjinfu on 2017/8/5.
 */

public class HttpWorker implements Callable<Range> {

    private Task task;
    private Range range;

    private WorkListener workListener;
    private ProgressListener progressListener;

    private volatile boolean quit;
    private byte[] buffer = new byte[1024 * 1024];

    public HttpWorker(
            Task task,
            Range range,
            WorkListener workListener,
            ProgressListener progressListener) {
        this.task = task;
        this.range = range;
    }

    @Override
    public Range call() throws Exception {
        /* Downgrade download thread priority. */
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        /* Connect server. */
        URL url = new URL(task.getUrlStr());
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        /* Add header. */
        addHeader(connection);
        /* Check response. */
        /* Remote resource modified.*/
        if (connection.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED) {
            workListener.onResourceModified(task);
            return null;
        }
        /* Response 206, download. */
        if (connection.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
            readAndWrite(connection);
        }
        return null;
    }

    private void addHeader(HttpURLConnection connection) {
        HttpResource r = (HttpResource) task.getResource();
        if (r.geteTag() != null && !"".equals(r.geteTag())) {
            connection.setRequestProperty("If-Match", r.geteTag());
        }
        if (r.getLastModified() != null && !"".equals(r.getLastModified())) {
            connection.setRequestProperty("If-Unmodified-Since", r.geteTag());
        }
        connection.setRequestProperty("Range", "bytes=" + range.getStart() + "-" + range.getEnd());
    }

    private void readAndWrite(HttpURLConnection connection) {
        RandomAccessFile randomAccessFile = null;
        BufferedInputStream bis = null;
        try {
            bis = new BufferedInputStream(connection.getInputStream());

            randomAccessFile = new RandomAccessFile(task.getFilePath(), "rw");
            randomAccessFile.seek(range.getStart());

            final long total = range.getEnd() - range.getStart() + 1;
            int downloadCount = 0;
            int readCount;
            while ((readCount = bis.read(buffer)) != -1) {
                randomAccessFile.write(buffer, 0, readCount);
                downloadCount += readCount;
                progressListener.onUpdate(total, downloadCount);

                /* Time to quit. */
                if (quit) {
                    workListener.onDownload(task, range, new Range(range.getStart(), range.getStart() + downloadCount - 1));
                    return;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            /* Download nothing. */
            workListener.onDownload(task, range, Range.INVALID_RANGE);
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
                if (randomAccessFile != null) {
                    randomAccessFile.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void quit() {
        quit = true;
    }
}

@@ -535,16 +535,47 @@
 * 1024%5D;
+%0A    private int downloadCount;
 %0A%0A    pu
@@ -781,16 +781,108 @@
  range;%0A
+        this.workListener = workListener;%0A        this.progressListener = progressListener;%0A
     %7D%0A%0A 
@@ -2682,42 +2682,8 @@
  1;%0A
-            int downloadCount = 0;
 %0A   
@@ -3025,273 +3025,312 @@
     
-workListener.onDownload(task, range, new Range(range.getStart(), range.getStart() + downloadCount - 1));%0A                    return;%0A                %7D%0A            %7D%0A        %7D catch (Exception e) %7B%0A            e.printStackTrace();%0A            /* Download nothing. */
+return;%0A                %7D%0A            %7D%0A        %7D catch (Exception e) %7B%0A            e.printStackTrace();%0A        %7D finally %7B%0A            /* Update download range. */%0A            Range download = downloadCount == 0 ? Range.INVALID_RANGE : new Range(range.getStart(), range.getStart() + downloadCount - 1);
 %0A   
@@ -3379,49 +3379,46 @@
 ge, 
-Range.INVALID_RANGE);%0A        %7D finally %7B
+download);%0A            /* Close io. */
 %0A   

Improve HttpWorker.