package com.datdo.mobilib.carrier;

import android.annotation.SuppressLint;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;

import com.daimajia.easing.Glider;
import com.daimajia.easing.Skill;
import com.datdo.mobilib.util.MblUtils;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.Animator.AnimatorListener;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;

import junit.framework.Assert;

/**
 * <pre>
 * An implementation of {@link com.datdo.mobilib.carrier.MblCarrier} with sliding animation when navigatings betweens interceptor.
 * 4 direction: LeftRight, RightLeft, TopBottom, BottomTop.
 * Default direction is LeftRight.
 * The animation works on all Android API >= 10
 * </pre>
 */
@SuppressLint("RtlHardcoded")
public class MblSlidingCarrier extends MblCarrier {

    /**
     * Contructor
     * @see com.datdo.mobilib.carrier.MblCarrier#MblCarrier(android.content.Context, android.widget.FrameLayout, com.datdo.mobilib.carrier.MblCarrier.MblCarrierCallback)
     */
    public MblSlidingCarrier(Context context, FrameLayout interceptorContainerView, MblCarrierCallback callback) {
        super(context, interceptorContainerView, callback);
    }

    /**
     * Sliding direction
     */
    public static enum SlidingDirection {
        LEFT_RIGHT, RIGHT_LEFT,
        TOP_BOTTOM, BOTTOM_TOP;
    }

    private SlidingDirection mSlidingDirection = SlidingDirection.LEFT_RIGHT;

    /**
     * Get direction to animate.
     */
    public SlidingDirection getSlidingDirection() {
        return mSlidingDirection;
    }

    /**
     * Set direction to animate.
     */
    public void setSlidingDirection(SlidingDirection slidingOrientation) {
        Assert.assertNotNull(slidingOrientation);
        mSlidingDirection = slidingOrientation;
    }

    private void animate(
            final MblInterceptor    currentInterceptor,
            final MblInterceptor    nextInterceptor,
            final int               from,
            final int               to,
            final Runnable          onAnimationEnd) {

        ValueAnimator anim = ValueAnimator.ofInt(from, to);
        anim.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator anim) {

                int val = (Integer) anim.getAnimatedValue();

                if (mSlidingDirection == SlidingDirection.LEFT_RIGHT || mSlidingDirection == SlidingDirection.RIGHT_LEFT) {
                    setX(currentInterceptor, val);
                    setX(nextInterceptor, val - to);
                } else if (mSlidingDirection == SlidingDirection.TOP_BOTTOM || mSlidingDirection == SlidingDirection.BOTTOM_TOP) {
                    setY(currentInterceptor, val);
                    setY(nextInterceptor, val - to);
                }

                // prevent blinking
                if (Math.abs(val - from) >= MblUtils.pxFromDp(10)) {
                    nextInterceptor.setVisibility(View.VISIBLE);
                } else {
                    nextInterceptor.setVisibility(View.INVISIBLE);
                }
            }
        });
        anim.addListener(new AnimatorListener() {

            @Override
            public void onAnimationCancel(Animator animation) {
                onAnimationEnd.run();
            }

            @Override
            public void onAnimationRepeat(Animator animation) {}

            @Override
            public void onAnimationStart(Animator animation) {}

            @Override
            public void onAnimationEnd(Animator animation) {
                onAnimationEnd.run();
            }
        });
        AnimatorSet set = new AnimatorSet();
        final long DURATION = 750;
        set.playTogether(Glider.glide(Skill.ExpoEaseOut, DURATION, anim));
        set.setDuration(DURATION);
        set.start();
    }

    @Override
    protected void animateForStarting(
            final MblInterceptor    currentInterceptor,
            final MblInterceptor    nextInterceptor,
            final Runnable          onAnimationEnd) {

        final int from = 0;
        final int to;
        switch (mSlidingDirection) {
            case LEFT_RIGHT:
                to = mInterceptorContainerView.getWidth();
                break;
            case RIGHT_LEFT:
                to = -mInterceptorContainerView.getWidth();
                break;
            case TOP_BOTTOM:
                to = mInterceptorContainerView.getHeight();
                break;
            case BOTTOM_TOP:
                to = -mInterceptorContainerView.getHeight();
                break;
            default:
                return; // never happen
        }

        animate(currentInterceptor, nextInterceptor, from, to, onAnimationEnd);
    }

    @Override
    protected void animateForFinishing(
            final MblInterceptor currentInterceptor,
            final MblInterceptor previousInterceptor,
            final Runnable onAnimationEnd) {

        final int from = 0;
        final int to;
        switch (mSlidingDirection) {
            case LEFT_RIGHT:
                to = -mInterceptorContainerView.getWidth();
                break;
            case RIGHT_LEFT:
                to = mInterceptorContainerView.getWidth();
                break;
            case TOP_BOTTOM:
                to = -mInterceptorContainerView.getHeight();
                break;
            case BOTTOM_TOP:
                to = mInterceptorContainerView.getHeight();
                break;
            default:
                return; // never happen
        }

        animate(currentInterceptor, previousInterceptor, from, to, onAnimationEnd);
    }

    @SuppressLint("NewApi")
    private void setX(View view, int x) {
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) view.getLayoutParams();
        lp.leftMargin = x;
        lp.rightMargin = -x;
        lp.gravity = Gravity.TOP | Gravity.LEFT;
        view.setLayoutParams(lp);
    }

    @SuppressLint("NewApi")
    private void setY(View view, int y) {
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) view.getLayoutParams();
        lp.topMargin = y;
        lp.bottomMargin = -y;
        lp.gravity = Gravity.TOP | Gravity.LEFT;
        view.setLayoutParams(lp);
    }
}

@@ -3918,10 +3918,10 @@
 N = 
-75
+60
 0;%0A 

Improve MblSlidingCarrier: faster animation