
package org.zarroboogs.weibo.support.lib;

import org.zarroboogs.weibo.support.utils.Utility;

import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.widget.ImageView;

public class AnimationRect implements Parcelable {

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeParcelable(scaledBitmapRect, flags);
        dest.writeParcelable(imageViewEntireRect, flags);
        dest.writeParcelable(imageViewVisibleRect, flags);
        dest.writeInt(type);
        dest.writeBooleanArray(new boolean[]{
                isTotalVisible
        });
        dest.writeBooleanArray(new boolean[]{
                isTotalInvisible
        });
        dest.writeBooleanArray(new boolean[]{
                isScreenPortrait
        });
        dest.writeFloat(thumbnailWidthHeightRatio);
        dest.writeInt(thumbnailWidth);
        dest.writeInt(thumbnailHeight);
        dest.writeInt(widgetWidth);
        dest.writeInt(widgetHeight);
        dest.writeFloat(clipByParentRectTop);
        dest.writeFloat(clipByParentRectBottom);
        dest.writeFloat(clipByParentRectLeft);
        dest.writeFloat(clipByParentRectRight);
    }

    public static final Creator<AnimationRect> CREATOR = new Creator<AnimationRect>() {
        public AnimationRect createFromParcel(Parcel in) {
            AnimationRect rect = new AnimationRect();
            rect.scaledBitmapRect = in.readParcelable(Rect.class.getClassLoader());
            rect.imageViewEntireRect = in.readParcelable(Rect.class.getClassLoader());
            rect.imageViewVisibleRect = in.readParcelable(Rect.class.getClassLoader());
            rect.type = in.readInt();

            boolean[] booleans = new boolean[1];
            in.readBooleanArray(booleans);
            rect.isTotalVisible = booleans[0];

            boolean[] isTotalInvisibleBooleans = new boolean[1];
            in.readBooleanArray(isTotalInvisibleBooleans);
            rect.isTotalInvisible = isTotalInvisibleBooleans[0];

            boolean[] isScreenPortraitArray = new boolean[1];
            in.readBooleanArray(isScreenPortraitArray);
            rect.isScreenPortrait = isScreenPortraitArray[0];

            rect.thumbnailWidthHeightRatio = in.readFloat();
            rect.thumbnailWidth = in.readInt();
            rect.thumbnailHeight = in.readInt();

            rect.widgetWidth = in.readInt();
            rect.widgetHeight = in.readInt();

            rect.clipByParentRectTop = in.readFloat();
            rect.clipByParentRectBottom = in.readFloat();
            rect.clipByParentRectLeft = in.readFloat();
            rect.clipByParentRectRight = in.readFloat();

            return rect;
        }

        public AnimationRect[] newArray(int size) {
            return new AnimationRect[size];
        }
    };

    public static final int TYPE_CLIP_V = 0;

    public static final int TYPE_CLIP_H = 1;

    public static final int TYPE_EXTEND_V = 2;

    public static final int TYPE_EXTEND_H = 3;

    public float clipByParentRectTop;

    public float clipByParentRectBottom;

    public float clipByParentRectLeft;

    public float clipByParentRectRight;

    public Rect imageViewEntireRect;

    public Rect imageViewVisibleRect;

    public Rect scaledBitmapRect;

    public int type = -1;

    public boolean isTotalVisible;

    public boolean isTotalInvisible;

    public boolean isScreenPortrait;

    public float thumbnailWidthHeightRatio;

    public int thumbnailWidth;

    public int thumbnailHeight;

    public int widgetWidth;

    public int widgetHeight;

    public static AnimationRect buildFromImageView(ImageView imageView) {
        AnimationRect rect = new AnimationRect();

        rect.isScreenPortrait = Utility.isDevicePort();

        Drawable drawable = imageView.getDrawable();

        if (drawable == null) {
            return null;
        }
        Rect drawableRect = drawable.getBounds();

        rect.widgetWidth = imageView.getWidth();

        rect.widgetHeight = imageView.getHeight();

        rect.thumbnailWidthHeightRatio = (float) drawableRect.width() / (float) drawableRect.height();

        rect.thumbnailWidth = drawableRect.width();

        rect.thumbnailHeight = drawableRect.height();

        rect.imageViewEntireRect = new Rect();
        int[] location = new int[2];
        imageView.getLocationOnScreen(location);
        rect.imageViewEntireRect.left = location[0];
        rect.imageViewEntireRect.top = location[1];
        rect.imageViewEntireRect.right = rect.imageViewEntireRect.left + imageView.getWidth();
        rect.imageViewEntireRect.bottom = rect.imageViewEntireRect.top + imageView.getHeight();

        rect.imageViewVisibleRect = new Rect();
        boolean isVisible = imageView.getGlobalVisibleRect(rect.imageViewVisibleRect);

        boolean checkWidth = rect.imageViewVisibleRect.width() < imageView.getWidth();
        boolean checkHeight = rect.imageViewVisibleRect.height() < imageView.getHeight();

        rect.isTotalVisible = isVisible && !checkWidth && !checkHeight;

        rect.isTotalInvisible = !isVisible;

        ImageView.ScaleType scaledType = imageView.getScaleType();

        Rect scaledBitmapRect = new Rect(rect.imageViewEntireRect);

        int bitmapWidth = drawableRect.width();
        int bitmapHeight = drawableRect.height();

        int imageViewWidth = imageView.getWidth();
        int imageViewHeight = imageView.getHeight();

        float startScale;

        int deltaX;

        int deltaY;

        switch (scaledType) {
            case CENTER_CROP:

                if ((float) imageViewWidth / bitmapWidth > (float) imageViewHeight / bitmapHeight) {

                    startScale = (float) imageViewWidth / bitmapWidth;
                    rect.type = TYPE_CLIP_V;

                } else {
                    startScale = (float) imageViewHeight / bitmapHeight;
                    rect.type = TYPE_CLIP_H;
                }

                bitmapHeight = (int) (bitmapHeight * startScale);
                bitmapWidth = (int) (bitmapWidth * startScale);

                deltaX = (imageViewWidth - bitmapWidth) / 2;
                deltaY = (imageViewHeight - bitmapHeight) / 2;

                scaledBitmapRect.set(scaledBitmapRect.left + deltaX, scaledBitmapRect.top + deltaY, scaledBitmapRect.right
                        - deltaX, scaledBitmapRect.bottom
                        - deltaY);

                break;

            case FIT_CENTER:

                if ((float) imageViewWidth / bitmapWidth > (float) imageViewHeight / bitmapHeight) {
                    // Extend start bounds horizontally
                    startScale = (float) imageViewHeight / bitmapHeight;

                    rect.type = TYPE_EXTEND_V;

                } else {
                    startScale = (float) imageViewWidth / bitmapWidth;
                    rect.type = TYPE_EXTEND_H;
                }

                bitmapHeight = (int) (bitmapHeight * startScale);
                bitmapWidth = (int) (bitmapWidth * startScale);

                deltaX = (imageViewWidth - bitmapWidth) / 2;
                deltaY = (imageViewHeight - bitmapHeight) / 2;

                scaledBitmapRect.set(scaledBitmapRect.left + deltaX, scaledBitmapRect.top + deltaY, scaledBitmapRect.right
                        - deltaX, scaledBitmapRect.bottom
                        - deltaY);

                break;
        }

        rect.scaledBitmapRect = scaledBitmapRect;

        return rect;
    }

    public static float getClipLeft(AnimationRect animationRect, Rect finalBounds) {
        final Rect startBounds = animationRect.scaledBitmapRect;

        float startScale;
        if ((float) finalBounds.width() / finalBounds.height() > (float) startBounds.width() / startBounds.height()) {
            startScale = (float) startBounds.height() / finalBounds.height();

        } else {
            startScale = (float) startBounds.width() / finalBounds.width();
        }

        int oriBitmapScaledWidth = (int) (finalBounds.width() * startScale);

        // sina server may cut thumbnail's right or bottom
        int thumbnailAndOriDeltaRightSize = Math.abs(animationRect.scaledBitmapRect.width() - oriBitmapScaledWidth);

        float serverClipThumbnailRightSizePercent = (float) thumbnailAndOriDeltaRightSize / (float) oriBitmapScaledWidth;

        float deltaH = oriBitmapScaledWidth - oriBitmapScaledWidth * serverClipThumbnailRightSizePercent - animationRect.widgetWidth;

        float deltaLeft = deltaH / 2;

        if (!animationRect.isTotalVisible && !animationRect.isTotalInvisible) {
            float deltaInvisibleLeft = Math.abs(animationRect.imageViewVisibleRect.left
                    - animationRect.imageViewEntireRect.left);
            deltaLeft += deltaInvisibleLeft;
        }

        return (deltaLeft) / (float) oriBitmapScaledWidth;
    }

    public static float getClipTop(AnimationRect animationRect, Rect finalBounds) {

        final Rect startBounds = animationRect.scaledBitmapRect;

        float startScale;
        if ((float) finalBounds.width() / finalBounds.height() > (float) startBounds.width() / startBounds.height()) {
            startScale = (float) startBounds.height() / finalBounds.height();

        } else {
            startScale = (float) startBounds.width() / finalBounds.width();
        }

        int oriBitmapScaledHeight = (int) (finalBounds.height() * startScale);

        // sina server may cut thumbnail's right or bottom
        int thumbnailAndOriDeltaBottomSize = Math.abs(animationRect.scaledBitmapRect.height() - oriBitmapScaledHeight);

        float serverClipThumbnailBottomSizePercent = (float) thumbnailAndOriDeltaBottomSize / (float) oriBitmapScaledHeight;

        float deltaV = oriBitmapScaledHeight - oriBitmapScaledHeight * serverClipThumbnailBottomSizePercent - animationRect.widgetHeight;

        float deltaTop = deltaV / 2;

        if (!animationRect.isTotalVisible && !animationRect.isTotalInvisible) {

            float deltaInvisibleTop = Math.abs(animationRect.imageViewVisibleRect.top
                    - animationRect.imageViewEntireRect.top);

            deltaTop += deltaInvisibleTop;

        }

        return (deltaTop) / (float) oriBitmapScaledHeight;
    }

    public static float getClipRight(AnimationRect animationRect, Rect finalBounds) {
        final Rect startBounds = animationRect.scaledBitmapRect;

        float startScale;
        if ((float) finalBounds.width() / finalBounds.height() > (float) startBounds.width() / startBounds.height()) {
            startScale = (float) startBounds.height() / finalBounds.height();

        } else {
            startScale = (float) startBounds.width() / finalBounds.width();
        }

        int oriBitmapScaledWidth = (int) (finalBounds.width() * startScale);

        // sina server may cut thumbnail's right or bottom
        int thumbnailAndOriDeltaRightSize = Math.abs(animationRect.scaledBitmapRect.width() - oriBitmapScaledWidth);

        float serverClipThumbnailRightSizePercent = (float) thumbnailAndOriDeltaRightSize / (float) oriBitmapScaledWidth;

        float deltaH = oriBitmapScaledWidth - oriBitmapScaledWidth * serverClipThumbnailRightSizePercent - animationRect.widgetWidth;

        float deltaRight = deltaH / 2;

        if (!animationRect.isTotalVisible && !animationRect.isTotalInvisible) {
            float deltaInvisibleRight = Math.abs(animationRect.imageViewVisibleRect.right
                    - animationRect.imageViewEntireRect.right);
            deltaRight += deltaInvisibleRight;
        }

        deltaRight += thumbnailAndOriDeltaRightSize;

        return (deltaRight) / (float) oriBitmapScaledWidth;
    }

    public static float getClipBottom(AnimationRect animationRect, Rect finalBounds) {
        final Rect startBounds = animationRect.scaledBitmapRect;

        float startScale;
        if ((float) finalBounds.width() / finalBounds.height() > (float) startBounds.width() / startBounds.height()) {
            startScale = (float) startBounds.height() / finalBounds.height();

        } else {
            startScale = (float) startBounds.width() / finalBounds.width();
        }

        int oriBitmapScaledHeight = (int) (finalBounds.height() * startScale);

        // sina server may cut thumbnail's right or bottom
        int thumbnailAndOriDeltaBottomSize = Math.abs(animationRect.scaledBitmapRect.height() - oriBitmapScaledHeight);

        float serverClipThumbnailBottomSizePercent = (float) thumbnailAndOriDeltaBottomSize / (float) oriBitmapScaledHeight;

        float deltaV = oriBitmapScaledHeight - oriBitmapScaledHeight * serverClipThumbnailBottomSizePercent - animationRect.widgetHeight;

        float deltaBottom = deltaV / 2;

        if (!animationRect.isTotalVisible && !animationRect.isTotalInvisible) {

            float deltaInvisibleBottom = Math.abs(animationRect.imageViewVisibleRect.bottom
                    - animationRect.imageViewEntireRect.bottom);

            deltaBottom += deltaInvisibleBottom;
        }

        deltaBottom += thumbnailAndOriDeltaBottomSize;
        return (deltaBottom) / (float) oriBitmapScaledHeight;
    }

}
