package de.fu_berlin.cdv.chasingpictures;

import android.os.AsyncTask;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import de.fu_berlin.cdv.chasingpictures.api.Picture;

/**
 * @author Simon
 */
public class PictureDownloader extends AsyncTask<Picture, PictureDownloader.Progress, Void> {
    private static final String TAG = "PictureDownloader";
    private static final int BUFFER_SIZE = 1024 * 100; // 100 KB
    private final File targetDirectory;

    public PictureDownloader(File targetDirectory) {
        this.targetDirectory = targetDirectory;
    }

    @Override
    protected Void doInBackground(Picture... params) {
        Progress progress = new Progress(params.length);

        for (Picture picture : params) {
            if (isCancelled())
                return null;

            try {
                String fileName = picture.getId() + "_" + picture.getUpdatedAt().getTime();
                File destinationFile = new File(targetDirectory, fileName);

                picture.setCachedFile(destinationFile);

                // If file already exists, (and isn't empty) skip the download.
                if (destinationFile.exists() && destinationFile.length() > 0) {
                    continue;
                }

                URL url = picture.getASCIIUrl();
                downloadUrlToFile(url, destinationFile);
            } catch (IOException e) {
                Log.e(TAG, Log.getStackTraceString(e));
                picture.setCachedFile(null);
            }

            publishProgress(progress.advance());
        }
        return null;
    }

    private void downloadUrlToFile(URL url, File destinationFile) throws IOException {
        String location;
        HttpURLConnection urlConnection;

        // Follow redirects
        while (true) {
            urlConnection = ((HttpURLConnection) url.openConnection());

            /*
            urlConnection.setConnectTimeout(15000);
            urlConnection.setReadTimeout(15000);
            urlConnection.setInstanceFollowRedirects(false);
             */

            switch (urlConnection.getResponseCode()) {
                case HttpURLConnection.HTTP_MOVED_PERM:
                case HttpURLConnection.HTTP_MOVED_TEMP:
                    location = urlConnection.getHeaderField("Location");
                    url = new URL(url, location);  // Deal with relative URLs
                    continue;
            }

            break;
        }

        int contentLength = urlConnection.getContentLength();

        InputStream in = new BufferedInputStream(urlConnection.getInputStream());
        FileOutputStream fos = new FileOutputStream(destinationFile);
        byte[] buffer;

        if (contentLength > 0) {
            buffer = new byte[contentLength];
        } else {
            buffer = new byte[BUFFER_SIZE];
        }

        try {
            int result;
            do {
                result = in.read(buffer);
                if (result > 0)
                    fos.write(buffer, 0, result);
            } while (result > 0);
        } finally {
            in.close();
            fos.close();
        }
    }

    public static class Progress {
        protected int current;
        public final int max;

        public Progress(int max) {
            this.max = max;
            this.current = 0;
        }

        public Progress advance() {
            current++;
            return this;
        }

        public double getPercent() {
            return (100.0 * current) / max;
        }

        public int getCurrent() {
            return current;
        }
    }
}

@@ -65,16 +65,60 @@
 ncTask;%0A
+import android.support.annotation.Nullable;%0A
 import a
@@ -865,98 +865,130 @@
     
-Progress progress = new Progress(params.length);%0A%0A        for (Picture picture : params) %7B
+int count = 0;%0A%0A        for (Picture picture : params) %7B%0A            final Progress progress = new Progress(count, null);%0A
 %0A   
@@ -1743,16 +1743,58 @@
 (null);%0A
+                progress.setException(e);%0A
         
@@ -1840,19 +1840,30 @@
 ress
-.advance())
+);%0A            count++
 ;%0A  
@@ -3460,132 +3460,425 @@
     
-public static class Progress %7B%0A        protected int current;%0A        public final int max;%0A%0A        public Progress(int max
+/**%0A     * Class indicating the progress of downloading.%0A     * If an exception happened, it can be retrieved using %7B@link #getException()%7D.%0A     */%0A    public static class Progress %7B%0A        private final int state;%0A        @Nullable%0A        private Throwable exception;%0A%0A        public Progress(int state) %7B%0A            this.state = state;%0A        %7D%0A%0A        public Progress(int state, @Nullable Throwable exception
 ) %7B%0A
@@ -3898,17 +3898,21 @@
 his.
-max = max
+state = state
 ;%0A  
@@ -3930,19 +3930,29 @@
 his.
-current = 0
+exception = exception
 ;%0A  
@@ -3979,87 +3979,378 @@
 lic 
-Progress advance() %7B%0A            current++;%0A            r
+int getState() %7B%0A            return state;%0A        %7D%0A%0A        @Deprecated%0A        public int getCurrent() %7B%0A            return state;%0A        %7D%0A%0A        /**%0A         * R
 eturn
+s
  th
-is;%0A        %7D%0A
+e exception published with this progress update.%0A         *%0A         * @return A %7B@link Throwable%7D describing the error, or %7B@code null%7D if no exception occurred.%0A         */%0A        @Nullable
 %0A   
@@ -4365,25 +4365,30 @@
 lic 
-dou
+Throwa
 ble get
-Percent
+Exception
 () %7B
@@ -4411,31 +4411,17 @@
 urn 
-(100.0 * current) / max
+exception
 ;%0A  
@@ -4448,53 +4448,97 @@
 lic 
-int getCurrent() %7B%0A            return current
+void setException(@Nullable Throwable exception) %7B%0A            this.exception = exception
 ;%0A  

Update download progress to contain exceptions