/*
 * Copyright (C) 2012 Google Inc.
 * Licensed to 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.mail.browse;

import android.app.FragmentManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewParent;

import com.android.ex.photo.util.ImageUtils;
import com.android.mail.R;
import com.android.mail.analytics.Analytics;
import com.android.mail.providers.Attachment;
import com.android.mail.providers.UIProvider;
import com.android.mail.providers.UIProvider.AttachmentDestination;
import com.android.mail.providers.UIProvider.AttachmentRendition;
import com.android.mail.ui.AttachmentTile;
import com.android.mail.ui.AttachmentTileGrid;
import com.android.mail.utils.AttachmentUtils;
import com.android.mail.utils.LogTag;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.Utils;

import java.util.Comparator;
import java.util.PriorityQueue;

/**
 * View for a single attachment in conversation view. Shows download status and allows launching
 * intents to act on an attachment.
 *
 */
public class MessageAttachmentTile extends AttachmentTile implements OnClickListener,
        AttachmentViewInterface {

    private int mPhotoIndex;
    private View mTextContainer;

    private final AttachmentActionHandler mActionHandler;

    private PhotoViewHandler mPhotoViewHandler;

    private static final String LOG_TAG = LogTag.getLogTag();

    /**
     * Let someone else do this work, since it typically requires broader visibility of context,
     * like what other photos to also show alongside this one.
     */
    public interface PhotoViewHandler {
        void viewPhoto(MessageAttachmentTile source);
    }

    public MessageAttachmentTile(Context context) {
        this(context, null);
    }

    public MessageAttachmentTile(Context context, AttributeSet attrs) {
        super(context, attrs);

        mActionHandler = new AttachmentActionHandler(context, this);
    }

    public void initialize(FragmentManager fragmentManager) {
        mActionHandler.initialize(fragmentManager);
    }

    public void setPhotoViewHandler(PhotoViewHandler pvh) {
        mPhotoViewHandler = pvh;
    }

    /**
     * Render or update an attachment's view. This happens immediately upon instantiation, and
     * repeatedly as status updates stream in, so only properties with new or changed values will
     * cause sub-views to update.
     */
    public void render(Attachment attachment, int index,
            AttachmentPreviewCache attachmentPreviewCache, boolean loaderResult) {
        render(attachment, attachmentPreviewCache);

        mPhotoIndex = index;

        mActionHandler.setAttachment(mAttachment);
        mActionHandler.updateStatus(loaderResult);
    }

    public static MessageAttachmentTile inflate(LayoutInflater inflater, ViewGroup parent) {
        MessageAttachmentTile view = (MessageAttachmentTile) inflater.inflate(
                R.layout.conversation_message_attachment_tile, parent, false);
        return view;
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        mTextContainer = findViewById(R.id.attachment_tile_text_container);

        setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        onClick();
    }

    private boolean onClick() {
        showAndDownloadAttachments();
        return true;
    }

    private void showAndDownloadAttachments() {
        // TODO: clean this up, it seems like it should live in AttachmentTileGrid since it keeps
        // inappropriately touching this view's peers
        AttachmentTileGrid tileGrid = ((AttachmentTileGrid) getParent());
        int childCount = tileGrid.getChildCount();

        PriorityQueue<MessageAttachmentTile> queue = new PriorityQueue<MessageAttachmentTile>(
                childCount, new ViewIndexDistanceComparator(mPhotoIndex));
        for (int i = 0; i < childCount; i++) {
            MessageAttachmentTile tile = (MessageAttachmentTile) tileGrid.getChildAt(i);
            queue.add(tile);
        }

        // we want our downloads to have higher priority than the highest background downloads
        int maxAdditionalPriority = childCount;
        for (int i = 0; i < childCount; i++) {
            // higher priority tiles are returned first
            MessageAttachmentTile tile = queue.remove();
            tile.downloadAttachment(maxAdditionalPriority - i, i != 0);
        }

        viewAttachment();
    }

    public void downloadAttachment(int additionalPriority, boolean delayDownload) {
        if (!mAttachment.isPresentLocally()) {
            mActionHandler.startDownloadingAttachment(AttachmentDestination.CACHE,
                    UIProvider.AttachmentRendition.BEST, additionalPriority, delayDownload);
        }
    }

    @Override
    public void viewAttachment() {
        final String mime = Utils.normalizeMimeType(mAttachment.getContentType());

        Analytics.getInstance()
                .sendEvent("view_attachment", mime, "attachment_tile", mAttachment.size);

        if (ImageUtils.isImageMimeType(mime)) {
            if (mPhotoViewHandler != null) {
                mPhotoViewHandler.viewPhoto(this);
            } else {
                LogUtils.e(LOG_TAG, "unable to view image attachment b/c handler is null");
            }
            return;
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        Utils.setIntentDataAndTypeAndNormalize(
                intent, mAttachment.contentUri, mime);
        try {
            getContext().startActivity(intent);
        } catch (ActivityNotFoundException e) {
            // couldn't find activity for View intent
            LogUtils.e(LOG_TAG, "Couldn't find Activity for intent", e);
        }
    }

    @Override
    public void updateProgress(boolean showDeterminateProgress) {
        // do not show progress for image tiles
    }

    @Override
    public void onUpdateStatus() {
    }

    @Override
    public void setThumbnailToDefault() {
        super.setThumbnailToDefault();
        mTextContainer.setVisibility(VISIBLE);
    }

    @Override
    public void setThumbnail(Bitmap result) {
        super.setThumbnail(result);
        mTextContainer.setVisibility(GONE);
    }

    @Override
    public void thumbnailLoadFailed() {
        super.thumbnailLoadFailed();

        if (AttachmentUtils.canDownloadAttachment(getContext(), null)) {
            // Download if there is network. This check prevents the attachment
            // download from failing and making the error toast show
            mActionHandler.startDownloadingAttachment(
                    AttachmentDestination.CACHE, AttachmentRendition.SIMPLE, 0, false);
        }
    }

    /**
     * Given two child views, figure out whose index is closest to the specified
     * index.
     */
    public static class ViewIndexDistanceComparator implements Comparator<View>{
        final private int mIndex;
        /**
         * @param index Compare based on each view's distance to this index
         */
        public ViewIndexDistanceComparator(int index) {
            mIndex = index;
        }

        @Override
        public int compare(View lhs, View rhs) {
            ViewParent parent = lhs.getParent();
            if (parent == rhs.getParent()) {
                if (parent instanceof ViewGroup) {
                    ViewGroup p = (ViewGroup) parent;
                    int lhsIndex = p.indexOfChild(lhs);
                    int rhsIndex = p.indexOfChild(rhs);
                    int lhsDistance = Math.abs(mIndex - lhsIndex);
                    int rhsDistance = Math.abs(mIndex - rhsIndex);
                    // prefer shorter distance since they are the next ones to be swiped to
                    int result = lhsDistance - rhsDistance;
                    if (result == 0) {
                        // prefer higher index since they are to the right in the photoviewer
                        return rhsIndex - lhsIndex;
                    }
                    return result;
                }
            }
            return 0;
        }
    }
}
