ReservationView.java
1 |
|
2 |
import java.util.Set; |
3 |
import java.util.HashSet; |
4 |
import java.util.Date; |
5 |
import java.util.ArrayList; |
6 |
import java.text.DateFormat; |
7 |
import java.awt.Dimension; |
8 |
/** |
9 |
* Creates a view screen that allows interaction with the reservation. |
10 |
* This window will place the reservation details in editable fields, so its |
11 |
* state can be adapted. |
12 |
* It then also adds a couple of buttons; add/update/cancel, with their |
13 |
* respective actions. These will then be passed to the ReservationController. |
14 |
* It will not allow to add/update a reservation if dates overlap, i.e. beds |
15 |
* can't be reserved for that period. |
16 |
* @author Maarten Vangeneugden - 1438256 |
17 |
*/ |
18 |
public class ReservationView { |
19 |
|
20 |
private Reservation reservation; |
21 |
private Window window; |
22 |
|
23 |
// Controllers for communication with the rest |
24 |
private ReservationController rc; |
25 |
private RoomController roc; |
26 |
|
27 |
// GUI widgets |
28 |
private JTextField nameField; |
29 |
private JSpinner amountPeopleField; |
30 |
private JTextField beginDateField; |
31 |
private JTextField endDateField; |
32 |
private JSpinner durationField; |
33 |
private JRadioButton[] typeField; |
34 |
private JCheckBox showerField; |
35 |
private JCheckBox bathField; |
36 |
private JCheckBox minibarField; |
37 |
private JCheckBox aircoField; |
38 |
private ArrayList<JCheckBox> breakfastDayFields; |
39 |
|
40 |
|
41 |
/** |
42 |
* Construct a window to edit a Reservation. |
43 |
* This window presents its caller with the necessary tools to edit the |
44 |
* given Reservation, and save it in the system. |
45 |
* |
46 |
* By sending it an empty Reservation, you can add a new Reservation to the |
47 |
* system. |
48 |
* This class is built in a way that allows it to be used for both creating |
49 |
* new Reservations, and updating/changing existing Reservations. |
50 |
* Existing Reservations can also be removed by clicking the appropriate |
51 |
* button. |
52 |
* @param reservation The Reservation that will be updated. |
53 |
* @param rc The ReservationController class. |
54 |
* @param roc The RoomController class. |
55 |
* @pre No parameter may be a null pointer. |
56 |
* @post A window is displayed with GUI widgets, which are filled in |
57 |
* according to the state of reservation. |
58 |
* @throws NullPointerException if any parameter is a null pointer. |
59 |
*/ |
60 |
public ReservationView(Reservation reservation, ReservationController rc, RoomController roc) { |
61 |
// Contract validation |
62 |
if(rc == null || roc == null || reservation == null) |
63 |
throw new NullPointerException("One or more of the given parameters is a null pointer."); |
64 |
// Contract validated |
65 |
this.rc = rc; |
66 |
this.roc = roc; |
67 |
|
68 |
this.reservation = reservation; |
69 |
this.window = new Window("Reservation screen"); |
70 |
this.addFields(); |
71 |
} |
72 |
|
73 |
public void setReservation(Reservation reservation) { |
74 |
this.reservation = reservation; |
75 |
} |
76 |
|
77 |
public Reservation getReservation() { |
78 |
return reservation; |
79 |
} |
80 |
|
81 |
/** |
82 |
* Add the necessary fields to the window. |
83 |
* This method inspects the Reservation, and copies the included information |
84 |
* to the widget's content. |
85 |
*/ |
86 |
private void addFields() { |
87 |
this.window.createLabel("Group name"); |
88 |
this.nameField = window.createTextField(this.reservation.getGroupName()); |
89 |
// nameField needs manual sizing, since an empty name makes it too |
90 |
// small. |
91 |
Dimension minimumSize = new Dimension(500, 0); |
92 |
this.nameField.setMinimumSize(minimumSize); |
93 |
this.window.createLabel("Amount of people"); |
94 |
this.amountPeopleField = this.window.createSpinner(1, 20, this.reservation.getPeople(), 1); |
95 |
System.out.println("HIER AL"); |
96 |
// Formatting date for the date field: |
97 |
this.window.createLabel("Begin date"); |
98 |
this.beginDateField = window.createTextField(this.reservation.getBeginDate().toGMTString()); |
99 |
this.window.createLabel("End date"); |
100 |
this.endDateField = window.createTextField(this.reservation.getEndDate().toGMTString()); |
101 |
String[] types = {"Male", "Female", "Mixed"}; |
102 |
this.typeField = this.window.createRadioButtons(types); |
103 |
// TODO: Add a test to see if the Reservation has indicated which type |
104 |
// it is, and then already check the corresponding radio button. |
105 |
this.showerField = this.window.createCheckbox("Shower"); |
106 |
this.bathField = this.window.createCheckbox("Bath"); |
107 |
this.minibarField = this.window.createCheckbox("Minibar"); |
108 |
this.aircoField = this.window.createCheckbox("Airco"); |
109 |
// TODO: Idem for the facilities, test if already in Reservation, and |
110 |
// check accordingly. |
111 |
System.out.println("ZELGS HIER"); |
112 |
this.breakfastDayFields = new ArrayList<>(); |
113 |
this.window.createButton("Add/Update reservation", "", "addReservation", this); |
114 |
this.window.createButton("Remove reservation", "", "removeReservation", this); |
115 |
this.window.createButton("Update breakfast possibilities", "", "generateBreakfastOptions", this); |
116 |
this.generateBreakfastOptions(); |
117 |
} |
118 |
|
119 |
/** |
120 |
* Creates all possible breakfast options for this Reservation. |
121 |
* This method will first inform itself with the BeginDateField and |
122 |
* EndDateField values. |
123 |
* If these are filled with correctly formatted dates, the method will |
124 |
* generate all times that breakfast can be served in the given timespan. |
125 |
* |
126 |
* After all possible breakfasts are generated, the method will inform with |
127 |
* the Reservation itself if there are already breakfasts put in it. If so, |
128 |
* the checkboxes of those days are checked by default. |
129 |
* |
130 |
* Call this method whenever an update of the days is requested. |
131 |
*/ |
132 |
public void generateBreakfastOptions() { |
133 |
Date beginDate = new Date(Date.parse(this.beginDateField.getText())); |
134 |
Date endDate = new Date(this.endDateField.getText()); |
135 |
if(!beginDate.before(endDate)) { |
136 |
System.err.println("Begin date did not occur before end date. No update executed."); |
137 |
return; |
138 |
} |
139 |
|
140 |
// Time in Date class is represented using milliseconds |
141 |
final long ONE_DAY = 1000*60*60*24; |
142 |
Date breakfastDay = (Date)beginDate.clone(); |
143 |
// Breakfast is served at 9 o'clock! |
144 |
breakfastDay.setSeconds(0); |
145 |
breakfastDay.setMinutes(0); |
146 |
breakfastDay.setHours(9); |
147 |
// First check: Can people have breakfast on day of arrival? |
148 |
if(breakfastDay.before(beginDate)) { |
149 |
breakfastDay.setTime(breakfastDay.getTime() + ONE_DAY); |
150 |
} |
151 |
// Removing the previous checkboxes, and creating a new list of them: |
152 |
for(int i=0; i<this.breakfastDayFields.size(); i++) { |
153 |
this.window.removeComponent(this.breakfastDayFields.get(i)); |
154 |
} |
155 |
ArrayList<JCheckBox> checkboxes = new ArrayList<>(); |
156 |
while(breakfastDay.before(endDate)) { |
157 |
String dateString = |
158 |
String.valueOf(breakfastDay.getDate()) +"/"+ |
159 |
String.valueOf(breakfastDay.getMonth()+1) +"/"+ |
160 |
String.valueOf(breakfastDay.getYear()+1900); |
161 |
JCheckBox checkbox = this.window.createCheckbox(dateString); |
162 |
if(this.reservation.getBreakfastDays().contains(breakfastDay)) {// Check if already enabled |
163 |
checkbox.setSelected(true); |
164 |
} |
165 |
checkboxes.add(checkbox); |
166 |
breakfastDay.setTime(breakfastDay.getTime() + ONE_DAY); |
167 |
} |
168 |
// Putting these checkboxes in the appropriate member: |
169 |
this.breakfastDayFields = checkboxes; |
170 |
} |
171 |
|
172 |
/** |
173 |
* Get all selected breakfast days. |
174 |
* Goes over all the current checkboxes concerning the breakfast days, and |
175 |
* looks which ones are selected. |
176 |
* The selected ones are put in a Set, which is then returned to the method |
177 |
* caller. |
178 |
* @pre generateBreakfastOptions must be run ONCE before calling this |
179 |
* method. |
180 |
* @throws NullPointerException if the precondition wasn't met. |
181 |
* @return A Set containing all dates on which breakfast should be served. |
182 |
* An empty Set indicates no selected breakfast days. all breakfast days |
183 |
* occur at 9 o'clock in the morning. |
184 |
*/ |
185 |
public Set<Date> getSelectedBreakfastDays() { |
186 |
Set<Date> breakfastDays = new HashSet<>(); |
187 |
for(JCheckBox checkbox : this.breakfastDayFields) { |
188 |
if(checkbox.isSelected()) { |
189 |
// Extract information first |
190 |
String[] parts = checkbox.getText().split("\\/"); // Regex for "/" |
191 |
int day = Integer.parseInt(parts[0]); |
192 |
int month = Integer.parseInt(parts[1]); |
193 |
int year = Integer.parseInt(parts[2]); |
194 |
breakfastDays.add(new Date(year-1900, month-1, day, 8, 0, 0)); |
195 |
} |
196 |
} |
197 |
return breakfastDays; |
198 |
} |
199 |
|
200 |
/** |
201 |
* Update stored Reservation with displayed information. |
202 |
* This method reads all information displayed in the fields. |
203 |
* It will then update the Reservation with that data. |
204 |
* This method will not update the Reservation until all data is correctly |
205 |
* formatted. |
206 |
*/ |
207 |
public void updateReservation() { |
208 |
// Collect all data from the fields |
209 |
String name = this.nameField.getText(); |
210 |
if(name.isEmpty()) { |
211 |
this.window.messageDialog("Name mustn't be blank."); |
212 |
return; |
213 |
} |
214 |
Date beginDate = null, endDate = null; |
215 |
try { |
216 |
beginDate = new Date(this.beginDateField.getText()); |
217 |
System.out.println(beginDate.toGMTString()); |
218 |
endDate = new Date(this.endDateField.getText()); |
219 |
System.out.println(endDate.toGMTString()); |
220 |
} |
221 |
catch(Exception e) { |
222 |
this.window.messageDialog("Not all date fields were properly formatted."); |
223 |
return; |
224 |
} |
225 |
if(!beginDate.before(endDate)) { |
226 |
this.window.messageDialog("Begin date must come before end date."); |
227 |
return; |
228 |
} |
229 |
int people = (Integer)this.amountPeopleField.getValue(); |
230 |
String type = ""; |
231 |
for(int i=0; i<this.typeField.length; i++) { |
232 |
if(this.typeField[i].isSelected()) { |
233 |
type = this.typeField[i].getText(); |
234 |
break; |
235 |
} |
236 |
} |
237 |
Set<String> facilities = new HashSet<>(); |
238 |
if(this.showerField.isSelected()) { |
239 |
facilities.add("Shower"); |
240 |
} |
241 |
if(this.bathField.isSelected()) { |
242 |
facilities.add("Bath"); |
243 |
} |
244 |
if(this.minibarField.isSelected()) { |
245 |
facilities.add("Minibar"); |
246 |
} |
247 |
if(this.aircoField.isSelected()) { |
248 |
facilities.add("Airco"); |
249 |
} |
250 |
Set<Date> breakfastDays = this.getSelectedBreakfastDays(); |
251 |
// All data collected; save in Reservation. |
252 |
this.reservation.setGroupName(name); |
253 |
this.reservation.setPeople(people); |
254 |
this.reservation.setBeginDate(beginDate); |
255 |
this.reservation.setEndDate(endDate); |
256 |
this.reservation.setRoomType(type); |
257 |
this.reservation.setRoomFacilities(facilities); |
258 |
this.reservation.setBreakfastDays(breakfastDays); |
259 |
} |
260 |
|
261 |
/** |
262 |
* Start the addition of this Reservation to the system. |
263 |
* This method will check the current fields, and update the Reservation |
264 |
* with those values. In doing so, the validity of the values is checked |
265 |
* (formatting, begin date before end date, ...). |
266 |
* If everything is okay, the method will check if these changes are |
267 |
* possible in the current system; are there enough empty beds? |
268 |
* |
269 |
* If everything is okay, the changes will be propagated to the |
270 |
* Reservation's state, and (if it's a new Reservation) will be added to the |
271 |
* system's active Reservations. |
272 |
*/ |
273 |
public void addReservation() { |
274 |
// HACK: |
275 |
// I'm temporarily replacing the real Reservation with a fake one, as to |
276 |
// test whether there is a free Room. If so, we can return the real |
277 |
// Reservation and do the same thing. |
278 |
Reservation tempReservation = this.reservation; |
279 |
this.reservation = new Reservation(); |
280 |
this.updateReservation(); |
281 |
// XXX: To make sure that, if this is an active Reservation, it's not |
282 |
// counted as being active, we must temporarily remove it from the |
283 |
// active Reservations: |
284 |
if(this.rc.getReservations().contains(tempReservation)) { |
285 |
this.rc.cancelReservation(tempReservation); |
286 |
} |
287 |
// Now checking for a free Room: |
288 |
if(this.roc.getQualifiedRooms(this.reservation).isEmpty()) { |
289 |
boolean tryAgain = this.window.confirmDialog("No rooms met the requirements! Would you like to continue and change the parameters?"); |
290 |
if(tryAgain) { |
291 |
this.reservation = tempReservation; // Sanitizing what I made dirty =3 |
292 |
// We don't need to add the Reservation back, because, if we add |
293 |
// it later, it will be correct nonetheless. |
294 |
} |
295 |
else { |
296 |
this.removeReservation(); |
297 |
} |
298 |
} |
299 |
else { |
300 |
// We've found qualified Rooms and everything went well! So let's add |
301 |
// it. |
302 |
this.reservation = tempReservation; |
303 |
this.updateReservation(); |
304 |
Room room = this.roc.getQualifiedRoom(this.reservation); |
305 |
this.rc.addReservation(this.reservation, room); |
306 |
// Now closing the window, we're done here |
307 |
// Confirm and show price: |
308 |
int price = this.reservation.getPrice(room); |
309 |
this.window.messageDialog("Reservation confirmed! Price: " +String.valueOf(price)); |
310 |
this.window.close(); |
311 |
} |
312 |
} |
313 |
|
314 |
/** |
315 |
* Remove Reservation and the GUI. |
316 |
* Calling this method will remove the Reservation, followed by closing this |
317 |
* window. |
318 |
* If the Reservation is active (i.e. saved in the ReservationController), |
319 |
* it will be removed. |
320 |
* Any changes will be cancelled. |
321 |
*/ |
322 |
public void removeReservation() { |
323 |
if(this.rc.getReservations().contains(this.reservation)) { |
324 |
this.rc.cancelReservation(this.reservation); |
325 |
} |
326 |
this.window.close(); |
327 |
} |
328 |
} |
329 |