package io.leocad.webcachedimageview;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.AsyncTask;
import android.util.Log;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;

import io.leocad.view.WebCachedImageView;


public class BitmapWorkerTask extends AsyncTask<Object, Void, Bitmap> {

	private WeakReference<WebCachedImageView> mImageViewReference;
	public String url;

	public BitmapWorkerTask(WebCachedImageView iv) {
		mImageViewReference = new WeakReference<WebCachedImageView>(iv);
	}

	@Override
	protected Bitmap doInBackground(Object... params) {

		url = (String) params[0];
		CacheManager cacheMgr = (CacheManager) params[1];
		int width = (Integer) params[2];
		int height = (Integer) params[3];
		Bitmap bitmap = null;

		// Check for cached versions
		if (
				// First, check in memory
				((bitmap = cacheMgr.getCachedOnMemory(url, width, height)) != null)
				// Then, check in disk
				|| ((bitmap = cacheMgr.getCachedOnDisk(url, width, height)) != null)

			) {
			return bitmap;
		}

		// No cached versions. Download it
		try {
			bitmap = decodeSampledBitmapFromUrl(url, width, height);

		} catch (IOException e) {
			Log.e("WebCachedImageView", "Can't download image at " + url, e);
		}

		// And cache it
		if (bitmap != null) {
			cacheMgr.cacheOnMemory(url, bitmap, width, height);
			cacheMgr.cacheOnDisk(url, bitmap, width, height);
		}

		return bitmap;
	}

	@Override
	protected void onPostExecute(Bitmap bitmap) {
		
		if (isCancelled()) {
            bitmap = null;
        }
		
		if (mImageViewReference != null && bitmap != null) {
            final WebCachedImageView imageView = mImageViewReference.get();
            
            if (imageView != null) {
            	final BitmapWorkerTask imageViewTask = imageView.getBitmapWorkerTask();
            	
            	if (imageViewTask == this) {
            		imageView.setImageBitmap(bitmap);
            	}
            }
        }
	}
	
	private static Bitmap decodeSampledBitmapFromUrl(String url, int reqWidth, int reqHeight) throws IOException {

	    // First decode with inJustDecodeBounds=true to check dimensions
	    final Options options = new Options();
	    options.inJustDecodeBounds = true;
	    
	    InputStream stream = fetchStream(url);
	    BitmapFactory.decodeStream(stream, null, options);
	    stream.close();

	    // Calculate inSampleSize
	    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
	    // Decode bitmap with inSampleSize set
	    options.inJustDecodeBounds = false;
	    
	    stream = fetchStream(url);
	    Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
	    stream.close();
	    
	    return bitmap;
	}
	
	private static InputStream fetchStream(String urlString) throws IllegalStateException, IOException {
		
		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpGet request = new HttpGet(urlString);
		HttpResponse response = httpClient.execute(request);
		return response.getEntity().getContent();
	}
	
	private static int calculateInSampleSize(Options options, int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {

			// Calculate ratios of height and width to requested height and width
			final int heightRatio = Math.round((float) height / (float) reqHeight);
			final int widthRatio = Math.round((float) width / (float) reqWidth);

			// Choose the smallest ratio as inSampleSize value, this will guarantee
			// a final image with both dimensions larger than or equal to the
			// requested height and width.
			inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
		}

		return inSampleSize;
	}
}