diff options
Diffstat (limited to '')
| -rw-r--r-- | src/main/java/design/model/Golfer.java | 58 | ||||
| -rw-r--r-- | src/main/java/design/model/League.java | 30 | ||||
| -rw-r--r-- | src/main/java/design/model/ScrambleLeague.java | 20 | ||||
| -rw-r--r-- | src/main/java/design/model/StrokeLeague.java | 10 | ||||
| -rw-r--r-- | src/main/java/design/model/holeplay/HolePlayContext.java | 61 | ||||
| -rw-r--r-- | src/main/java/design/model/undo/Memento.java | 4 | ||||
| -rw-r--r-- | src/main/java/design/model/undo/Originator.java | 7 | ||||
| -rw-r--r-- | src/main/java/design/model/undo/UndoManager.java | 91 |
8 files changed, 259 insertions, 22 deletions
diff --git a/src/main/java/design/model/Golfer.java b/src/main/java/design/model/Golfer.java index 1c4e669..84f7396 100644 --- a/src/main/java/design/model/Golfer.java +++ b/src/main/java/design/model/Golfer.java @@ -7,8 +7,11 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import java.util.ArrayList; import java.util.List; +import design.model.undo.Memento; +import design.model.undo.Originator; + @JsonPropertyOrder({ "clubs", "nextClubId" }) -public class Golfer { +public class Golfer implements Originator { private String username; private int passwordHash; private String fullName; @@ -16,20 +19,18 @@ public class Golfer { private final List<Round> rounds; private final List<Club> clubs; // Keep track of golfer's clubs private int nextClubId; - private final List<Invite> invites; @JsonCreator private Golfer(String username, int passwordHash, String fullName, List<Course> courses, List<Round> rounds, - List<Club> clubs, List<Invite> invites) { + List<Club> clubs) { this.username = username; this.passwordHash = passwordHash; this.fullName = fullName; this.courses = courses; this.rounds = rounds; this.clubs = clubs; - this.invites = invites != null ? invites : new ArrayList<>(); this.nextClubId = this.clubs.stream().mapToInt(Club::getId).max().orElse(0) + 1; } @@ -40,7 +41,6 @@ public class Golfer { this.courses = new ArrayList<>(); this.rounds = new ArrayList<>(); this.clubs = new ArrayList<>(); - this.invites = new ArrayList<>(); this.nextClubId = 1; } @@ -93,8 +93,8 @@ public class Golfer { } public Club addClub(Club c) { - c.setId(nextClubId++); clubs.add(c); + c.setId(nextClubId++); return c; } @@ -119,15 +119,49 @@ public class Golfer { clubs.remove(c); } - public boolean addInvite(Invite invite) { - return invites.add(invite); + // Takes a snapshot of the golfer + private static class GolferMemento implements Memento { + private final String username; + private final int passwordHash; + private final String fullName; + private final List<Course> courses; + private final List<Round> rounds; + private final List<Club> clubs; + private final int nextClubId; + + GolferMemento(Golfer g) { + this.username = g.username; + this.passwordHash = g.passwordHash; + this.fullName = g.fullName; + this.courses = new ArrayList<>(g.courses); + this.rounds = new ArrayList<>(g.rounds); + this.clubs = new ArrayList<>(g.clubs); + this.nextClubId = g.nextClubId; + } } - public boolean removeInvite(Invite o) { - return invites.remove(o); + @Override + public Memento createMemento() { + return new GolferMemento(this); } - public Invite[] getInvites() { - return invites.toArray(Invite[]::new); + @Override + public void restore(Memento memento) { + GolferMemento gm = (GolferMemento) memento; + + this.username = gm.username; + this.passwordHash = gm.passwordHash; + this.fullName = gm.fullName; + + this.courses.clear(); + this.courses.addAll(gm.courses); + + this.rounds.clear(); + this.rounds.addAll(gm.rounds); + + this.clubs.clear(); + this.clubs.addAll(gm.clubs); + + this.nextClubId = gm.nextClubId; } } diff --git a/src/main/java/design/model/League.java b/src/main/java/design/model/League.java index 0252f89..881e25f 100644 --- a/src/main/java/design/model/League.java +++ b/src/main/java/design/model/League.java @@ -1,9 +1,22 @@ package design.model; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import java.util.ArrayList; import java.util.Date; +import java.util.List; +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "type" +) +@JsonSubTypes({ + @JsonSubTypes.Type(value = ScrambleLeague.class, name = "scramble"), + @JsonSubTypes.Type(value = StrokeLeague.class, name = "stroke") +}) public abstract class League { private int id; private final String name; @@ -11,15 +24,17 @@ public abstract class League { private final Date startDate; private final Date endDate; private final Golfer owner; + private final List<Match> schedule; @JsonCreator - protected League(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { + protected League(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List<Match> schedule) { this.id = id; this.name = name; this.registrationDate = registrationDate; this.startDate = startDate; this.endDate = endDate; this.owner = owner; + this.schedule = schedule != null ? schedule : new ArrayList<>(); } public League(String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { @@ -29,6 +44,7 @@ public abstract class League { this.startDate = startDate; this.endDate = endDate; this.owner = owner; + this.schedule = new ArrayList<>(); } public int getId() { @@ -55,6 +71,18 @@ public abstract class League { return owner; } + public Match[] getSchedule() { + return schedule.toArray(Match[]::new); + } + + public void addMatchToSchedule(Match match) { + Date date = match.getDateScheduled(); + if(date.after(endDate)){ + throw new IllegalArgumentException("Cannot create match after league has ended"); + } + schedule.add(match); + } + public void setId(int id) { assert this.id == -1; this.id = id; diff --git a/src/main/java/design/model/ScrambleLeague.java b/src/main/java/design/model/ScrambleLeague.java index 7ff966e..d372264 100644 --- a/src/main/java/design/model/ScrambleLeague.java +++ b/src/main/java/design/model/ScrambleLeague.java @@ -1,22 +1,25 @@ package design.model; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; +@JsonTypeName("scramble") public class ScrambleLeague extends League { private final List<Team> participants; @JsonCreator - private ScrambleLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List<Team> participants) { - super(id, name, registrationDate, startDate, endDate, owner); + private ScrambleLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List<Team> participants, List<Match> schedule) { + super(id, name, registrationDate, startDate, endDate, owner, schedule); this.participants = participants; } - public ScrambleLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { - super(id, name, registrationDate, startDate, endDate, owner); + public ScrambleLeague(String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { + super(name, registrationDate, startDate, endDate, owner); this.participants = new ArrayList<>(); } @@ -31,4 +34,13 @@ public class ScrambleLeague extends League { public Team[] getParticipants() { return participants.toArray(Team[]::new); } + + public Team locateTeam(Golfer golfer) { + for (Team participant : participants) { + if (List.of(participant.getMembers()).contains(golfer)) { + return participant; + } + } + return null; + } } diff --git a/src/main/java/design/model/StrokeLeague.java b/src/main/java/design/model/StrokeLeague.java index 6bdde0a..2b787b5 100644 --- a/src/main/java/design/model/StrokeLeague.java +++ b/src/main/java/design/model/StrokeLeague.java @@ -1,22 +1,24 @@ package design.model; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonTypeName; import java.util.ArrayList; import java.util.Date; import java.util.List; +@JsonTypeName("stroke") public class StrokeLeague extends League { private final List<Golfer> participants; @JsonCreator - private StrokeLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List<Golfer> participants) { - super(id, name, registrationDate, startDate, endDate, owner); + private StrokeLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner, List<Golfer> participants, List<Match> schedule) { + super(id, name, registrationDate, startDate, endDate, owner, schedule); this.participants = participants; } - public StrokeLeague(int id, String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { - super(id, name, registrationDate, startDate, endDate, owner); + public StrokeLeague(String name, Date registrationDate, Date startDate, Date endDate, Golfer owner) { + super(name, registrationDate, startDate, endDate, owner); this.participants = new ArrayList<>(); } diff --git a/src/main/java/design/model/holeplay/HolePlayContext.java b/src/main/java/design/model/holeplay/HolePlayContext.java index 7a5d8ef..71fba32 100644 --- a/src/main/java/design/model/holeplay/HolePlayContext.java +++ b/src/main/java/design/model/holeplay/HolePlayContext.java @@ -6,7 +6,10 @@ import java.util.ArrayList; import design.model.*; import design.persistence.PersonalDatabase; -public class HolePlayContext { +import design.model.undo.Memento; +import design.model.undo.Originator; + +public class HolePlayContext implements Originator { private final Golfer golfer; private final Round round; private final PersonalDatabase pdb; @@ -109,4 +112,60 @@ public class HolePlayContext { void setStrokes(int s) { this.strokes = s; } + + // Captures current State, current play (hole# + swings), and stroke counter + private static class HolePlayMemento implements Memento { + private final String stateName; + private final Play currentPlayCopy; + private final int strokesCopy; + + HolePlayMemento(HolePlayContext ctx) { + this.stateName = ctx.state.name(); + + // Copy currentPlay if it exists + Play src = ctx.currentPlay; + if (src != null) { + var copySwings = new ArrayList<Swing>(); + for (Swing s : src.getSwings()) { + copySwings.add(new Swing(s.getDistance(), s.getClubUsed())); + } + this.currentPlayCopy = new Play(src.getHoleNumber(), copySwings); + } else { + this.currentPlayCopy = null; + } + + this.strokesCopy = ctx.strokes; + } + } + + @Override + public Memento createMemento() { + return new HolePlayMemento(this); + } + + @Override + public void restore(Memento m) { + HolePlayMemento hm = (HolePlayMemento) m; + + // restore strokes + this.strokes = hm.strokesCopy; + + // restore currentPlay + if (hm.currentPlayCopy == null) { + this.currentPlay = null; + } else { + var copySwings = new ArrayList<Swing>(); + for (Swing s : hm.currentPlayCopy.getSwings()) { + copySwings.add(new Swing(s.getDistance(), s.getClubUsed())); + } + this.currentPlay = new Play(hm.currentPlayCopy.getHoleNumber(), copySwings); + } + + // restore state based on name + switch (hm.stateName) { + case "SetupState" -> this.state = new SetupState(); + case "PlayState" -> this.state = new PlayState(); + case "HoleCompleteState" -> this.state = new HoleCompleteState(); + } + } }
\ No newline at end of file diff --git a/src/main/java/design/model/undo/Memento.java b/src/main/java/design/model/undo/Memento.java new file mode 100644 index 0000000..162c3f3 --- /dev/null +++ b/src/main/java/design/model/undo/Memento.java @@ -0,0 +1,4 @@ +package design.model.undo; + +public interface Memento { +} diff --git a/src/main/java/design/model/undo/Originator.java b/src/main/java/design/model/undo/Originator.java new file mode 100644 index 0000000..63eac38 --- /dev/null +++ b/src/main/java/design/model/undo/Originator.java @@ -0,0 +1,7 @@ +package design.model.undo; + +public interface Originator { + Memento createMemento(); + + void restore(Memento memento); +}
\ No newline at end of file diff --git a/src/main/java/design/model/undo/UndoManager.java b/src/main/java/design/model/undo/UndoManager.java new file mode 100644 index 0000000..5c6a4a0 --- /dev/null +++ b/src/main/java/design/model/undo/UndoManager.java @@ -0,0 +1,91 @@ +package design.model.undo; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.stream.Collectors; + +// Singleton caretaker that handles undo and redo stacks. +public final class UndoManager { + + private static final UndoManager INSTANCE = new UndoManager(); + + public static UndoManager instance() { + return INSTANCE; + } + + private UndoManager() { + } + + // Stack entry + private static class Entry { + final Originator originator; + final Memento memento; + final String label; + + Entry(Originator originator, Memento memento, String label) { + this.originator = originator; + this.memento = memento; + this.label = label; + } + } + + private final Deque<Entry> undoStack = new ArrayDeque<>(); + private final Deque<Entry> redoStack = new ArrayDeque<>(); + + // Capture state + public void capture(Originator originator, String label) { + undoStack.push(new Entry(originator, originator.createMemento(), label)); + redoStack.clear(); + } + + // Undo / Redo ops + public boolean canUndo() { + return !undoStack.isEmpty(); + } + + public boolean canRedo() { + return !redoStack.isEmpty(); + } + + public String peekUndoLabel() { + return canUndo() ? undoStack.peek().label : null; + } + + public String peekRedoLabel() { + return canRedo() ? redoStack.peek().label : null; + } + + public List<String> getUndoHistoryLabels() { + return undoStack.stream() + .map(e -> e.label) + .collect(Collectors.toList()); + } + + public void undo() { + if (!canUndo()) { + System.out.println("Nothing to undo."); + return; + } + + Entry entry = undoStack.pop(); + redoStack.push(new Entry(entry.originator, entry.originator.createMemento(), entry.label)); + entry.originator.restore(entry.memento); + } + + public void redo() { + if (!canRedo()) { + System.out.println("Nothing to redo."); + return; + } + + Entry entry = redoStack.pop(); + undoStack.push(new Entry(entry.originator, entry.originator.createMemento(), entry.label)); + entry.originator.restore(entry.memento); + } + + public void purge() { + undoStack.clear(); + redoStack.clear(); + } +} |
