diff --git a/src/main/java/net/themusicinnoise/vaccalc/PointEngine.java b/src/main/java/net/themusicinnoise/vaccalc/PointEngine.java index be7772c..25fcfb7 100644 --- a/src/main/java/net/themusicinnoise/vaccalc/PointEngine.java +++ b/src/main/java/net/themusicinnoise/vaccalc/PointEngine.java @@ -1,15 +1,108 @@ package net.themusicinnoise.vaccalc; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.Month; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class PointEngine { private double defaultPoints; + static private class PointRule { + private enum RuleType { + DAY_OF_WEEK, + MONTH, + DATE, + } + + static final Pattern DOW_PATTERN = Pattern.compile("dow=(sun|mon|tue|wed|thu|fri|sat) (\\d+\\.\\d+)", Pattern.CASE_INSENSITIVE); + static final Pattern MONTH_PATTERN = Pattern.compile("m=(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) (\\d+\\.\\d+)", Pattern.CASE_INSENSITIVE); + static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}) (\\d+\\.\\d+)", Pattern.CASE_INSENSITIVE); + + private RuleType type; + private DayOfWeek dow; + private Month mon; + private LocalDate date; + private double points; + + public PointRule(String def) { + Matcher dowMatcher = DOW_PATTERN.matcher(def); + Matcher monthMatcher = MONTH_PATTERN.matcher(def); + Matcher dateMatcher = DATE_PATTERN.matcher(def); + + if (dowMatcher.find()) { + this.type = RuleType.DAY_OF_WEEK; + this.points = Double.parseDouble(dowMatcher.group(2)); + this.dow = DayOfWeek.from(DateTimeFormatter.ofPattern("EEE").parse(dowMatcher.group(1))); + } else if (monthMatcher.find()) { + this.type = RuleType.MONTH; + this.points = Double.parseDouble(monthMatcher.group(2)); + this.mon = Month.from(DateTimeFormatter.ofPattern("MMM").parse(monthMatcher.group(1))); + } else if (dateMatcher.find()) { + this.type = RuleType.DATE; + this.points = Double.parseDouble(dateMatcher.group(2)); + this.date = LocalDate.parse(dateMatcher.group(1), DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } else { + throw new IllegalArgumentException("Invalid line: '" + def + "'"); + } + } + + public boolean applies(LocalDate date) { + switch (type) { + case DAY_OF_WEEK: + return this.dow == date.getDayOfWeek(); + case MONTH: + return this.mon == date.getMonth(); + case DATE: + return this.date.isEqual(date); + } + return false; + } + + public double getPoints() { return points; } + } + private List rules; + public PointEngine() { defaultPoints = 1.0; + rules = new ArrayList<>(); } + public void importPointsFile(File pointsFile) { + Pattern defaultPattern = Pattern.compile("default (\\d+\\.\\d+)"); + + try (BufferedReader br = new BufferedReader(new FileReader(pointsFile))) { + String line; + while ((line = br.readLine()) != null) { + Matcher defaultMatcher = defaultPattern.matcher(line); + if (defaultMatcher.find()) { + defaultPoints = Double.parseDouble(defaultMatcher.group(1)); + } else { + rules.add(new PointRule(line)); + } + } + } catch (IOException e) { + throw new RuntimeException("Failed to read points file: " + pointsFile, e); + } + } + + public void reset() { rules.clear(); } + public double getPointsOfDay(LocalDate date) { - return defaultPoints; + double points = defaultPoints; + for (PointRule rule : rules) { + if (rule.applies(date)) { + points = rule.getPoints(); + } + } + return points; } } diff --git a/src/main/java/net/themusicinnoise/vaccalc/VacCalc.java b/src/main/java/net/themusicinnoise/vaccalc/VacCalc.java index f6fb4a1..eeae96a 100644 --- a/src/main/java/net/themusicinnoise/vaccalc/VacCalc.java +++ b/src/main/java/net/themusicinnoise/vaccalc/VacCalc.java @@ -19,6 +19,26 @@ public class VacCalc extends JFrame { JMenuBar menuBar = new JMenuBar(); JMenu appMenu = new JMenu("VacCalc"); + JMenuItem importItem = new JMenuItem("Import points"); + importItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ev) { + JFileChooser fileChooser = new JFileChooser(); + int ret = fileChooser.showOpenDialog(VacCalc.this); + if(ret == JFileChooser.APPROVE_OPTION) { + try { + pointEngine.importPointsFile(fileChooser.getSelectedFile()); + } catch(RuntimeException ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(VacCalc.this, ex.getMessage(), "Parsing Error", + JOptionPane.ERROR_MESSAGE); + pointEngine.reset(); + } + } + calendarPanel.repaint(); + } + }); + appMenu.add(importItem); JMenuItem exitItem = new JMenuItem("Exit"); exitItem.addActionListener(new ActionListener() { @Override @@ -110,7 +130,7 @@ public class VacCalc extends JFrame { private void updatePointsLabel() { double points = calendarPanel.getTotalPoints(); - pointsLabel.setText(String.format("Total Points: %.1f", points)); + pointsLabel.setText(String.format("Total Points: %.3f", points)); } public static void main(String[] args) { diff --git a/vac-points.txt b/vac-points.txt new file mode 100644 index 0000000..c59890b --- /dev/null +++ b/vac-points.txt @@ -0,0 +1,6 @@ +default 1.0 +dow=Fri 0.825 +2026-12-24 0.5 +2026-12-31 0.5 +m=Jul 0.825 +m=Aug 0.825