package com.hx.curtain.drawer;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;

import com.hx.curtain.drawer.nineoldandroids.animation.Animator;
import com.hx.curtain.drawer.nineoldandroids.animation.ValueAnimator;

import static com.hx.curtain.drawer.R.styleable.CurtainMenu;


/**
 * Created by caifangmao on 15/3/26.
 */
public class CurtainContentLayout extends FrameLayout {

    public interface OnCurtainLayoutListener {
        void onSlide(View caurtainLayout, float slideOffset);
    }

    private static final int DEFAULT_INTERCEPT_LENGTH = 30;
    private int defaultMenuWidth;

    private View content;
    private View menu;
    private CurtainView curtainView;

    private Bitmap curtainTexture;

    private int initX;
    private int initY;

    private int currentX;
    private int currentY;

    private int vx;

    private Paint paint;

    private boolean inSlidingMode = false;

    private static final int SLIDING_MODE_CLOSED = 0;
    private static final int SLIDING_MODE_OPENED = 1;
    private static final int SLIDING_MODE_SLIDING = 2;

    private int slidingMode = 0;

    private int minVelocity;
    private int maxVY;
    private VelocityTracker velocityTracker;

    private ValueAnimator slidingAnimator;
    private float maxScrollRate;
    private OnCurtainLayoutListener curtainLayoutListener;
    private GestureDetector gestureDetector;

    public void setCurtainLayoutListener(OnCurtainLayoutListener curtainLayoutListener) {
        this.curtainLayoutListener = curtainLayoutListener;
    }

    private GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onDown(MotionEvent event) {

            if (slidingMode != SLIDING_MODE_OPENED) {
                slidingAnimator.cancel();

                inSlidingMode = true;

                initX = (int) event.getX();
                initY = (int) event.getY();

                if (curtainTexture != null && !curtainTexture.isRecycled()) {
                    curtainTexture.recycle();

                }

                curtainTexture = snapshot(CurtainContentLayout.this.content);
                curtainView.setTexture(curtainTexture);
                curtainView.setVisibility(View.VISIBLE);
                CurtainContentLayout.this.content.setVisibility(View.GONE);

                return true;
            } else {
                if (event.getX() < defaultMenuWidth) {
                    return false;
                } else {
                    slidingAnimator.cancel();

                    inSlidingMode = true;

                    initX = (int) event.getX();
                    initY = (int) event.getY();

                    vx = defaultMenuWidth;

                    if (curtainTexture != null && !curtainTexture.isRecycled()) {
                        curtainTexture.recycle();

                    }

                    curtainTexture = snapshot(CurtainContentLayout.this.content);
                    curtainView.setTexture(curtainTexture);
                    curtainView.setVisibility(View.VISIBLE);
                    CurtainContentLayout.this.content.setVisibility(View.GONE);

                    return true;
                }
            }

        }

        @Override
        public boolean onSingleTapUp(MotionEvent event) {

            if (slidingMode == SLIDING_MODE_OPENED && event.getX() >= defaultMenuWidth) {
                slidingAnimator.setIntValues(vx, 0);
                slidingAnimator.setDuration(500);
                slidingAnimator.start();

                return true;
            } else {
                return false;
            }


        }

        @Override
        public boolean onScroll(MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {

            if (CurtainContentLayout.this.content != null) {
                currentX = (int) ev2.getX();
                currentY = (int) ev2.getY();

                vx = slidingMode == SLIDING_MODE_CLOSED ? currentX - initX : defaultMenuWidth - (initX - currentX);

                if (vx < 0) {
                    vx = 0;
                }

                if (vx > CurtainContentLayout.this.menu.getWidth()) {
                    vx = CurtainContentLayout.this.menu.getWidth();
                }

                curtainView.setWaveHeight(vx / (float) curtainView.getMeasuredWidth());
                if (curtainLayoutListener != null)
                    curtainLayoutListener.onSlide(CurtainContentLayout.this, vx / (float) curtainView.getMeasuredWidth() / maxScrollRate);
            }

            return true;
        }

        @Override
        public boolean onFling(MotionEvent ev1, MotionEvent ev2, float velocityX, float velocityY) {

            if (Math.abs(velocityX) > minVelocity * 5) {
                if (velocityX > 0) {
                    slidingAnimator.setIntValues(vx, defaultMenuWidth);
                    slidingAnimator.setDuration((long) (Math.abs(defaultMenuWidth - vx) / (float) defaultMenuWidth * 500L));
                } else {
                    slidingAnimator.setDuration(500);//(long) (((float) vx / Math.abs(velocityX)) * 1000.0F)
                    slidingAnimator.setIntValues(vx, 0);
                }

                slidingAnimator.start();
            } else {
                if (ev2.getX() > defaultMenuWidth / 2) {
                    slidingAnimator.setIntValues(vx, defaultMenuWidth);
                    slidingAnimator.setDuration((long) (Math.abs(defaultMenuWidth - vx) / (float) defaultMenuWidth * 500L));
                } else {
                    slidingAnimator.setIntValues(vx, 0);
                    slidingAnimator.setDuration(500);
                }

                slidingAnimator.start();
            }

            return true;
        }
    };


    public CurtainContentLayout(Context context) throws Exception {
        this(context, null);
    }

    public CurtainContentLayout(Context context, AttributeSet attrs) throws Exception {
        this(context, attrs, 0);
    }

    public CurtainContentLayout(Context context, AttributeSet attrs, int defStyle) throws Exception {
        super(context, attrs, defStyle);


        TypedArray ta = context.obtainStyledAttributes(attrs, CurtainMenu);
        Float hWaveCount = ta.getFloat(R.styleable.CurtainMenu_h_waveCount, 5f);
        Float vWaveCount = ta.getFloat(R.styleable.CurtainMenu_v_waveCount, 1.1f);
        int menuLayoutId = ta.getResourceId(R.styleable.CurtainMenu_behind_menu, -1);
        int contentLayoutId = ta.getResourceId(R.styleable.CurtainMenu_content, -1);
        maxScrollRate = ta.getFloat(R.styleable.CurtainMenu_maxRate, 0.75f);
        ta.recycle();
        //相对于父view最大划开区域
        defaultMenuWidth = (int) (getResources().getDisplayMetrics().widthPixels * maxScrollRate);
        curtainView = new CurtainView(context, hWaveCount, vWaveCount);
        //curtainView.setDirection(CurtainView.DIRECTION_LEFT);

        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        addView(curtainView, 0, layoutParams);
        curtainView.setVisibility(View.GONE);


        if (menuLayoutId != -1) {
            addMenu(LayoutInflater.from(context).inflate(menuLayoutId, null, false));
        }

        if (contentLayoutId != -1) {
            addContent(LayoutInflater.from(context).inflate(contentLayoutId, null, false));
        } else {
            throw new Exception("you must set curtain content layout!!!");
        }

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        gestureDetector = new GestureDetector(context, gestureListener);

        minVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();

        slidingAnimator = ValueAnimator.ofInt(vx, 1);
        slidingAnimator.setDuration(500L);
        slidingAnimator.setInterpolator(new DecelerateInterpolator());
        slidingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (Integer) animation.getAnimatedValue();
                setSlidingFactor(value);
            }
        });
        slidingAnimator.addListener(new Animator.AnimatorListener() {

            @Override
            public void onAnimationCancel(Animator animator) {
            }

            @Override
            public void onAnimationStart(Animator animator) {
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                if (vx > defaultMenuWidth / 2) {
                    slidingMode = SLIDING_MODE_OPENED;
                } else {
                    slidingMode = SLIDING_MODE_CLOSED;
                }
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }

        });
    }

    public void toggle() {
        switch (slidingMode) {
            case SLIDING_MODE_CLOSED:

                if (curtainTexture == null) {
                    return;
                }

                slidingAnimator.setIntValues(vx, defaultMenuWidth);
                slidingAnimator.setDuration(500L);
                slidingAnimator.setInterpolator(new DecelerateInterpolator());
                slidingAnimator.start();
                break;
            case SLIDING_MODE_OPENED:

                slidingAnimator.setIntValues(vx, 0);
                slidingAnimator.setDuration(500L);
                slidingAnimator.setInterpolator(new DecelerateInterpolator());
                slidingAnimator.start();
                break;
        }


    }


    void setSlidingFactor(int slidingFactor) {
        this.vx = slidingFactor;

        if (this.vx <= 0) {
            this.content.setVisibility(View.VISIBLE);
            this.curtainView.setVisibility(View.GONE);
            inSlidingMode = false;
        } else {
            this.content.setVisibility(View.GONE);
            this.curtainView.setVisibility(View.VISIBLE);
        }

        this.curtainView.setWaveHeight(this.vx / (float) curtainView.getMeasuredWidth());
        if (curtainLayoutListener != null)
            curtainLayoutListener.onSlide(CurtainContentLayout.this, vx / (float) curtainView.getMeasuredWidth() / maxScrollRate);
    }

    Integer getSlidingFactor() {
        return this.vx;
    }

    public void addContent(View content) {

        if (content != null) {
            this.content = content;
            this.content.setBackgroundColor(0xFFFFFFFF);

            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

            addView(content, this.menu == null ? 0 : 1, layoutParams);
        }
    }

    public void addMenu(View menu) {
        if (menu != null) {
            this.menu = menu;

            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);

            addView(menu, 0, layoutParams);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        defaultMenuWidth = (int) (getMeasuredWidth() * maxScrollRate);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (event.getActionMasked() == MotionEvent.ACTION_DOWN && event.getX() <= DEFAULT_INTERCEPT_LENGTH) {
            return true;
        }
        return super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:

                if (velocityTracker == null) {
                    velocityTracker = VelocityTracker.obtain();
                }

                velocityTracker.addMovement(event);

                break;
            case MotionEvent.ACTION_MOVE:


                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:

                currentX = (int) event.getX();
                currentY = (int) event.getY();

                final VelocityTracker velocityTracker = this.velocityTracker;
                final int pointerId = event.getPointerId(0);
                velocityTracker.computeCurrentVelocity(1000, ViewConfiguration.get(getContext()).getScaledMaximumFlingVelocity());
                final float velocityY = velocityTracker.getYVelocity(pointerId);
                final float velocityX = velocityTracker.getXVelocity(pointerId);

                if (Math.abs(velocityX) <= 0 && initX != currentX) {
                    if (event.getX() > defaultMenuWidth / 2) {
                        slidingAnimator.setIntValues(vx, defaultMenuWidth);
                        slidingAnimator.setDuration((long) (Math.abs(defaultMenuWidth - vx) / (float) defaultMenuWidth * 500L));
                        slidingAnimator.setInterpolator(new DecelerateInterpolator());
                        slidingAnimator.start();
                    } else {
                        slidingAnimator.setIntValues(vx, 0);
                        slidingAnimator.setDuration((long) (vx / (float) defaultMenuWidth * 500L));
                        slidingAnimator.setInterpolator(new DecelerateInterpolator());
                        slidingAnimator.start();
                    }
                }


                break;
        }

        return gestureDetector.onTouchEvent(event);
    }

    @Override
    public void setBackgroundColor(int color) {
    }

    private Bitmap snapshot(View v) {

        Bitmap b = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Drawable bg = getBackground();
        if (bg != null) {
            bg.setBounds(0, 0, getWidth(), getHeight());
            bg.draw(c);
        } else {
            paint.setColor(0xFFFFFFFF);
            c.drawRect(0, 0, getWidth(), getHeight(), paint);
        }
        v.draw(c);
        //make sure the color on the top will continue to the status bar area
//        paint.setColor(b.getPixel(0, getStatusBarHeight() + 1));
//        c.drawRect(0, 0, getContext().getResources().getDisplayMetrics().widthPixels, getStatusBarHeight(), paint);
        return b;
    }

    private int getStatusBarHeight() {
        int result = 0;
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            result = getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }

    @Override
    public void dispatchDraw(Canvas canvas) {
        if (inSlidingMode) {
            paint.setColor(0xFF000000);
            canvas.drawRect(menu.getRight(), 0, getWidth(), getHeight(), paint);
        }


        super.dispatchDraw(canvas);
    }
}
