package de.szimnau; import de.szimnau.tools.FormatTools; import java.math.BigDecimal; import java.time.LocalTime; import java.time.temporal.ChronoUnit; import java.util.concurrent.TimeUnit; import static de.szimnau.tools.CommonTools.print; import static de.szimnau.tools.CommonTools.println; public abstract class AbstractLoadingBar { private final LocalTime startTime; private LocalTime endTime; private long totalMinutes; private BigDecimal totalMinutesBD; protected AbstractLoadingBar(LocalTime startTime) { this.startTime = startTime; } protected AbstractLoadingBar(LocalTime startTime, LocalTime endTime) { this.startTime = startTime; setEndTime(endTime); } protected AbstractLoadingBar(LocalTime startTime, long totalMinutes) { this.startTime = startTime; setTotalMinutes(totalMinutes); } public LocalTime getStartTime() { return startTime; } public LocalTime getEndTime() { return endTime; } protected final void setEndTime(LocalTime endTime) { this.endTime = endTime; this.totalMinutes = startTime.until(endTime, ChronoUnit.MINUTES); this.totalMinutesBD = BigDecimal.valueOf(totalMinutes); extraInitEndTimeTotalMinutes(); } protected void extraInitEndTimeTotalMinutes() {} protected long getTotalMinutes() { return totalMinutes; } protected final void setTotalMinutes(long totalMinutes) { this.totalMinutes = totalMinutes; this.totalMinutesBD = BigDecimal.valueOf(totalMinutes); this.endTime = startTime.plusMinutes(totalMinutes); extraInitEndTimeTotalMinutes(); } protected BigDecimal getTotalMinutesBD() { return totalMinutesBD; } protected long getPassedMinutes() { return getPassedMinutes(false); } protected long getPassedMinutes(boolean passedMinutesZero) { return passedMinutesZero ? 0 : startTime.until(LocalTime.now().truncatedTo(ChronoUnit.MINUTES), ChronoUnit.MINUTES); } public void showLoadingBar() { showLoadingBar(false, false, 0); } public void showLoadingBar(boolean debug, boolean passedMinutesZero) { showLoadingBar(debug, passedMinutesZero, 100L); } public void showLoadingBarDebug() { showLoadingBar(true, true, 100L); } public void showLoadingBarDebug(long millisWaiting) { showLoadingBar(true, true, millisWaiting); } public void showLoadingBarDebug(boolean passedMinutesZero) { showLoadingBar(true, passedMinutesZero, 100L); } public void showLoadingBarDebug(boolean passedMinutesZero, long millisWaiting) { showLoadingBar(true, passedMinutesZero, millisWaiting); } private void showLoadingBar(boolean debug, boolean passedMinutesZero, long millisWaiting) { long passedMinutes = getPassedMinutes(debug && passedMinutesZero); if (passedMinutes > totalMinutes) { passedMinutes = totalMinutes; } else if (passedMinutes < 0) { var now = LocalTime.now().truncatedTo(ChronoUnit.SECONDS); println("!ACHTUNG! Startzeit \"" + startTime + ":00\" liegt in der Zukunft von jetzt an (" + now + ") gesehen."); } println(FormatTools.minutesToTimeString(totalMinutes) + " gesamt; Endzeit: " + FormatTools.TIME_FORMATTER.format(endTime)); while (passedMinutes < totalMinutes) { print(fillLoadingBar(passedMinutes, true)); waitUntilNextMinute(debug, millisWaiting); passedMinutes++; } println(fillLoadingBar(passedMinutes, false)); } protected abstract String fillLoadingBar(long passedMinutes, boolean progressive); protected void waitUntilNextMinute() { waitUntilNextMinute(false, 0L); } protected void waitUntilNextMinuteDebug() { waitUntilNextMinute(true, 100L); } protected void waitUntilNextMinuteDebug(long millisWaiting) { waitUntilNextMinute(true, millisWaiting); } private void waitUntilNextMinute(boolean debug, long millisWaiting) { try { if (debug) { TimeUnit.MILLISECONDS.sleep(millisWaiting); return; } var now = LocalTime.now(); var oneMinuteLater = now.plusMinutes(1).truncatedTo(ChronoUnit.MINUTES); /* We wait whole seconds to not make it overly complicated. That results in cut milliseconds: if we would have to wait 1 second and 526 milliseconds, we wait only 1 second. So, adjust for ignored milliseconds, add +1 second as it is better to switch between 00 and 01 as between 59 and 00 */ TimeUnit.SECONDS.sleep(now.until(oneMinuteLater, ChronoUnit.SECONDS) + 1); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException(ie); } } }