/*
 * Copyright (c) 2016 Jacksgong(blog.dreamtobe.cn).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.dreamtobe.percentsmoothhandler;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import junit.framework.Assert;

import java.lang.ref.WeakReference;

/**
 * Created by Jacksgong on 2/2/16.
 * <p/>
 * handle the case of the internal of the percent between the current and the last is
 * too large to smooth for the target
 *
 * @see ISmoothTarget
 */
public class SmoothHandler extends Handler {
    final WeakReference<ISmoothTarget> targetWeakReference;

    private float aimPercent;
    private float minInternalPercent = 0.03f; // 3%
    private float smoothInternalPercent = 0.01f; // 1%
    private int smoothIncreaseDelayMillis = 1; // 1ms

    public float getMinInternalPercent() {
        return minInternalPercent;
    }

    /**
     * if the provider percent more than minInternalPercent, it will be split to the several smoothInternalPercent
     *
     * @param minInternalPercent the min internal of the percent, default 0.03
     * @see #setSmoothInternalPercent(float)
     */
    public void setMinInternalPercent(float minInternalPercent) {
        Assert.assertTrue("the min internal percent must more than 0", minInternalPercent > 0);
        Assert.assertTrue("the min internal percent must less than 1", minInternalPercent <= 1);
        Assert.assertTrue("the min internal percent must more than the smooth internal percent",
                minInternalPercent > this.smoothInternalPercent);
        this.minInternalPercent = minInternalPercent;
    }

    public float getSmoothInternalPercent() {
        return smoothInternalPercent;
    }

    /**
     * if the provider percent more than minInternalPercent, it will be split to the several smoothInternalPercent
     *
     * @param smoothInternalPercent the internal of the percent will provide the smooth effect, default 0.01
     * @see #setMinInternalPercent(float)
     */
    public void setSmoothInternalPercent(float smoothInternalPercent) {
        Assert.assertTrue("the smooth internal percent must more than 0", minInternalPercent > 0);
        Assert.assertTrue("the smooth internal percent must less than 0.5", minInternalPercent < 0.5);
        Assert.assertTrue("the smooth internal percent must less than the min internal percent",
                smoothInternalPercent < this.minInternalPercent);
        this.smoothInternalPercent = smoothInternalPercent;
    }

    public int getSmoothIncreaseDelayMillis() {
        return smoothIncreaseDelayMillis;
    }

    /**
     * @param smoothIncreaseDelayMillis the delay of increase duration, default 1ms
     */
    public void setSmoothIncreaseDelayMillis(int smoothIncreaseDelayMillis) {
        Assert.assertTrue("the delay of increase duration must more than 0", minInternalPercent > 0);
        this.smoothIncreaseDelayMillis = smoothIncreaseDelayMillis;
    }

    /**
     * generally use for the progress widget
     *
     * @param targetWeakReference the weak reference of the smooth target
     */
    public SmoothHandler(WeakReference<ISmoothTarget> targetWeakReference) {
        super(Looper.getMainLooper());
        this.targetWeakReference = targetWeakReference;
    }

    public SmoothHandler(WeakReference<ISmoothTarget> targetWeakReference, Looper looper) {
        super(looper);
        this.targetWeakReference = targetWeakReference;
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if (this.targetWeakReference == null || this.targetWeakReference.get() == null) {
            return;
        }

        final ISmoothTarget target = targetWeakReference.get();

        if (target.getPercent() >= this.aimPercent || target.getPercent() >= 1 ||
                (target.getPercent() == 0 && this.aimPercent == 0)) {
            clear();
            return;
        }

        target.setPercent(target.getPercent() + smoothInternalPercent);
        sendEmptyMessageDelayed(0, smoothIncreaseDelayMillis);
    }

    private void clear() {
        removeMessages(0);
    }

    /**
     * if the provider percent(the aim percent) more than minInternalPercent, it will be split to the several smoothInternalPercent
     *
     * @param percent the aim percent
     */
    public void loopSmooth(float percent) {
        if (this.targetWeakReference == null || this.targetWeakReference.get() == null) {
            return;
        }

        final ISmoothTarget target = targetWeakReference.get();

        target.setPercent(this.aimPercent);
        clear();

        this.aimPercent = percent;

        if (this.aimPercent - target.getPercent() > minInternalPercent) {
            sendEmptyMessage(0);
        } else {
            target.setPercent(percent);
        }

    }
}
@@ -4451,39 +4451,32 @@
      %7D%0A%0A        
-target.
 setPercent(targe
@@ -4469,16 +4469,23 @@
 tPercent
+2Target
 (target.
@@ -4632,25 +4632,795 @@
     
-removeMessages(0)
+this.ignoreCommit = false;%0A        removeMessages(0);%0A    %7D%0A%0A    private boolean ignoreCommit = false;%0A%0A    /**%0A     * Must be invoked by some method which will change the percent for monitor all changes%0A     * about percent.%0A     *%0A     * @param percent the percent will be effect by the target.%0A     */%0A    public void commitPercent(float percent) %7B%0A        if (this.ignoreCommit) %7B%0A            this.ignoreCommit = false;%0A            return;%0A        %7D%0A        this.aimPercent = percent;%0A    %7D%0A%0A    private void setPercent2Target(final float percent) %7B%0A        if (targetWeakReference == null %7C%7C targetWeakReference.get() == null) %7B%0A            return;%0A        %7D%0A%0A        this.ignoreCommit = true;%0A        targetWeakReference.get().setPercent(percent);%0A        this.ignoreCommit = false
 ;%0A  
@@ -5847,39 +5847,32 @@
 get();%0A%0A        
-target.
 setPercent(this.
@@ -5865,16 +5865,23 @@
 tPercent
+2Target
 (this.ai
@@ -6081,23 +6081,16 @@
         
-target.
 setPerce
@@ -6083,32 +6083,39 @@
       setPercent
+2Target
 (percent);%0A     

add 'commitPercent(percent:float):void' to handle the percent is changed by somewhere SmoothHandler does not know