package com.cjj.mousepaint.contral.control;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.content.Context;
import android.os.Handler;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;


import com.cjj.mousepaint.R;
import com.cjj.mousepaint.contral.control.RhythmAdapter;
import com.cjj.mousepaint.utils.AnimatorUtils;
import com.cjj.mousepaint.utils.AppUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * User: shine
 * Date: 2014-12-12
 * Time: 16:48
 * Description:
 */
public class RhythmLayout extends HorizontalScrollView {


    private Context mContext;

    private RhythmAdapter mAdapter;

    private Handler mHandler;

    private ShiftMonitorTimer mTimer;

    private IRhythmItemListener mListener;


    private LinearLayout mLinearLayout;

    private float mItemWidth;

    private int mMaxTranslationHeight;

    private int mIntervalHeight;

    private int mCurrentItemPosition;

    private int mEdgeSizeForShiftRhythm;

    private int mScreenWidth;

    private long mFingerDownTime;

    private int mScrollStartDelayTime;

    private int mLastDisplayItemPosition;

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

    public RhythmLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }

    private void init() {
        mScreenWidth = AppUtils.getScreenDisplayMetrics(mContext).widthPixels;
        mItemWidth = mScreenWidth / 7;
        mMaxTranslationHeight = (int) mItemWidth;
        mIntervalHeight = (mMaxTranslationHeight / 6);
        mEdgeSizeForShiftRhythm = getResources().getDimensionPixelSize(R.dimen.rhythm_edge_size_for_shift);
        mCurrentItemPosition = -1;
        mLastDisplayItemPosition = -1;
        mScrollStartDelayTime = 0;
        mFingerDownTime = 0;
        mHandler = new Handler();
        mTimer = new ShiftMonitorTimer();
        mTimer.startMonitor();
    }

    public void setAdapter(RhythmAdapter adapter) {
        this.mAdapter = adapter;
        if (mLinearLayout == null) {
            mLinearLayout = (LinearLayout) getChildAt(0);
        }
        mAdapter.setItemWidth(mItemWidth);
        for (int i = 0; i < this.mAdapter.getCount(); i++) {
            mLinearLayout.addView(mAdapter.getView(i, null, null));
        }
    }


    public void invalidateData() {
        int childCount = this.mLinearLayout.getChildCount();
        if (childCount < this.mAdapter.getCount())
            for (int i = childCount; i < this.mAdapter.getCount(); i++)
                this.mLinearLayout.addView(this.mAdapter.getView(i, null, null));
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                mTimer.monitorTouchPosition(ev.getX(), ev.getY());
                updateItemHeight(ev.getX());
                break;
            case MotionEvent.ACTION_DOWN:
                mTimer.monitorTouchPosition(ev.getX(), ev.getY());
                mFingerDownTime = System.currentTimeMillis();
                updateItemHeight(ev.getX());
                if (mListener != null)
                    mListener.onStartSwipe();
                break;
            case MotionEvent.ACTION_UP:
                actionUp();
                break;
        }

        return true;
    }


    private void actionUp() {
        mTimer.monitorTouchPosition(-1.0F, -1.0F);
        if (mCurrentItemPosition < 0) {
            return;
        }
        int firstPosition = getFirstVisibleItemPosition();
        int lastPosition = firstPosition + mCurrentItemPosition;
        final List viewList = getVisibleViews();
        int size = viewList.size();
        if (size > mCurrentItemPosition) {
            viewList.remove(mCurrentItemPosition);
        }
        if (firstPosition - 1 >= 0) {
            viewList.add(mLinearLayout.getChildAt(firstPosition - 1));
        }
        if (lastPosition + 1 <= mLinearLayout.getChildCount()) {
            viewList.add(mLinearLayout.getChildAt(lastPosition + 1));
        }
        this.mHandler.postDelayed(new Runnable() {
            public void run() {
                for (int i = 0; i < viewList.size(); i++) {
                    View downView = (View) viewList.get(i);
                    shootDownItem(downView, true);
                }
            }
        }, 200L);
        if (mListener != null)
            mListener.onSelected(lastPosition);
        mCurrentItemPosition = -1;
        vibrate(20L);
    }

    private void updateItemHeight(float scrollX) {
        List viewList = getVisibleViews();
        int position = (int) (scrollX / mItemWidth);
        if (position == mCurrentItemPosition || position >= mLinearLayout.getChildCount())
            return;
        mCurrentItemPosition = position;
        makeItems(position, viewList);
    }


    private void makeItems(int fingerPosition, List<View> viewList) {
        if (fingerPosition >= viewList.size()) {
            return;
        }
        int size = viewList.size();
        for (int i = 0; i < size; i++) {

            int translationY = Math.min(Math.max(Math.abs(fingerPosition - i) * mIntervalHeight, 10), mMaxTranslationHeight);
            updateItemHeightAnimator(viewList.get(i), translationY);
        }

    }


    private List<View> getVisibleViews() {
        ArrayList arrayList = new ArrayList();
        if (mLinearLayout == null)
            return arrayList;
        int firstPosition = getFirstVisibleItemPosition();
        int lastPosition = firstPosition + 7;
        if (mLinearLayout.getChildCount() < 7) {
            lastPosition = mLinearLayout.getChildCount();
        }
        for (int i = firstPosition; i < lastPosition; i++)
            arrayList.add(mLinearLayout.getChildAt(i));
        return arrayList;
    }


    private List<View> getVisibleViews(boolean isForward, boolean isBackward) {
        ArrayList viewList = new ArrayList();
        if (this.mLinearLayout == null)
            return viewList;
        int firstPosition = getFirstVisibleItemPosition();
        int lastPosition = firstPosition + 7;
        if (mLinearLayout.getChildCount() < 7) {
            lastPosition = mLinearLayout.getChildCount();
        }
        if ((isForward) && (firstPosition > 0))
            firstPosition--;
        if ((isBackward) && (lastPosition < mLinearLayout.getChildCount()))
            lastPosition++;
        for (int i = firstPosition; i < lastPosition; i++)
            viewList.add(mLinearLayout.getChildAt(i));

        return viewList;
    }


    public int getFirstVisibleItemPosition() {
        if (mLinearLayout == null) {
            return 0;
        }
        int size = mLinearLayout.getChildCount();
        for (int i = 0; i < size; i++) {
            View view = mLinearLayout.getChildAt(i);
            if (getScrollX() < view.getX() + mItemWidth / 2.0F)
                return i;
        }
        return 0;
    }


    class ShiftMonitorTimer extends Timer {
        private TimerTask timerTask;
        private boolean canShift = false;
        private float x;
        private float y;

        void monitorTouchPosition(float x, float y) {
            this.x = x;
            this.y = y;
            if ((x < 0.0F) || ((x > mEdgeSizeForShiftRhythm) && (x < mScreenWidth - mEdgeSizeForShiftRhythm)) || (y < 0.0F)) {
                mFingerDownTime = System.currentTimeMillis();
                this.canShift = false;
            } else {
                this.canShift = true;
            }
        }

        void startMonitor() {
            if (this.timerTask == null) {
                timerTask = new TimerTask() {
                    @Override
                    public void run() {
                        long duration = System.currentTimeMillis() - mFingerDownTime;
                        if (canShift && duration > 1000) {
                            int firstPosition = getFirstVisibleItemPosition();
                            int toPosition = 0;
                            boolean isForward = false;
                            boolean isBackward = false;
                            final List<View> localList;
                            if (x <= mEdgeSizeForShiftRhythm && x >= 0.0F) {
                                if (firstPosition - 1 >= 0) {
                                    mCurrentItemPosition = 0;
                                    toPosition = firstPosition - 1;
                                    isForward = true;
                                    isBackward = false;

                                }
                            } else if (x > mScreenWidth - mEdgeSizeForShiftRhythm) {
                                if (getSize() >= 1 + (firstPosition + 7)) {
                                    mCurrentItemPosition = 7;
                                    toPosition = firstPosition + 1;
                                    isForward = false;
                                    isBackward = true;
                                }
                            }
                            if (isForward || isBackward) {
                                localList = getVisibleViews(isForward, isBackward);
                                final int finalToPosition = toPosition;
                                mHandler.post(new Runnable() {
                                    public void run() {
                                        makeItems(mCurrentItemPosition, localList);
                                        scrollToPosition(finalToPosition, 200, 0, true);
                                        vibrate(10L);
                                    }
                                });
                            }

                        }

                    }
                };
            }
            schedule(timerTask, 200L, 250L);

        }
    }

    public int getSize() {
        if (mLinearLayout == null) {
            return 0;
        }
        return mLinearLayout.getChildCount();
    }

    public View getItemView(int position) {
        return mLinearLayout.getChildAt(position);
    }


    public Animator scrollToPosition(int position, int duration, int startDelay, boolean isStart) {
        int viewX = (int) getItemView(position).getX();
        return smoothScrollX(viewX, duration, startDelay, isStart);
    }


    public Animator scrollToPosition(int position, int startDelay, boolean isStart) {
        int viewX = (int) getItemView(position).getX();
        return smoothScrollX(viewX, 300, startDelay, isStart);
    }

    private Animator smoothScrollX(int position, int duration, int startDelay, boolean isStart) {
        return AnimatorUtils.moveScrollViewToX(this, position, duration, startDelay, isStart);
    }


    private void updateItemHeightAnimator(View view, int translationY) {
        if (view != null)
            AnimatorUtils.showUpAndDownBounce(view, translationY, 180, true, true);
    }



    public Animator shootDownItem(int viewPosition, boolean isStart) {
        if ((viewPosition >= 0) && (mLinearLayout != null) && (getSize() > viewPosition))
            return shootDownItem(getItemView(viewPosition), isStart);
        return null;
    }

    public Animator shootDownItem(View view, boolean isStart) {
        if (view != null)
            return AnimatorUtils.showUpAndDownBounce(view, mMaxTranslationHeight, 350, isStart, true);
        return null;
    }


    public Animator bounceUpItem(int viewPosition, boolean isStart) {
        if (viewPosition >= 0)
            return bounceUpItem(getItemView(viewPosition), isStart);
        return null;
    }

    public Animator bounceUpItem(View view, boolean isStart) {
        if (view != null)
            return AnimatorUtils.showUpAndDownBounce(view, 10, 350, isStart, true);
        return null;
    }


    private void vibrate(long miss) {
        ((Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(new long[]{0L, miss}, -1);
    }


    public void setRhythmListener(IRhythmItemListener listener) {
        this.mListener = listener;
    }

    public void setScrollRhythmStartDelayTime(int scrollStartDelayTime) {
        this.mScrollStartDelayTime = scrollStartDelayTime;
    }

    public float getRhythmItemWidth() {
        return mItemWidth;
    }


    public void showRhythmAtPosition(int position) {
        if (this.mLastDisplayItemPosition == position)
            return;
        Animator scrollAnimator;
        Animator bounceUpAnimator;
        Animator shootDownAnimator;

        if ((this.mLastDisplayItemPosition < 0) || (mAdapter.getCount() <= 7) || (position <= 3)) {
            scrollAnimator = scrollToPosition(0, mScrollStartDelayTime, false);
        } else if (mAdapter.getCount() - position <= 3) {
            scrollAnimator = scrollToPosition(mAdapter.getCount() - 7, mScrollStartDelayTime, false);
        } else {
            scrollAnimator = scrollToPosition(position - 3, mScrollStartDelayTime, false);
        }
        bounceUpAnimator = bounceUpItem(position, false);
        shootDownAnimator = shootDownItem(mLastDisplayItemPosition, false);
        AnimatorSet animatorSet1 = new AnimatorSet();
        if (bounceUpAnimator != null) {
            animatorSet1.playTogether(bounceUpAnimator);
        }
        if (shootDownAnimator != null) {
            animatorSet1.playTogether(shootDownAnimator);
        }
        AnimatorSet animatorSet2 = new AnimatorSet();
        animatorSet2.playSequentially(new Animator[]{scrollAnimator, animatorSet1});
        animatorSet2.start();
        mLastDisplayItemPosition = position;
    }

}