// Path: src/com/ciphertechsolutions/io/applicationLogic/Utils.java
// public class Utils {
// 
//     /**
//      * Converts the given duration to a string in the format of "x days hh:mm:ss", "hh:mm:ss", or "x seconds",
//      * depending on the amount of time in the duration.
//      * @param duration The duration to convert to a string.
//      * @return The duration as a string.
//      */
//     public static String getPrettyTime(Duration duration) {
//         StringBuilder timeString = new StringBuilder();
//         long seconds = duration.getSeconds();
//         addDays(duration, timeString);
//         addHours(duration, timeString, seconds);
//         addMinutesAndSeconds(duration, timeString, seconds);
//         return timeString.toString();
//     }
// 
//     private static void addMinutesAndSeconds(Duration duration, StringBuilder timeString, long seconds) {
//         if (duration.toMinutes() >= 1) {
//             int remainingMinutes = (int) ((seconds % 3600) / 60);
//             padIfNeeded(timeString, remainingMinutes);
//             timeString.append(":");
//             int remainingSeconds = (int) (seconds % 60);
//             padIfNeeded(timeString, remainingSeconds);
//         }
//         else {
//             timeString.append(seconds % 60);
//             timeString.append(" seconds.");
//         }
//     }
// 
//     private static void addHours(Duration duration, StringBuilder timeString, long seconds) {
//         if (duration.toHours() >= 1) {
//             timeString.append((seconds % 86400)/ 3600);
//             timeString.append(":");
//         }
//     }
// 
//     private static void addDays(Duration duration, StringBuilder timeString) {
//         if (duration.toDays() >= 1) {
//             timeString.append(duration.toDays());
//             timeString.append(" days ");
//         }
//     }
// 
//     private static void padIfNeeded(StringBuilder timeString, int remaining) {
//         if (remaining < 10) {
//             timeString.append("0");
//         }
//         timeString.append(remaining);
//     }
// }


import java.net.URL;
import java.time.Duration;
import java.util.List;
import java.util.ResourceBundle;
import com.ciphertechsolutions.io.applicationLogic.Utils;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.collections.ListChangeListener;
import javafx.collections.WeakListChangeListener;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;
        private int calls;
        private double lastAverage;
        private final long max;
        private final long startTime;

        protected ProgressStatus() {
            calls = 0;
            lastAverage = 0;
            max = workflowController.getMaxOutputCount();
            startTime = System.nanoTime();
        }

        protected void onChange(long newCount) {
            double percentComplete = newCount / (double) max;
            calls++;
            if (calls % 250 == 0) {
                estimateRemainingTime(percentComplete);
            }
            if (newCount == max) {
                timeEstimateLabel.setText("Complete");
                setReturnVisible();
            }
            else if (lastAverage > 0) {
                timeEstimateLabel.setText(Math.round((1 - percentComplete) * 100) + "% remaining: " + getTime());
                timeEstimateLabel.setVisible(true);
            }
            progressBar.setProgress(percentComplete);
        }

        protected String getTime() {
// Path: src/com/ciphertechsolutions/io/applicationLogic/Utils.java
// public class Utils {
// 
//     /**
//      * Converts the given duration to a string in the format of "x days hh:mm:ss", "hh:mm:ss", or "x seconds",
//      * depending on the amount of time in the duration.
//      * @param duration The duration to convert to a string.
//      * @return The duration as a string.
//      */
//     public static String getPrettyTime(Duration duration) {
//         StringBuilder timeString = new StringBuilder();
//         long seconds = duration.getSeconds();
//         addDays(duration, timeString);
//         addHours(duration, timeString, seconds);
//         addMinutesAndSeconds(duration, timeString, seconds);
//         return timeString.toString();
//     }
// 
//     private static void addMinutesAndSeconds(Duration duration, StringBuilder timeString, long seconds) {
//         if (duration.toMinutes() >= 1) {
//             int remainingMinutes = (int) ((seconds % 3600) / 60);
//             padIfNeeded(timeString, remainingMinutes);
//             timeString.append(":");
//             int remainingSeconds = (int) (seconds % 60);
//             padIfNeeded(timeString, remainingSeconds);
//         }
//         else {
//             timeString.append(seconds % 60);
//             timeString.append(" seconds.");
//         }
//     }
// 
//     private static void addHours(Duration duration, StringBuilder timeString, long seconds) {
//         if (duration.toHours() >= 1) {
//             timeString.append((seconds % 86400)/ 3600);
//             timeString.append(":");
//         }
//     }
// 
//     private static void addDays(Duration duration, StringBuilder timeString) {
//         if (duration.toDays() >= 1) {
//             timeString.append(duration.toDays());
//             timeString.append(" days ");
//         }
//     }
// 
//     private static void padIfNeeded(StringBuilder timeString, int remaining) {
//         if (remaining < 10) {
//             timeString.append("0");
//         }
//         timeString.append(remaining);
//     }
// }


// Path: src/com/ciphertechsolutions/io/ui/ImagingController.java
import java.net.URL;
import java.time.Duration;
import java.util.List;
import java.util.ResourceBundle;
import com.ciphertechsolutions.io.applicationLogic.Utils;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.collections.ListChangeListener;
import javafx.collections.WeakListChangeListener;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;

        private int calls;
        private double lastAverage;
        private final long max;
        private final long startTime;

        protected ProgressStatus() {
            calls = 0;
            lastAverage = 0;
            max = workflowController.getMaxOutputCount();
            startTime = System.nanoTime();
        }

        protected void onChange(long newCount) {
            double percentComplete = newCount / (double) max;
            calls++;
            if (calls % 250 == 0) {
                estimateRemainingTime(percentComplete);
            }
            if (newCount == max) {
                timeEstimateLabel.setText("Complete");
                setReturnVisible();
            }
            else if (lastAverage > 0) {
                timeEstimateLabel.setText(Math.round((1 - percentComplete) * 100) + "% remaining: " + getTime());
                timeEstimateLabel.setVisible(true);
            }
            progressBar.setProgress(percentComplete);
        }

        protected String getTime() {
            return Utils.getPrettyTime(Duration.ofSeconds(Math.max(Math.round(lastAverage - (System.nanoTime() - startTime) / 1000000000), 0)));