package de.szimnau.tools; import de.szimnau.LoadingBar; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.time.LocalTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; import static de.szimnau.tools.CommonTools.print; import static de.szimnau.tools.CommonTools.println; public class LoadingBarCliTools { private static final Pattern OFFSET_PATTERN = Pattern.compile("[+-]\\d+"); private static final Pattern LUNCH_DURATION_PATTERN = Pattern.compile("\\d+"); private enum DaySection { MITTAG("-m", "Mittag"), ZAPFENSTREICH("-z", "Zapfenstreich"); private final String param; private final String description; DaySection(String param, String description) { this.param = param; this.description = description; } public static DaySection byParam(String param) { return Arrays.stream(DaySection.values()).filter((DaySection section) -> section.getParam().equals(param)).findFirst().orElse(null); } public String getParam() { return param; } public String getDescription() { return description; } } private LoadingBarCliTools() {} public static void askParametersAndRun(Function constructor) throws IOException { var br = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); print("Ankunftszeit: "); var startTime = LocalTime.parse(br.readLine(), FormatTools.TIME_FORMATTER).truncatedTo(ChronoUnit.MINUTES); LoadingBar lb = constructor.apply(startTime); boolean debug = false; boolean passedMinutesZero = false; if (lb.hasMittagspauseArrived(debug && passedMinutesZero)) { handleMittagspause(br, lb); lb.showLoadingBar(debug, passedMinutesZero); } handleZapfenstreich(br, lb); lb.showLoadingBar(debug, passedMinutesZero); } private static void handleMittagspause(BufferedReader br, LoadingBar lb) throws IOException { print("Mittagspause verschieben um (optional): "); String mittagspauseOffsetRaw = br.readLine(); if (mittagspauseOffsetRaw != null && !mittagspauseOffsetRaw.isBlank()) { var mittagspauseOffset = Integer.parseInt(mittagspauseOffsetRaw); lb.initMittagspause(mittagspauseOffset); return; } print("Mittagspause um (optional): "); String manualMittagspauseRaw = br.readLine(); if (manualMittagspauseRaw != null && !manualMittagspauseRaw.isBlank()) { var manualMittagspause = LocalTime.parse(manualMittagspauseRaw, FormatTools.TIME_FORMATTER).truncatedTo(ChronoUnit.MINUTES); lb.initMittagspause(manualMittagspause); } else { lb.initMittagspause(); } } private static void handleZapfenstreich(BufferedReader br, LoadingBar lb) throws IOException { print("Mittagspause hat gedauert (optional): "); String mittagspauseDurationRaw = br.readLine(); Integer mittagspauseDuration = null; if (mittagspauseDurationRaw != null && !mittagspauseDurationRaw.isBlank()) { mittagspauseDuration = Integer.valueOf(mittagspauseDurationRaw); } LocalTime vorlaeufigeEndzeit = lb.getStartTime().plusMinutes(LoadingBar.MAX_NUMBER_WORK_MINS) .plusMinutes(mittagspauseDuration != null ? mittagspauseDuration : LoadingBar.MIN_LUNCH_DURATION); println("Endzeit: " + FormatTools.TIME_FORMATTER.format(vorlaeufigeEndzeit)); print("Feierabend verschieben um (optional): "); String zapfenstreichOffsetRaw = br.readLine(); if (zapfenstreichOffsetRaw != null && !zapfenstreichOffsetRaw.isBlank()) { int zapfenstreichOffset = Integer.parseInt(zapfenstreichOffsetRaw); lb.initZapfenstreich(mittagspauseDuration, zapfenstreichOffset); return; } print("Manuelle Uhrzeit Feierabend (optional): "); String manualZapfenstreichRaw = br.readLine(); if (manualZapfenstreichRaw != null && !manualZapfenstreichRaw.isBlank()) { LocalTime manualZapfenstreich = LocalTime.parse(manualZapfenstreichRaw, FormatTools.TIME_FORMATTER).truncatedTo(ChronoUnit.MINUTES); lb.initZapfenstreich(mittagspauseDuration, manualZapfenstreich); } else { lb.initZapfenstreich(mittagspauseDuration); } } public static void parseParametersAndRun(String[] args, Function constructor) { String nextArg = args[0]; if ("--help".equals(nextArg)) { printHelp(); System.exit(1); } verifyMinimumNumberOfArgs(args); verifyTimeFormat(nextArg, "Erstes Argument"); var startTime = LocalTime.parse(nextArg, FormatTools.TIME_FORMATTER).truncatedTo(ChronoUnit.MINUTES); nextArg = args[1]; var section = DaySection.byParam(nextArg); verifyDaySection(section, nextArg); LoadingBar lb = constructor.apply(startTime); if (section == DaySection.MITTAG) { initLoadingBarMittagspause(args, lb); } else { initLoadingBarZapfenstreich(args, lb); } boolean debug = false; boolean passedMinutesZero = false; lb.showLoadingBar(debug, passedMinutesZero); } private static void initLoadingBarMittagspause(String[] args, LoadingBar lb) { if (args.length == 2) { lb.initMittagspause(); return; } String nextArg = args[2]; if (OFFSET_PATTERN.matcher(nextArg).matches()) { lb.initMittagspause(Integer.parseInt(nextArg)); return; } verifyTimeFormat(nextArg, "Argument nach " + DaySection.MITTAG.getParam()); var manualMittagspause = LocalTime.parse(nextArg, FormatTools.TIME_FORMATTER).truncatedTo(ChronoUnit.MINUTES); lb.initMittagspause(manualMittagspause); } private static void initLoadingBarZapfenstreich(String[] args, LoadingBar lb) { if (args.length == 2) { lb.initZapfenstreich(); return; } String nextArg = args[2]; LocalTime maxZapfenstreich = null; int endTimeOffset = 0; Integer lunchDuration = null; if (FormatTools.TIME_PATTERN.matcher(nextArg).matches()) { maxZapfenstreich = LocalTime.parse(nextArg, FormatTools.TIME_FORMATTER).truncatedTo(ChronoUnit.MINUTES); } else if (OFFSET_PATTERN.matcher(nextArg).matches()) { endTimeOffset = Integer.parseInt(nextArg); } else { verifyDurationFormat(nextArg, "Argument nach " + DaySection.ZAPFENSTREICH.getParam()); lunchDuration = Integer.parseInt(nextArg); } if (args.length == 3) { if (maxZapfenstreich == null && endTimeOffset == 0) { lb.initZapfenstreich(lunchDuration); } else if (maxZapfenstreich == null) { lb.initZapfenstreich(lunchDuration, endTimeOffset); } else { lb.initZapfenstreich(lunchDuration, maxZapfenstreich); } return; } nextArg = args[3]; if (lunchDuration == null) { println("Letztes Argument darf nur auf Mittagspausendauer folgen."); System.exit(1); } if (maxZapfenstreich == null && !OFFSET_PATTERN.matcher(nextArg).matches()) { verifyTimeFormat(nextArg, "Letztes Argument nach " + DaySection.ZAPFENSTREICH.getParam() + " und Mittagspausendauer"); maxZapfenstreich = LocalTime.parse(nextArg, FormatTools.TIME_FORMATTER).truncatedTo(ChronoUnit.MINUTES); lb.initZapfenstreich(lunchDuration, maxZapfenstreich); return; } verifyOffsetFormat(nextArg, "Letztes Argument nach " + DaySection.ZAPFENSTREICH.getParam() + " und Enduhrzeit"); endTimeOffset = Integer.parseInt(nextArg); lb.initZapfenstreich(lunchDuration, endTimeOffset); } private static void verifyMinimumNumberOfArgs(String[] args) { if (args.length >= 2) { return; } println("Mindestens 2 Argumente müssen gegeben sein."); printHelp(); System.exit(1); } private static void verifyTimeFormat(String param, String errMsgPrefix) { verifyInputFormat(FormatTools.TIME_PATTERN, param, errMsgPrefix, "Uhrzeitformat (" + FormatTools.TIME_FORMAT + ")", false); } private static void verifyDurationFormat(String param, String errMsgPrefix) { verifyInputFormat(LUNCH_DURATION_PATTERN, param, errMsgPrefix, "Minutenanzahl (ganze Zahl)", true); } private static void verifyOffsetFormat(String param, String errMsgPrefix) { verifyInputFormat(OFFSET_PATTERN, param, errMsgPrefix, "Minutendifferenz (ganze Zahl mit Vorzeichen)", false); } private static void verifyInputFormat(Pattern pattern, String param, String errMsgPrefix, String firstInputPart, boolean timeInputPossible) { if (pattern.matcher(param).matches()) { return; } var possibleTimeInputPart = timeInputPossible ? " oder Uhrzeitformat (" + FormatTools.TIME_FORMAT + ")" : ""; println(errMsgPrefix + " \"" + param + "\" muss " + firstInputPart + possibleTimeInputPart + " entsprechen."); System.exit(1); } private static void verifyDaySection(DaySection section, String param) { if (section != null) { return; } List sectionDescs = Arrays.stream(DaySection.values()).map((DaySection ds) -> ds.getDescription() + " (" + ds.getParam() + ")") .collect(Collectors.toList()); String sectionDescsJoined = String.join(" oder ", sectionDescs); println("Argument nach Startzeit \"" + param + "\" muss Angabe für " + sectionDescsJoined + " sein."); System.exit(1); } private static void printHelp() { println("Mögliche Argumente für LoadingBar:\n" + "Normalfall Vormittag (Mittagspause <= " + LoadingBar.LATEST_LUNCH_TIME + ")\n" + FormatTools.TIME_FORMAT + " " + DaySection.MITTAG.getParam() + "\n" + "Vormittag mit expliziter Mittagspause (<= " + LoadingBar.LATEST_LUNCH_TIME + ")\n" + FormatTools.TIME_FORMAT + " " + DaySection.MITTAG.getParam() + " " + FormatTools.TIME_FORMAT + "\n" + "Vormittag mit abweichender Minutenanzahl Arbeitszeit\n" + FormatTools.TIME_FORMAT + " " + DaySection.MITTAG.getParam() + " -+mm\n" + "Normalfall Nachmittag (Mittagspause " + LoadingBar.MIN_LUNCH_DURATION + " min)\n" + FormatTools.TIME_FORMAT + " " + DaySection.ZAPFENSTREICH.getParam() + "\n" + "Nachmittag mit expliziter Länge Mittagspause (Mittagspause unter " + LoadingBar.MIN_LUNCH_DURATION + " min wird auf " + LoadingBar.MIN_LUNCH_DURATION + " min korrigiert)\n" + FormatTools.TIME_FORMAT + " " + DaySection.ZAPFENSTREICH.getParam() + " mm\n" + "Nachmittag mit explizitem Feierabend (Mittagspause je nach Minimum (s.u.))\n" + FormatTools.TIME_FORMAT + " " + DaySection.ZAPFENSTREICH.getParam() + " " + FormatTools.TIME_FORMAT + "\n" + "Nachmittag mit abweichender Minutenanzahl Arbeitszeit\n" + FormatTools.TIME_FORMAT + " " + DaySection.ZAPFENSTREICH.getParam() + " -+mm\n" + "Nachmittag mit explizitem Feierabend u. expliziter Länge Mittagspause (Mittagspause unter Minimum (s.u.) wird auf Minimum korrigiert)\n" + FormatTools.TIME_FORMAT + " " + DaySection.ZAPFENSTREICH.getParam() + " mm " + FormatTools.TIME_FORMAT + "\n" + "Nachmittag mit explizitem Feierabend u. abweichender Minutenanzahl Arbeitszeit\n" + FormatTools.TIME_FORMAT + " " + DaySection.ZAPFENSTREICH.getParam() + " " + FormatTools.TIME_FORMAT + " -+mm\n\n" + "Mittagspause minimum in Minuten:\n" + " - bis " + LoadingBar.MAX_NUMBER_WORK_MINS_WITHOUT_LUNCH + " min (" + LoadingBar.MAX_NUMBER_WORK_MINS_WITHOUT_LUNCH / CommonTools.MINS_PER_HOUR + " std): 0\n" + " - bis " + LoadingBar.MAX_NUMBER_WORK_MINS_WITHOUT_LUNCH + " min + " + LoadingBar.MIN_LUNCH_DURATION + " min: Arbeitszeit - " + LoadingBar.MAX_NUMBER_WORK_MINS_WITHOUT_LUNCH + " min\n" + " - ab " + LoadingBar.MAX_NUMBER_WORK_MINS_WITHOUT_LUNCH + " min + " + LoadingBar.MIN_LUNCH_DURATION + " min: " + LoadingBar.MIN_LUNCH_DURATION + " min\n" ); } }