package net.squanchy.support.graphics;

import android.animation.Animator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.support.annotation.ColorInt;
import android.support.annotation.IntRange;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.view.animation.Interpolator;

import me.eugeniomarletti.renderthread.CanvasProperty;
import me.eugeniomarletti.renderthread.RenderThread;

public class CircularRevealDrawable extends ColorDrawable {

    private final Paint animationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private final SimpleAnimationEndListener animationEndListener = new SimpleAnimationEndListener() {
        @Override
        public void onAnimationEnd(Animator animation) {
            setColor(targetColor);
        }
    };
    
    private final Interpolator interpolator = new FastOutLinearInInterpolator();

    private Animator radiusAnimator;

    private CanvasProperty<Float> centerXProperty;
    private CanvasProperty<Float> centerYProperty;
    private CanvasProperty<Float> radiusProperty;
    private CanvasProperty<Paint> paintProperty;

    private boolean startAnimationOnNextDraw;

    private int durationMillis;

    private float hotspotX;
    private float hotspotY;
    private int width;
    private int height;

    @ColorInt
    private int targetColor;

    public static CircularRevealDrawable from(ColorDrawable colorDrawable) {
        CircularRevealDrawable revealDrawable = new CircularRevealDrawable();
        revealDrawable.setColor(colorDrawable.getColor());
        return revealDrawable;
    }

    public void animateToColor(@ColorInt int color, @IntRange(from = 0) int durationMillis) {
        targetColor = color;
        startAnimationOnNextDraw = true;
        this.durationMillis = durationMillis;
        invalidateSelf();
    }

    @Override
    public void draw(Canvas canvas) {
        // 1. Let the "main" color be drawn
        super.draw(canvas);

        // 2. If we just got a reveal start request, go with it
        if (startAnimationOnNextDraw) {
            initializeAnimation(canvas);
            radiusAnimator.start();
            startAnimationOnNextDraw = false;
        }

        if (centerXProperty != null && centerYProperty != null && radiusProperty != null && paintProperty != null) {
            RenderThread.drawCircle(canvas, centerXProperty, centerYProperty, radiusProperty, paintProperty);
        }
    }

    private void initializeAnimation(Canvas canvas) {
        float initialRadius = 0f;
        float targetRadius = calculateTargetRadius();
        animationPaint.setColor(targetColor);

        centerXProperty = RenderThread.createCanvasProperty(canvas, hotspotX);
        centerYProperty = RenderThread.createCanvasProperty(canvas, hotspotY);
        radiusProperty = RenderThread.createCanvasProperty(canvas, initialRadius);
        paintProperty = RenderThread.createCanvasProperty(canvas, animationPaint);

        if (radiusAnimator != null) {
            radiusAnimator.cancel();
        }
        radiusAnimator = RenderThread.createFloatAnimator(this, canvas, radiusProperty, targetRadius);
        radiusAnimator.setInterpolator(interpolator);
        radiusAnimator.setDuration(durationMillis);
        radiusAnimator.addListener(animationEndListener);
    }

    private float calculateTargetRadius() {
        float maxXDistance = Math.max(hotspotX, width - hotspotX);
        float maxYDistance = Math.max(hotspotY, height - hotspotY);
        return (float) Math.sqrt(maxXDistance * maxXDistance + maxYDistance * maxYDistance);
    }

    @Override
    public void setHotspot(float x, float y) {
        super.setHotspot(x, y);
        hotspotX = x;
        hotspotY = y;
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        width = bounds.width();
        height = bounds.height();
    }

    private abstract static class SimpleAnimationEndListener implements Animator.AnimatorListener {

        @Override
        public void onAnimationStart(Animator animation) {
            // Don't care
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            // Don't care
        }

        @Override
        public void onAnimationRepeat(Animator animation) {
            // Don't care
        }
    }
}

@@ -662,243 +662,8 @@
 );%0A%0A
-    private final SimpleAnimationEndListener animationEndListener = new SimpleAnimationEndListener() %7B%0A        @Override%0A        public void onAnimationEnd(Animator animation) %7B%0A            setColor(targetColor);%0A        %7D%0A    %7D;%0A    %0A
     
@@ -1043,30 +1043,30 @@
 ate int 
-d
+revealD
 uration
-Millis
 ;%0A%0A    p
@@ -1164,16 +1164,67 @@
 eight;%0A%0A
+    @ColorInt%0A    private int pendingTargetColor;%0A%0A
     @Col
@@ -1613,17 +1613,65 @@
         
-t
+revealDuration = durationMillis;%0A        pendingT
 argetCol
@@ -1735,69 +1735,28 @@
     
-this.durationMillis = durationMillis;%0A        invalidateSelf(
+setColor(targetColor
 );%0A 
@@ -1831,63 +1831,68 @@
  1. 
-Let
+Draw
  the %22
-main%22 color be drawn%0A        super.draw(canvas
+current%22 color%0A        canvas.drawColor(getColor()
 );%0A%0A
@@ -2033,16 +2033,36 @@
 n(canvas
+, pendingTargetColor
 );%0A     
@@ -2161,113 +2161,118 @@
     
-if (centerXProperty != null && centerYProperty != null && radiusProperty != null && paintProperty != null
+// 3. This draws the reveal, if one is needed%0A        if (radiusAnimator != null && radiusAnimator.isRunning()
 ) %7B%0A
@@ -2440,32 +2440,56 @@
 on(Canvas canvas
+, int pendingTargetColor
 ) %7B%0A        floa
@@ -2588,33 +2588,40 @@
 nPaint.setColor(
-t
+pendingT
 argetColor);%0A%0A  
@@ -2977,16 +2977,46 @@
  != null
+ && radiusAnimator.isRunning()
 ) %7B%0A    
@@ -3044,24 +3044,59 @@
 r.cancel();%0A
+            setColor(targetColor);%0A
         %7D%0A  
@@ -3285,30 +3285,30 @@
 uration(
-d
+revealD
 uration
-Millis
 );%0A     
@@ -3314,56 +3314,40 @@
     
-radiusAnimator.addListener(animationEndListener)
+targetColor = pendingTargetColor
 ;%0A  
@@ -3950,458 +3950,7 @@
    %7D
-%0A%0A    private abstract static class SimpleAnimationEndListener implements Animator.AnimatorListener %7B%0A%0A        @Override%0A        public void onAnimationStart(Animator animation) %7B%0A            // Don't care%0A        %7D%0A%0A        @Override%0A        public void onAnimationCancel(Animator animation) %7B%0A            // Don't care%0A        %7D%0A%0A        @Override%0A        public void onAnimationRepeat(Animator animation) %7B%0A            // Don't care%0A        %7D%0A    %7D
 %0A%7D%0A

Fix starting a reveal while one is in-flight