/*
 * Copyright 2013 Google Inc.
 * 
 * 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.google.android.apps.mytracks.services.tasks;

import com.google.android.apps.mytracks.util.PhotoUtils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;

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

/**
 * A bitmap loader.
 * 
 * @author Jimmy Shih
 */
public class BitmapLoader extends AsyncTask<Void, Void, Bitmap> {
  private static final String TAG = BitmapLoader.class.getSimpleName();

  private final WeakReference<ImageView> imageViewReference;
  private final Uri uri;
  private final int targetWidth;
  private final int targetHeight;
  private final boolean fitWithin;

  public BitmapLoader(
      ImageView imageView, Uri uri, int targetWidth, int targetHeight, boolean fitWithin) {

    // Use a WeakReference to ensure the ImageView can be garbage collected
    imageViewReference = new WeakReference<ImageView>(imageView);
    this.uri = uri;
    this.targetWidth = targetWidth;
    this.targetHeight = targetHeight;
    this.fitWithin = fitWithin;
  }

  public Uri getUri() {
    return uri;
  }

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

    // Get the image dimensions
    BitmapFactory.Options options = new BitmapFactory.Options();

    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(uri.getPath(), options);

    // Set imageWidth and imageHeight based on image rotation
    int rotation = getRotation();
    int imageWidth;
    int imageHeight;

    if (rotation == 0 || rotation == 180) {
      imageWidth = options.outWidth;
      imageHeight = options.outHeight;
    } else {
      imageWidth = options.outHeight;
      imageHeight = options.outWidth;
    }

    // Get a scaled down version of the image
    options.inJustDecodeBounds = false;
    options.inSampleSize = getInSampleSize(imageWidth, imageHeight);
    options.inPurgeable = true;

    Bitmap scaledBitmap = BitmapFactory.decodeFile(uri.getPath(), options);

    // Get the final bitmap after rotating the scaled down image
    Bitmap bitmap;
    if (rotation == 0 && fitWithin) {
      bitmap = scaledBitmap;
    } else {
      Matrix matrix = new Matrix();
      matrix.postRotate(rotation);
      int offset = 0;
      int height = scaledBitmap.getHeight();
      if (!fitWithin && height > targetHeight) {
        offset = (height - targetHeight) / 2;
        height = targetHeight;
      }
      bitmap = Bitmap.createBitmap(
          scaledBitmap, 0, offset, scaledBitmap.getWidth(), height, matrix, true);
      scaledBitmap.recycle();
    }
    return bitmap;
  }

  @Override
  protected void onPostExecute(Bitmap bitmap) {
    if (isCancelled()) {
      bitmap = null;
    }
    // If imageView is still around, set bitmap
    if (imageViewReference != null && bitmap != null) {
      ImageView imageView = imageViewReference.get();
      if (imageView != null) {
        BitmapLoader bitmapLoader = PhotoUtils.getBitmapLoader(imageView);
        if (this == bitmapLoader) {
          imageView.setImageBitmap(bitmap);
        }
      }
    }
  }

  private int getRotation() {
    try {
      ExifInterface exifInterface = new ExifInterface(uri.getPath());
      switch (exifInterface.getAttributeInt(
          ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
        case ExifInterface.ORIENTATION_ROTATE_90:
          return 90;
        case ExifInterface.ORIENTATION_ROTATE_180:
          return 180;
        case ExifInterface.ORIENTATION_ROTATE_270:
          return 270;
        default:
          return 0;
      }
    } catch (IOException e) {
      Log.e(TAG, "Unable to get photo orientation", e);
      return 0;
    }
  }

  /**
   * Gets the in sample size.
   * 
   * @param imageWidth the image width
   * @param imageHeight the image height
   */
  private int getInSampleSize(int imageWidth, int imageHeight) {
    float widthRatio = 1;
    if (imageWidth > targetWidth) {
      widthRatio = (float) imageWidth / (float) targetWidth;
    }

    float heightRatio = 1;
    if (imageHeight > targetHeight) {
      heightRatio = (float) imageHeight / (float) targetHeight;
    }

    double size;
    if (fitWithin) {
      /*
       * To fit within the target area, return the larger sample ratio so the
       * image will not be larger than the target dimensions.
       */
      size = Math.max(widthRatio, heightRatio);
    } else {
      /*
       * To fill the target area, return the smaller ratio so the image will
       * cover both dimensions.
       */
      size = Math.min(widthRatio, heightRatio);
    }
    // Use Math.floor to not under-sample.
    return (int) Math.floor(size);
  }
}

@@ -2083,32 +2083,121 @@
 ath(), options);
+%0A    %0A    if (options.outWidth == 0 %7C%7C options.outHeight == 0) %7B%0A      return null;%0A    %7D
 %0A%0A    // Set ima
@@ -2800,16 +2800,77 @@
 tions);%0A
+    if (scaledBitmap == null) %7B%0A      return null;%0A    %7D%0A    
 %0A    // 

Handle the case the photo file is deleted when loading a bitmap