package com.tarek360.playpausedrawable;

import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.Property;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;

import static android.graphics.Paint.ANTI_ALIAS_FLAG;

/**
 * Created by Tarek360 on 3/4/2015.
 */

public class PlayPauseDrawable extends Drawable {

    private boolean mAnimationMode;
    private long mAnimationDuration;
    private static final Interpolator ANIMATION_INTERPOLATOR = new DecelerateInterpolator();
    private static final String TAG = PlayPauseDrawable.class.getSimpleName();

    private Paint mLinePaint;
    private Paint mBackgroundPaint;

    private float[] mPoints = new float[12];
    private final RectF mBounds = new RectF();


    private ArgbEvaluator mArgbEvaluator = new ArgbEvaluator();

    private float mRotation;
    private float mStrokeWidth;
    private int mPlayColor;
    private int mPauseColor;
    private int shiftY;

    public PlayPauseDrawable() {
        this(14, 0XFFE91E63, 0XFFffffff, 300);
    }

    public PlayPauseDrawable(int strokeWidth, int playColor, int pauseColor, long animationDuration) {
        mStrokeWidth = strokeWidth;
        mPlayColor = playColor;
        mPauseColor = pauseColor;
        mAnimationDuration = animationDuration;
        initPaints();
    }

    private void initPaints() {
        mLinePaint = new Paint(ANTI_ALIAS_FLAG);
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setColor(mPauseColor);
        mLinePaint.setStrokeWidth(mStrokeWidth);
        mLinePaint.setStrokeCap(Paint.Cap.ROUND);

        mBackgroundPaint = new Paint(ANTI_ALIAS_FLAG);
        mLinePaint.setAntiAlias(true);
        mBackgroundPaint.setStyle(Paint.Style.FILL);
        mBackgroundPaint.setColor(mPlayColor);
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);

        int padding = bounds.centerX()/2;
        shiftY = bounds.centerY()/8;
        mBounds.left = bounds.left + padding;
        mBounds.right = bounds.right - padding;
        mBounds.top = bounds.top + padding;
        mBounds.bottom = bounds.bottom - padding;

        setupPauseMode();
    }

    private void setupPauseMode(){

        mPoints[0] =  mBounds.left + shiftY;
        mPoints[1] =  mBounds.top;

        mPoints[2] =  mBounds.left + shiftY;
        mPoints[3] =  mBounds.bottom;

        mPoints[4] =  mBounds.right - shiftY;
        mPoints[5] =  mBounds.top;

        mPoints[6] =  mBounds.right - shiftY;
        mPoints[7] =  mBounds.bottom;

        mPoints[8] =  mBounds.left + shiftY;
        mPoints[9] =  mBounds.centerY();

        mPoints[10] = mBounds.left + shiftY;
        mPoints[11] = mBounds.centerY();
    }

    @Override
    public void draw(Canvas canvas) {

        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBackgroundPaint);
        Picture picture = new Picture() ;
        picture.draw(canvas);
        canvas.save();
        canvas.rotate(180 * mRotation, (x(0) + x(1))/2, (y(0) + y(1))/2);
        canvas.drawLine(x(0), y(0), x(1), y(1), mLinePaint);
        canvas.restore();

        canvas.save();
        canvas.rotate(180 * mRotation, (x(2) + x(3)) / 2, (y(2) + y(3)) / 2);
        canvas.drawLine(x(2), y(2), x(3), y(3), mLinePaint);
        canvas.restore();

        canvas.save();
        canvas.rotate(180 * mRotation, (x(4) + x(5)) / 2, (y(4) + y(5)) / 2);
        canvas.drawLine(x(4), y(4), x(5), y(5), mLinePaint);
        canvas.restore();

    }

    public void toggle() {
        if(mAnimationMode) {
            animatePause();
        } else {
            animatePlay();
        }
        mAnimationMode = !mAnimationMode;
    }



    public void animatePause() {
        AnimatorSet set = new AnimatorSet();
        set.playTogether(
                ObjectAnimator.ofFloat(this, mPropertyPointAX, mBounds.left + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointAY, mBounds.top),

                ObjectAnimator.ofFloat(this, mPropertyPointBX, mBounds.left + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointBY, mBounds.bottom),

                ObjectAnimator.ofFloat(this, mPropertyPointCX, mBounds.right - shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointCY, mBounds.top),

                ObjectAnimator.ofFloat(this, mPropertyPointDX, mBounds.right - shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointDY, mBounds.bottom),

                ObjectAnimator.ofFloat(this, mPropertyPointEX, mBounds.left + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointEY, mBounds.centerY()),

                ObjectAnimator.ofFloat(this, mPropertyPointFX, mBounds.left + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointFY, mBounds.centerY()),

                ObjectAnimator.ofFloat(this, mRotationProperty, 0f, 1f),
                ObjectAnimator.ofObject(this, mLineColorProperty, mArgbEvaluator, mPauseColor),
                ObjectAnimator.ofObject(this, mBackgroundColorProperty, mArgbEvaluator, mPlayColor),

                ObjectAnimator.ofFloat(this, mStrokeWidthProperty, mStrokeWidth)


        );
        set.setDuration(mAnimationDuration);
        set.setInterpolator(ANIMATION_INTERPOLATOR);
        set.start();
    }


    public void animatePlay() {
        AnimatorSet set = new AnimatorSet();


        set.playTogether(
                ObjectAnimator.ofFloat(this, mPropertyPointAX, mBounds.left + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointAY, mBounds.top),

                ObjectAnimator.ofFloat(this, mPropertyPointBX, mBounds.right + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointBY, mBounds.centerY()),

                ObjectAnimator.ofFloat(this, mPropertyPointCX, mBounds.right + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointCY, mBounds.centerY()),

                ObjectAnimator.ofFloat(this, mPropertyPointDX, mBounds.left + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointDY, mBounds.bottom),


                ObjectAnimator.ofFloat(this, mPropertyPointEX, mBounds.left + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointEY, mBounds.bottom),

                ObjectAnimator.ofFloat(this, mPropertyPointFX, mBounds.left + shiftY),
                ObjectAnimator.ofFloat(this, mPropertyPointFY, mBounds.top),

                ObjectAnimator.ofFloat(this, mRotationProperty, 0f, 1f),
                ObjectAnimator.ofObject(this, mLineColorProperty, mArgbEvaluator, mPlayColor),
                ObjectAnimator.ofObject(this, mBackgroundColorProperty, mArgbEvaluator, mPauseColor),

                ObjectAnimator.ofFloat(this, mStrokeWidthProperty, mStrokeWidth * 5/7)


        );
        set.setDuration(mAnimationDuration);
        set.setInterpolator(ANIMATION_INTERPOLATOR);
        set.start();
    }


    private float x(int pointIndex) {
        return mPoints[xPosition(pointIndex)];
    }

    private float y(int pointIndex) {
        return mPoints[yPosition(pointIndex)];
    }

    private int xPosition(int pointIndex) {
        return pointIndex*2;
    }

    private int yPosition(int pointIndex) {
        return xPosition(pointIndex) + 1;
    }



    @Override
    public void setAlpha(int alpha) {}

    @Override
    public void setColorFilter(ColorFilter cf) {}

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    private Property<PlayPauseDrawable, Integer> mBackgroundColorProperty = new Property<PlayPauseDrawable, Integer>(Integer.class, "bg_color") {
        @Override
        public Integer get(PlayPauseDrawable object) {
            return object.mBackgroundPaint.getColor();
        }

        @Override
        public void set(PlayPauseDrawable object, Integer value) {
            object.mBackgroundPaint.setColor(value);
        }
    };

    private Property<PlayPauseDrawable, Integer> mLineColorProperty = new Property<PlayPauseDrawable, Integer>(Integer.class, "line_color") {
        @Override
        public Integer get(PlayPauseDrawable object) {
            return object.mLinePaint.getColor();
        }

        @Override
        public void set(PlayPauseDrawable object, Integer value) {
            object.mLinePaint.setColor(value);
        }
    };

    private Property<PlayPauseDrawable, Float> mRotationProperty = new Property<PlayPauseDrawable, Float>(Float.class, "rotation") {
        @Override
        public Float get(PlayPauseDrawable object) {
            return object.mRotation;
        }

        @Override
        public void set(PlayPauseDrawable object, Float value) {
            object.mRotation = value;
        }
    };

    private PointProperty mPropertyPointAX = new XPointProperty(0);
    private PointProperty mPropertyPointAY = new YPointProperty(0);
    private PointProperty mPropertyPointBX = new XPointProperty(1);
    private PointProperty mPropertyPointBY = new YPointProperty(1);
    private PointProperty mPropertyPointCX = new XPointProperty(2);
    private PointProperty mPropertyPointCY = new YPointProperty(2);
    private PointProperty mPropertyPointDX = new XPointProperty(3);
    private PointProperty mPropertyPointDY = new YPointProperty(3);
    private PointProperty mPropertyPointEX = new XPointProperty(4);
    private PointProperty mPropertyPointEY = new YPointProperty(4);
    private PointProperty mPropertyPointFX = new XPointProperty(5);
    private PointProperty mPropertyPointFY = new YPointProperty(5);

    private abstract class PointProperty extends Property<PlayPauseDrawable, Float> {

        protected int mPointIndex;

        private PointProperty(int pointIndex) {
            super(Float.class, "point_" + pointIndex);
            mPointIndex = pointIndex;
        }
    }

    private StrokeWidthProperty mStrokeWidthProperty = new StrokeWidthProperty();
    private class StrokeWidthProperty extends Property<PlayPauseDrawable, Float> {

        public StrokeWidthProperty() {
            super(Float.class, "StrokeWidth");
        }

        @Override
        public Float get(PlayPauseDrawable object) {
            return object.mStrokeWidth;
        }

        @Override
        public void set(PlayPauseDrawable object, Float value) {
            object.mLinePaint.setStrokeWidth(value);
            invalidateSelf();
        }
    }

    private class XPointProperty extends PointProperty {

        private XPointProperty(int pointIndex) {
            super(pointIndex);
        }

        @Override
        public Float get(PlayPauseDrawable object) {
            return object.x(mPointIndex);
        }

        @Override
        public void set(PlayPauseDrawable object, Float value) {
            object.mPoints[object.xPosition(mPointIndex)] = value;
            invalidateSelf();
        }
    }

    private class YPointProperty extends PointProperty {

        private YPointProperty(int pointIndex) {
            super(pointIndex);
        }

        @Override
        public Float get(PlayPauseDrawable object) {
            return object.y(mPointIndex);
        }

        @Override
        public void set(PlayPauseDrawable object, Float value) {
            object.mPoints[object.yPosition(mPointIndex)] = value;
            invalidateSelf();
        }
    }

}