package com.github.ignition.support.images.remote;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;

import com.github.ignition.support.cache.ImageCache;

public class RemoteImageLoaderJob implements Runnable {

    private static final String LOG_TAG = "Ignition/ImageLoader";

    private static final int DEFAULT_RETRY_HANDLER_SLEEP_TIME = 1000;

    private String imageUrl;
    private RemoteImageLoaderHandler handler;
    private ImageCache imageCache;
    private int numRetries, defaultBufferSize;

    public RemoteImageLoaderJob(String imageUrl, RemoteImageLoaderHandler handler, ImageCache imageCache,
            int numRetries, int defaultBufferSize) {
        this.imageUrl = imageUrl;
        this.handler = handler;
        this.imageCache = imageCache;
        this.numRetries = numRetries;
    }

    /**
     * The job method run on a worker thread. It will first query the image cache, and on a miss,
     * download the image from the Web.
     */
    @Override
    public void run() {
        Bitmap bitmap = null;

        if (imageCache != null) {
            // at this point we know the image is not in memory, but it could be cached to SD card
            bitmap = imageCache.getBitmap(imageUrl);
        }

        if (bitmap == null) {
            bitmap = downloadImage();
        }

        notifyImageLoaded(imageUrl, bitmap);
    }

    // TODO: we could probably improve performance by re-using connections instead of closing them
    // after each and every download
    protected Bitmap downloadImage() {
        int timesTried = 1;

        while (timesTried <= numRetries) {
            try {
                byte[] imageData = retrieveImageData();

                if (imageData == null) {
                    break;
                }

                if (imageCache != null) {
                    imageCache.put(imageUrl, imageData);
                }

                return BitmapFactory.decodeByteArray(imageData, 0, imageData.length);

            } catch (Throwable e) {
                Log.w(LOG_TAG, "download for " + imageUrl + " failed (attempt " + timesTried + ")");
                e.printStackTrace();
                SystemClock.sleep(DEFAULT_RETRY_HANDLER_SLEEP_TIME);
                timesTried++;
            }
        }

        return null;
    }

    protected byte[] retrieveImageData() throws IOException {
        URL url = new URL(imageUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        // determine the image size and allocate a buffer
        int fileSize = connection.getContentLength();
        if (fileSize <= 0) {
            fileSize = defaultBufferSize;
            Log.w(LOG_TAG,
                    "Server did not set a Content-Length header, will default to buffer size of "
                            + defaultBufferSize + " bytes");
        }
        byte[] imageData = new byte[fileSize];

        // download the file
        Log.d(LOG_TAG, "fetching image " + imageUrl + " (" + fileSize + ")");
        BufferedInputStream istream = new BufferedInputStream(connection.getInputStream());
        int bytesRead = 0;
        int offset = 0;
        while (bytesRead != -1 && offset < fileSize) {
            bytesRead = istream.read(imageData, offset, fileSize - offset);
            offset += bytesRead;
        }

        // clean up
        istream.close();
        connection.disconnect();

        return imageData;
    }

    protected void notifyImageLoaded(String url, Bitmap bitmap) {
        Message message = new Message();
        message.what = RemoteImageLoaderHandler.HANDLER_MESSAGE_ID;
        Bundle data = new Bundle();
        data.putString(RemoteImageLoaderHandler.IMAGE_URL_EXTRA, url);
        Bitmap image = bitmap;
        data.putParcelable(RemoteImageLoaderHandler.BITMAP_EXTRA, image);
        message.setData(data);

        handler.sendMessage(message);
    }
}

@@ -81,16 +81,54 @@
 Stream;%0A
+import java.io.ByteArrayOutputStream;%0A
 import j
@@ -1093,16 +1093,68 @@
 etries;%0A
+        this.defaultBufferSize = defaultBufferSize;%0A
     %7D%0A%0A 
@@ -2948,28 +2948,109 @@
     
-if (fileSize %3C= 0) %7B
+BufferedInputStream istream = new BufferedInputStream(connection.getInputStream());%0A%0A        try %7B   
 %0A   
@@ -3058,16 +3058,20 @@
         
+if (
 fileSize
@@ -3071,37 +3071,28 @@
 ileSize 
+%3C
 = 
-defaultBufferSize;%0A
+0) %7B%0A    
         
@@ -3110,16 +3110,20 @@
 OG_TAG,%0A
+    
         
@@ -3240,16 +3240,20 @@
         
+    
 + defaul
@@ -3277,34 +3277,513 @@
 ytes%22);%0A        
-%7D%0A
+        ByteArrayOutputStream buf = new ByteArrayOutputStream(defaultBufferSize);%0A                byte%5B%5D buffer = new byte%5BdefaultBufferSize%5D;%0A                int bytesRead = 0;%0A                while (bytesRead != -1) %7B%0A                    bytesRead = istream.read(buffer, 0, defaultBufferSize);%0A                    if (bytesRead %3E 0)%0A                        buf.write(buffer, 0, bytesRead);%0A                %7D%0A                return buf.toByteArray();%0A            %7D else %7B%0A        
         byte%5B%5D i
@@ -3813,25 +3813,40 @@
 eSize%5D;%0A
-%0A
+        %0A       
         
 // downl
@@ -3833,24 +3833,25 @@
             
+ 
 // download 
@@ -3859,16 +3859,24 @@
 he file%0A
+        
         
@@ -3957,92 +3957,8 @@
     
-BufferedInputStream istream = new BufferedInputStream(connection.getInputStream());%0A
     
@@ -3972,32 +3972,40 @@
  bytesRead = 0;%0A
+        
         int offs
@@ -4008,24 +4008,32 @@
 offset = 0;%0A
+        
         whil
@@ -4079,32 +4079,40 @@
 ) %7B%0A            
+      
+  
 bytesRead = istr
@@ -4171,16 +4171,24 @@
         
+        
 offset +
@@ -4212,31 +4212,136 @@
     
-%7D%0A%0A        // clean up%0A
+        %7D%0A                return imageData;%0A            %7D%0A        %7D finally %7B%0A            // clean up%0A            try %7B%0A        
     
@@ -4357,24 +4357,32 @@
 am.close();%0A
+        
         conn
@@ -4406,34 +4406,60 @@
 ();%0A
-%0A        return imageData;
+            %7D catch (Exception ignore) %7B %7D%0A        %7D
 %0A   

work when server does not give Content-Length