OOP2

ReservationView.java

1
import javax.swing.*;
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