package com.smartcar.pvrmemoryleakdemo;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.IntEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;

import java.util.ArrayList;

/**
 * Created by tongguangli on 15-11-14.
 */
public class SCPopupWindow {

    private WindowManager mWindowManager = null;
    private View mChildView = null;
    private SCPopupWindowView mSCPopupView = null;
    private int mWidth = -1;
    private int mHeight = -1;
    private WindowManager.LayoutParams mLayoutParams = null;
    private View mAchorView = null;
    private boolean isThouchOutSide = true;
    private Animator mEnterAnimator = null;
    private Animator mExitAnimator = null;

    private OnDismissListener mOnDismissListener = null;
    private OnShowListener mOnShowListener = null;
    private boolean isClickOutSide = false;
    private Handler mHandler = new Handler();

    public SCPopupWindow(Context context, View child, int width, int height) {
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        mChildView = child;
        mWidth = width;
        mHeight = height;
        mLayoutParams = getWindowLayoutParams();
        initView(context);
    }

    private void initView(Context context) {
        mSCPopupView = new SCPopupWindowView(context);
        mSCPopupView.addView(mChildView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        mWindowManager.addView(mSCPopupView, mLayoutParams);
        mSCPopupView.setVisibility(View.GONE);
    }

    public void setThouchOutSide(boolean isThouchOutSide) {
        this.isThouchOutSide = isThouchOutSide;
    }


    public View getAchorView() {
        return mAchorView;
    }

    public void setWindowEnterAnimator(Animator animator) {
        this.mEnterAnimator = animator;
    }

    public void setWindowExitAnimator(Animator animator) {
        this.mExitAnimator = animator;
    }

    public void showWindow(View view, int xoff, int yoff) {
        this.mAchorView = view;
        int achorHeight = view.getMeasuredHeight();
        if (this.isThouchOutSide) {
            mLayoutParams.flags = WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
        } else {
            mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        }
        mLayoutParams.y = achorHeight + yoff;
        mLayoutParams.x = xoff;
        mWindowManager.updateViewLayout(mSCPopupView, mLayoutParams);
        if (isShowing()) {
            return;
        }
        show();
    }

    public void showWindow(View achor, int gravity, int xoff, int yoff) {
        int[] location = new int[2];
        achor.getLocationOnScreen(location);
        int achorWidth = achor.getMeasuredWidth();
        int achorHeight = achor.getMeasuredHeight();
        this.mAchorView = achor;
        if (this.isThouchOutSide) {
            mLayoutParams.flags = WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
        } else {
            mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
        }
        switch (gravity) {
            case Gravity.TOP:
                mLayoutParams.y = location[1] + yoff;
                mLayoutParams.x = location[0] + achorWidth / 2 - mWidth / 2 + xoff;
                break;
            case Gravity.LEFT:
                break;
            case Gravity.BOTTOM:
                mLayoutParams.y = location[1] + achorHeight + yoff;
                mLayoutParams.x = location[0] + achorWidth / 2 - mWidth / 2 + xoff;
                break;
            case Gravity.RIGHT:
                break;
        }
        mWindowManager.updateViewLayout(mSCPopupView, mLayoutParams);
        if (isShowing()) {
            return;
        }
        show();
    }

    private void show() {
        mSCPopupView.setVisibility(View.VISIBLE);
        startShowAnimator();
    }

    private void startShowAnimator() {
        if (mEnterAnimator == null) {
            mEnterAnimator = createDefaultShowAnimator();
        }
        mEnterAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                animation.removeListener(this);
                if (mOnShowListener != null) {
                    mOnShowListener.onShow();
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                animation.removeListener(this);
                if (mOnShowListener != null) {
                    mOnShowListener.onShow();
                }
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        mEnterAnimator.start();
    }

    public boolean isShowing() {
        return mSCPopupView.isShown();
    }

    public void dismiss() {
        if (mExitAnimator == null) {
            mExitAnimator = createDefaultHideAnimator();
        }
        mExitAnimator.removeListener(mExitAnimatorListener);
        mExitAnimator.addListener(mExitAnimatorListener);
        mExitAnimator.start();
    }

    private WindowManager.LayoutParams getWindowLayoutParams() {
        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        /*layoutParams.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;*/
        layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
        layoutParams.format = PixelFormat.RGBA_8888;
        layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;

        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        layoutParams.x = 0;
        layoutParams.y = 59 * 2;
        layoutParams.width = mWidth;
        layoutParams.height = mHeight;
        return layoutParams;
    }

    private Animator.AnimatorListener mExitAnimatorListener = new Animator.AnimatorListener() {

        @Override
        public void onAnimationStart(Animator animation) {

        }

        @Override
        public void onAnimationEnd(Animator animation) {
            animation.removeAllListeners();
            mSCPopupView.setVisibility(View.GONE);
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            animation.removeAllListeners();
            mSCPopupView.setVisibility(View.GONE);
        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    };


    private class SCPopupWindowView extends FrameLayout {

        public SCPopupWindowView(Context context) {
            super(context);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int action = event.getAction();
            switch (action & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_OUTSIDE:
                    if (isClickOutSide) {
                        dismiss();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    if (isClickOutSide) {
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                dismiss();
                            }
                        });
                    }
                    break;
            }
            return true;
        }


        @Override
        protected void onVisibilityChanged(View changedView, int visibility) {
            super.onVisibilityChanged(changedView, visibility);
            if (changedView == this && (visibility == View.GONE || visibility == View.INVISIBLE) && mOnDismissListener != null) {
                mOnDismissListener.onDismiss();
            }
        }
    }

    public void setOnDismissListener(OnDismissListener mOnDismissListener) {
        this.mOnDismissListener = mOnDismissListener;
    }

    public interface OnDismissListener {
        public void onDismiss();
    }

    public void setOnShowListener(OnShowListener mOnShowListener) {
        this.mOnShowListener = mOnShowListener;
    }

    public interface OnShowListener {
        public void onShow();
    }

    private int getChildHeight() {
        return mHeight;
    }

    private Animator createDefaultShowAnimator() {
        ArrayList<Animator> animators = new ArrayList<>();

        ValueAnimator height = ValueAnimator.ofObject(new ContentHeightEvaluator(mChildView), 0, getChildHeight());
        height.setInterpolator(new PathInterpolator(0.5f, 0f, 0f, 1f));
        height.setDuration(400);
        animators.add(height);

        View content = mChildView.findViewById(R.id.sc_pop_win_content);
        if (content == null) {
            content = mChildView;
        }

        Animator alpha = ObjectAnimator.ofFloat(content, "alpha", 0f, 1f);
        alpha.setInterpolator(new PathInterpolator(0.5f, 0f, 0f, 1f));
        alpha.setDuration(400);
        animators.add(alpha);

        Animator tranlateY = ObjectAnimator.ofFloat(mChildView, "translationY", -30, 0);
        tranlateY.setInterpolator(new PathInterpolator(0.5f, 0f, 0f, 1f));
        tranlateY.setDuration(400);
        animators.add(tranlateY);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(animators);
        return animatorSet;
    }

    private Animator createDefaultHideAnimator() {
        ArrayList<Animator> animators = new ArrayList<>();

        View content = mChildView.findViewById(R.id.sc_pop_win_content);
        if (content == null) {
            content = mChildView;
        }
        Animator alpha = ObjectAnimator.ofFloat(content, "alpha", 1f, 0f);
        alpha.setInterpolator(new PathInterpolator(0.5f, 0f, 0f, 1f));
        alpha.setDuration(400);
        animators.add(alpha);


        Animator tranlateY = ObjectAnimator.ofFloat(mChildView, "translationY", 0, -30);
        tranlateY.setInterpolator(new PathInterpolator(0.5f, 0f, 0f, 1f));
        tranlateY.setDuration(400);
        animators.add(tranlateY);

        ValueAnimator height = ValueAnimator.ofObject(new ContentHeightEvaluator(mChildView), getChildHeight(), 0);
        height.setInterpolator(new PathInterpolator(0.5f, 0f, 0f, 1f));
        height.setDuration(400);
        animators.add(height);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(animators);
        return animatorSet;
    }

    private static class ContentHeightEvaluator extends IntEvaluator {
        private View mContentView = null;

        public ContentHeightEvaluator(View contentView) {
            mContentView = contentView;
        }

        @Override
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            int height = super.evaluate(fraction, startValue, endValue);
            ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
            layoutParams.height = height;
            mContentView.setLayoutParams(layoutParams);
            return height;
        }
    }

}
