/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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.android.camera.data;

import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.os.AsyncTask;
import android.provider.MediaStore.Images;
import android.util.Log;

import com.android.camera.data.LocalMediaData.PhotoData;
import com.android.camera.exif.ExifInterface;
import com.android.camera.exif.ExifTag;
import com.android.camera2.R;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * RotationTask can be used to rotate a {@link LocalData} by updating the exif
 * data from jpeg file. Note that only {@link PhotoData}  can be rotated.
 */
public class RotationTask extends AsyncTask<LocalData, Void, LocalData> {
    private static final String TAG = "CAM_RotationTask";
    private final Context mContext;
    private final LocalDataAdapter mAdapter;
    private final int mCurrentDataId;
    private final boolean mClockwise;
    private ProgressDialog mProgress;

    public RotationTask(Context context, LocalDataAdapter adapter,
            int currentDataId, boolean clockwise) {
        mContext = context;
        mAdapter = adapter;
        mCurrentDataId = currentDataId;
        mClockwise = clockwise;
    }

    @Override
    protected void onPreExecute() {
        // Show a progress bar since the rotation could take long.
        mProgress = new ProgressDialog(mContext);
        int titleStringId = mClockwise ? R.string.rotate_right : R.string.rotate_left;
        mProgress.setTitle(mContext.getString(titleStringId));
        mProgress.setMessage(mContext.getString(R.string.please_wait));
        mProgress.setCancelable(false);
        mProgress.show();
    }

    @Override
    protected LocalData doInBackground(LocalData... data) {
        return rotateInJpegExif(data[0]);
    }

    /**
     * Rotates the image by updating the exif. Done in background thread.
     * The worst case is the whole file needed to be re-written with
     * modified exif data.
     *
     * @return A new {@link LocalData} object which containing the new info.
     */
    private LocalData rotateInJpegExif(LocalData data) {
        if (!(data instanceof PhotoData)) {
            Log.w(TAG, "Rotation can only happen on PhotoData.");
            return null;
        }

        PhotoData imageData = (PhotoData) data;
        int originRotation = imageData.getOrientation();
        int finalRotationDegrees;
        if (mClockwise) {
            finalRotationDegrees = (originRotation + 90) % 360;
        } else {
            finalRotationDegrees = (originRotation + 270) % 360;
        }

        String filePath = imageData.getPath();
        ContentValues values = new ContentValues();
        boolean success = false;
        int newOrientation = 0;
        if (imageData.getMimeType().equalsIgnoreCase(LocalData.MIME_TYPE_JPEG)) {
            ExifInterface exifInterface = new ExifInterface();
            ExifTag tag = exifInterface.buildTag(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.getOrientationValueForRotation(
                            finalRotationDegrees));
            if (tag != null) {
                exifInterface.setTag(tag);
                try {
                    exifInterface.forceRewriteExif(filePath);
                    long fileSize = new File(filePath).length();
                    values.put(Images.Media.SIZE, fileSize);
                    newOrientation = finalRotationDegrees;
                    success = true;
                } catch (FileNotFoundException e) {
                    Log.w(TAG, "Cannot find file to set exif: " + filePath);
                } catch (IOException e) {
                    Log.w(TAG, "Cannot set exif data: " + filePath);
                }
            } else {
                Log.w(TAG, "Cannot build tag: " + ExifInterface.TAG_ORIENTATION);
            }
        }

        PhotoData result = null;
        if (success) {
            // Swap width and height after rotation.
            int oldWidth = imageData.getWidth();
            int newWidth = imageData.getHeight();
            int newHeight = oldWidth;
            values.put(Images.Media.WIDTH, newWidth);
            values.put(Images.Media.HEIGHT, newHeight);

            // MediaStore using SQLite is thread safe.
            values.put(Images.Media.ORIENTATION, finalRotationDegrees);
            mContext.getContentResolver().update(imageData.getContentUri(),
                    values, "_id=?",
                    new String[] {
                            String.valueOf(imageData.getId()) });

            double[] latLong = data.getLatLong();
            double latitude = 0;
            double longitude = 0;
            if (latLong != null) {
                latitude = latLong[0];
                longitude = latLong[1];
            }

            result = new PhotoData(data.getId(), data.getTitle(),
                    data.getMimeType(), data.getDateTaken(), data.getDateModified(),
                    data.getPath(), newOrientation, newWidth, newHeight,
                    data.getSizeInBytes(), latitude, longitude);
        }

        return result;
    }

    @Override
    protected void onPostExecute(LocalData result) {
        mProgress.dismiss();
        if (result != null) {
            mAdapter.updateData(mCurrentDataId, result);
        }
    }
}
