1
+ package me .flame .menus .menu .iterator ;
2
+
3
+ import me .flame .menus .items .MenuItem ;
4
+ import me .flame .menus .menu .IterationDirection ;
5
+ import me .flame .menus .menu .Slot ;
6
+ import me .flame .menus .menu .Page ;
7
+ import org .jetbrains .annotations .NotNull ;
8
+ import org .jetbrains .annotations .Nullable ;
9
+
10
+ import java .util .Iterator ;
11
+ import java .util .NoSuchElementException ;
12
+ import java .util .Optional ;
13
+
14
+ public class PageIterator implements Iterator <MenuItem > {
15
+ @ NotNull
16
+ private final Page page ;
17
+
18
+ @ NotNull
19
+ private final IterationDirection direction ;
20
+
21
+ @ NotNull
22
+ private Slot position ;
23
+
24
+ private Slot next ;
25
+
26
+ private boolean isFirst = true ;
27
+
28
+ private final int rows ;
29
+
30
+ private static final String NOTHING_MORE_NEXT =
31
+ "Used PageIterator#next() but nothing more" +
32
+ "\n Fix: Use hasNext() beforehand to avoid this error." ;
33
+
34
+ private static final String NOTHING_MORE_NEXT_OPTIONAL =
35
+ "Used PageIterator#nextOptional() but nothing more" +
36
+ "\n Fix: Use hasNext() beforehand to avoid this error." ;
37
+
38
+ private static final String NOTHING_MORE_NEXT_NOT_NULL =
39
+ "Used PageIterator#nextNotNull() but nothing more" ;
40
+
41
+ private static final String GREATER_THAN_ONE_ONLY =
42
+ "Starting row and column must be 1 or greater only." +
43
+ "\n Fix: If you're using an algorithm for rows/cols, you might wanna check it" ;
44
+
45
+ public PageIterator (int startingRow , int startingCol ,
46
+ @ NotNull IterationDirection direction ,
47
+ @ NotNull Page page ) {
48
+ Slot prepos = new Slot (startingRow , startingCol );
49
+ if (!prepos .isSlot ()) throw new IllegalArgumentException (GREATER_THAN_ONE_ONLY );
50
+ this .page = page ;
51
+ this .rows = page .rows ();
52
+ this .position = prepos ;
53
+ this .direction = direction ;
54
+ }
55
+
56
+ public PageIterator (@ NotNull IterationDirection direction ,
57
+ @ NotNull Page page ) {
58
+ this .page = page ;
59
+ this .rows = page .rows ();
60
+ this .position = Slot .FIRST .copy ();
61
+ this .direction = direction ;
62
+ }
63
+
64
+ /**
65
+ * Retrieves the next slot in the menu.
66
+ *
67
+ * @param emptyOnly a boolean indicating whether to retrieve only empty slots
68
+ * @return the next empty slot in the menu, or null if no empty slot is found
69
+ */
70
+ public Slot nextSlot (boolean emptyOnly ) {
71
+ if (!emptyOnly ) return nextSlot ();
72
+
73
+ while (true ) {
74
+ MenuItem item = page .getItem (position );
75
+ if (item == null ) break ;
76
+
77
+ position = direction .shift (position , this .rows );
78
+ if (!position .isSlot ()) return null ;
79
+ }
80
+
81
+ // when it becomes empty
82
+ return position ;
83
+ }
84
+
85
+ /**
86
+ * Retrieves the next slot in the menu.
87
+ * @return the next empty slot in the menu, or null if no empty slot is found
88
+ */
89
+ public @ Nullable Slot nextSlot () {
90
+ if (!isFirst ) {
91
+ position = next ;
92
+ next = null ;
93
+ return position ;
94
+ }
95
+ isFirst = false ;
96
+ return position ;
97
+ }
98
+
99
+ @ Override
100
+ public boolean hasNext () {
101
+ if (next != null ) return true ;
102
+ next = direction .shift (position , this .rows );
103
+ return next .isSlot ();
104
+ }
105
+
106
+ @ Override
107
+ public MenuItem next () {
108
+ Slot slot = nextSlot ();
109
+ if (slot != null ) return page .getItem (slot .getSlot ());
110
+ throw new NoSuchElementException (NOTHING_MORE_NEXT );
111
+ }
112
+
113
+ /**
114
+ * Retrieves the next non-null MenuItem in the menu.
115
+ *
116
+ * @return the next non-null MenuItem in the menu
117
+ */
118
+ public MenuItem nextNotNull () {
119
+ while (hasNext ()) {
120
+ Slot slot = nextSlot ();
121
+ if (slot == null )
122
+ throw new NoSuchElementException (
123
+ NOTHING_MORE_NEXT_NOT_NULL +
124
+ "\n Fix: Everything after slot " + position .getSlot () + " is empty/null."
125
+ );
126
+
127
+ MenuItem item = page .getItem (slot .getSlot ());
128
+ if (item != null ) return item ;
129
+ }
130
+
131
+ throw new NoSuchElementException (
132
+ NOTHING_MORE_NEXT_NOT_NULL +
133
+ "\n Fix: Everything after slot " + position .getSlot () + " is empty/null."
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Retrieves the next optional menu item.
139
+ *
140
+ * @return an Optional object containing the next MenuItem, if available.
141
+ * Returns an empty Optional if the slot in the menu is empty.
142
+ * Returns an empty Optional if there are no more items.
143
+ * @throws NoSuchElementException if there are no more items in the menu.
144
+ */
145
+ public Optional <MenuItem > nextOptional () {
146
+ Slot slot = nextSlot ();
147
+ if (slot != null ) return page .get (slot );
148
+ throw new NoSuchElementException (NOTHING_MORE_NEXT_OPTIONAL );
149
+ }
150
+ }
0 commit comments