/*
 * Copyright © 2017 jjYBdx4IL (https://github.com/jjYBdx4IL)
 *
 * 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 com.github.jjYBdx4IL.utils.text;

import com.github.jjYBdx4IL.utils.time.TimeUtils;

public class Eta<T extends Number> {

    public static final long DEFAULT_PERIODMS = 10000L;
    
    private final T endValue;
    private final T startValue;
    private final long startMs;
    private final long periodMs;

    /**
     * Create an ETA instance.
     * 
     * @param startValue
     *            where progress starts
     * @param endValue
     *            where progress will end
     * @param periodMs
     *            defines how often {@link #toStringPeriodical(Number)} will
     *            return a non-null value
     */
    public Eta(T startValue, T endValue, long periodMs) {
        this.startValue = startValue;
        this.endValue = endValue;
        this.periodMs = periodMs;
        this.startMs = System.currentTimeMillis();
    }

    public Eta(T startValue, T endValue) {
        this(startValue, endValue, DEFAULT_PERIODMS);
    }

    public Eta(T endValue) {
        this(null, endValue, DEFAULT_PERIODMS);
    }

    /**
     * Convert current progress indicated by currentValue to a string describing
     * progress and ETA.
     * 
     * @param currentValue
     *            the current progress
     * @return a string with progress details incl. ETA
     */
    public String toString(T currentValue) {
        final long elapsedMs = System.currentTimeMillis() - startMs;
        final float processed = (currentValue.floatValue() - (startValue != null ? startValue.floatValue() : 0f));
        final float speedMs = processed / (float) elapsedMs;
        return String.format("%s in %s (%.2f/s, ETA: %s)",
            processed,
            TimeUtils.millisToDuration(elapsedMs),
            speedMs * 1e3f,
            processed == 0f
                ? "NaN"
                : TimeUtils.millisToDuration((long) ((endValue.floatValue() - currentValue.floatValue()) / speedMs))
        );
    }

    private long lastToStringPeriodical = 0;

    /**
     * Use this method to avoid spammning eta messages. Returns non-null only
     * every periodMs.
     * 
     * @param currentValue
     *            the current progress
     * @return the result of {@link #toString(Number)}, or null if called sooned
     *         than periodMs after the last call.
     */
    public String toStringPeriodical(T currentValue) {
        long now = System.currentTimeMillis();
        if (now - lastToStringPeriodical < periodMs) {
            return null;
        }
        lastToStringPeriodical = now;
        return toString(currentValue);
    }

}

@@ -806,20 +806,16 @@
 10000L;%0A
-    
 %0A    pri
@@ -1981,285 +1981,1145 @@
     
-final long elapsedMs = System.currentTimeMillis() - startMs;%0A        final float processed = (currentValue.floatValue() - (startValue != null ? startValue.floatValue() : 0f));%0A        final float speedMs = processed / (float) elapsedMs;%0A        return String.format(%22%25s in %25s (
+return toString(currentValue, System.currentTimeMillis());%0A    %7D%0A%0A    private String toString(T currentValue, final long now) %7B%0A        final long elapsedMs = now - startMs;%0A        final float processed = (currentValue.floatValue() - (startValue != null ? startValue.floatValue() : 0f));%0A        final float progressPercent = 100f * processed%0A            / (endValue.floatValue() - (startValue != null ? startValue.floatValue() : 0f));%0A        final float speedMs = processed / (float) elapsedMs;%0A        float currentSpeedMs = Float.NaN;%0A        String currentEta = %22NaN%22;%0A        if (prevValue != null) %7B%0A            final long deltaElapsedMs = now - lastToStringPeriodical;%0A            final float deltaProcessed = (currentValue.floatValue() - prevValue.floatValue());%0A            currentSpeedMs = deltaProcessed / deltaElapsedMs;%0A            if (deltaProcessed %3E 0f) %7B%0A                currentEta = TimeUtils%0A                    .millisToDuration((long) ((endValue.floatValue() - currentValue.floatValue()) / currentSpeedMs));%0A            %7D%0A        %7D%0A        return String.format(%22%25s (%25.2f%25%25) in %25s (total: %25.2f/s, ETA: %25s; current: 
 %25.2f
@@ -3156,16 +3156,45 @@
 cessed,%0A
+            progressPercent,%0A
         
@@ -3432,16 +3432,75 @@
 peedMs))
+,%0A            currentSpeedMs * 1e3f,%0A            currentEta
 %0A       
@@ -3554,16 +3554,48 @@
 cal = 0;
+%0A    private T prevValue = null;
 %0A%0A    /*
@@ -4094,32 +4094,85 @@
 null;%0A        %7D%0A
+        String result = toString(currentValue, now);%0A
         lastToSt
@@ -4205,37 +4205,55 @@
     
+p
 re
-turn toString(currentValue)
+vValue = currentValue;%0A        return result
 ;%0A  

add current performance/eta to Eta