/*
 * Copyright (C) 2012 Brian Muramatsu
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.btmura.android.reddit.widget;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.Log;
import android.util.LruCache;

import com.btmura.android.reddit.R;

public class ThumbnailLoader {

    private static final String TAG = "ThumbnailLoader";

    private static final BitmapCache BITMAP_CACHE = new BitmapCache(2 * 1024 * 1024);

    public void setThumbnail(Context context, ThingView v, String url) {
        if (!TextUtils.isEmpty(url)) {
            Bitmap b = BITMAP_CACHE.get(url);
            v.setThumbnailBitmap(b);
            if (b == null) {
                LoadThumbnailTask task = (LoadThumbnailTask) v.getTag();
                if (task == null || !url.equals(task.url)) {
                    if (task != null) {
                        task.cancel(true);
                    }
                    task = new LoadThumbnailTask(context, v, url);
                    v.setTag(task);
                    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                }
            }
        } else {
            LoadThumbnailTask task = (LoadThumbnailTask) v.getTag();
            if (task != null) {
                task.cancel(true);
                v.setTag(null);
            }
            v.setThumbnailBitmap(null);
        }
    }

    static class BitmapCache extends LruCache<String, Bitmap> {
        BitmapCache(int size) {
            super(size);
        }

        @Override
        protected int sizeOf(String key, Bitmap value) {
            return value.getByteCount();
        }
    }

    class LoadThumbnailTask extends AsyncTask<Void, Void, Bitmap> {

        private final Context context;
        private final WeakReference<ThingView> ref;
        private final String url;

        LoadThumbnailTask(Context context, ThingView v, String url) {
            this.context = context.getApplicationContext();
            this.ref = new WeakReference<ThingView>(v);
            this.url = url;
        }

        @Override
        protected Bitmap doInBackground(Void... params) {
            HttpURLConnection conn = null;
            try {
                URL u = new URL(url);
                conn = (HttpURLConnection) u.openConnection();
                Bitmap original = BitmapFactory.decodeStream(conn.getInputStream());
                Bitmap rounded = getThumbnailBitmap(original);
                original.recycle();
                return rounded;

            } catch (MalformedURLException e) {
                Log.e(TAG, "doInBackground", e);
            } catch (IOException e) {
                Log.e(TAG, "doInBackground", e);
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
            }
            return null;
        }

        private Bitmap getThumbnailBitmap(Bitmap original) {
            Resources r = context.getResources();
            float density = r.getDisplayMetrics().density;
            int radius = r.getDimensionPixelSize(R.dimen.radius);
            int thumbWidth = r.getDimensionPixelSize(R.dimen.thumb_width);
            int thumbHeight = Math.round(original.getHeight() * density);

            Bitmap rounded = Bitmap.createBitmap(thumbWidth, thumbHeight, Config.ARGB_8888);
            Canvas canvas = new Canvas(rounded);
            canvas.drawARGB(0, 0, 0, 0);

            Rect src = new Rect(0, 0, original.getWidth(), original.getHeight());
            RectF dst = new RectF(0, 0, thumbWidth, thumbHeight);

            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
            canvas.drawRoundRect(dst, radius, radius, paint);

            paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
            canvas.drawBitmap(original, src, dst, paint);

            return rounded;
        }

        @Override
        protected void onPostExecute(Bitmap b) {
            if (b != null) {
                BITMAP_CACHE.put(url, b);
            }
            ThingView v = ref.get();
            if (v != null && equals(v.getTag())) {
                if (b != null) {
                    v.setThumbnailBitmap(b);
                }
                v.setTag(null);
            }
        }
    }
}

@@ -661,32 +661,60 @@
 io.IOException;%0A
+import java.io.InputStream;%0A
 import java.lang
@@ -3278,24 +3278,60 @@
 onn = null;%0A
+            Bitmap original = null;%0A
             
@@ -3457,53 +3457,114 @@
     
-Bitmap original = BitmapFactory.decodeStream(
+if (isCancelled()) %7B%0A                    return null;%0A                %7D%0A%0A                InputStream is = 
 conn
@@ -3580,17 +3580,16 @@
 Stream()
-)
 ;%0A      
@@ -3602,52 +3602,137 @@
     
-Bitmap rounded = getThumbnailBitmap(original
+if (isCancelled()) %7B%0A                    return null;%0A                %7D%0A%0A                original = BitmapFactory.decodeStream(is
 );%0A 
@@ -3750,28 +3750,33 @@
     
-original.recyc
+if (isCancel
 le
+d
 ()
-;%0A
+) %7B%0A    
     
@@ -3794,23 +3794,92 @@
  return 
-rounded
+null;%0A                %7D%0A%0A                return getThumbnailBitmap(original)
 ;%0A%0A     
@@ -3948,32 +3948,30 @@
 .e(TAG, 
-%22doInBackground%22
+e.getMessage()
 , e);%0A  
@@ -4037,24 +4037,22 @@
 AG, 
-%22doInBackground%22
+e.getMessage()
 , e)
@@ -4073,24 +4073,122 @@
 %7D finally %7B%0A
+                if (original != null) %7B%0A                    original.recycle();%0A                %7D%0A
             

Fix #66: check isCancelled state in thumbnail task