OOP2

Bed.java

1
import java.util.Date;
2
import java.util.Map;
3
import java.util.HashMap;
4
5
import java.time.DateTimeException;
6
/**
7
 * Class representing a bed in the hostel.
8
 * Even though beds in a hostel could simply be an integer in a Room, these Beds
9
 * need to remember on what dates they are reserved.
10
 * @author Maarten Vangeneugden - 1438256
11
 */
12
public class Bed {
13
14
	/* Rationale:
15
	 * I know that a mapping is not necessarily the best solution for storing
16
	 * periods, because it doesn't offer built-in protection yadda yadda.
17
	 * However, that's Java's fault, as it doesn't provide a Pair<L,R> thing in
18
	 * the STL.
19
	 * The best solution is actually a collection of tuples: (Begin, End), but
20
	 * that doesn't exist in Java, and thus requires a custom implementation.
21
	 * All things considered, a Map is the least bad choice.
22
	 */
23
	private Map<Date, Date> reservedPeriods;
24
25
	public Bed() {
26
		this.reservedPeriods = new HashMap<>();
27
	}
28
29
	/**
30
	 * Reserves this Bed for the given period.
31
	 * This method will mark the given period for this Bed as "reserved", which
32
	 * can then be cancelled or queried later.
33
	 * @param begin The time where the reservation begins.
34
	 * @param end The time where the reservation ends.
35
	 * @pre No parameter may be a null pointer.
36
	 * @pre The given period mustn't overlap with a period already marked as
37
	 * reserved.
38
	 * @pre begin must come before end.
39
	 * @pre begin and end mustn't be equal.
40
	 * @post The given period will be marked as "Reserved", and will have to be
41
	 * manually cancelled/removed in order to reserve again.
42
	 * @throws NullPointerException if any parameter is a null pointer.
43
	 * @throws IllegalArgumentException if begin is equal to, or comes after
44
	 * end.
45
	 * @throws DateTimeException if the given period overlaps with an already
46
	 * reserved period.
47
	 */
48
	public void reservePeriod(Date begin, Date end) {
49
		if(!begin.before(end)) {
50
			throw new IllegalArgumentException("The begin date occurs after the end date.");
51
		}
52
		if(!this.isFree(begin, end)) {
53
			throw new DateTimeException("This period overlaps with a reserved period.");
54
		}
55
		// Contract validated, execute method
56
		this.reservedPeriods.put(begin, end);
57
	}
58
59
	/**
60
	 * Remove a previous registration from this Bed.
61
	 * This method will remove/cancel the given reservation period from the
62
	 * Bed, opening it up for reservation again.
63
	 * @param begin The time where the reservation begins.
64
	 * @param end The time where the reservation ends.
65
	 * @pre No parameter may be a null pointer.
66
	 * @pre The given period must already be marked as "Reserved" in this Bed.
67
	 * @pre begin must come before end.
68
	 * @pre begin and end mustn't be equal.
69
	 * @post The given period will lose its "Reserved" mark, allowing the period
70
	 * to be reserved again.
71
	 * @throws NullPointerException if any parameter is a null pointer.
72
	 * @throws IllegalArgumentException if begin is equal to, or comes after
73
	 * end; or, if the given period is not reserved.
74
	 */
75
	public void removeReservationPeriod(Date begin, Date end) {
76
		if(!begin.before(end)) {
77
			throw new IllegalArgumentException("The begin date occurs after the end date.");
78
		}
79
		if(!this.isFree(begin, end)) {
80
			throw new DateTimeException("This period overlaps with a reserved period.");
81
		}
82
		// Contract partially validated; further validation occurs while looking
83
		// for the reservation.
84
		// XXX: Check if Java correctly handles equality: 2 different Date
85
		// objects with the same date representation should be equal!
86
		boolean reservationFound = this.reservedPeriods.remove(begin, end);
87
		if(!reservationFound) {
88
			throw new IllegalArgumentException("The given period was not marked as reserved.");
89
		}
90
	}
91
		
92
	/**
93
	 * Checks whether this Bed can be reserved in the given period.
94
	 * Use this method whenever you need to inform yourself about any
95
	 * conflicting reservation period.
96
	 * @param begin The time where the reservation begins.
97
	 * @param end The time where the reservation ends.
98
	 * @pre No parameter must be a null pointer.
99
	 * @pre begin must come before end.
100
	 * @pre begin and end mustn't be equal.
101
	 * @throws NullPointerException if any parameter is a null pointer.
102
	 * @throws IllegalArgumentException if begin is equal to, or comes after
103
	 * end.
104
	 * @return True if the given period does not overlap with any reservation, false otherwise.
105
	 */
106
	public boolean isFree(Date begin, Date end) {
107
		if(!begin.before(end)) {
108
			throw new IllegalArgumentException("The begin date occurs after the end date.");
109
		}
110
		// Contract validated, execute method
111
		for(Map.Entry<Date, Date> reservedPeriod: this.reservedPeriods.entrySet()) {
112
			Date reservedBegin = reservedPeriod.getKey();
113
			Date reservedEnd = reservedPeriod.getValue();
114
			/* Forbidden possibilities:
115
			 * (A,B = reserved; X,Y = requested)
116
			 * X-A-Y-B / A-X-B-Y  -  Begins or ends in a reserved period
117
			 * X-A-B-Y  -  Complete overlapping of reserved period
118
			 * Allowed possibilities:
119
			 * A-B-X-Y / X-Y-A-B  -  No overlapping
120
			 */
121
			if((begin.after(reservedBegin) && begin.before(reservedEnd)) ||
122
			   (end.after(reservedBegin) && end.before(reservedEnd))) {
123
				// Triggered if any forbidden structure is detected
124
				return false;
125
			}
126
		}
127
		return true; // No overlapping found
128
	}
129
130
	/**
131
	 * Checks whether this Bed has open reservation periods.
132
	 * @return True if this Bed has reserved periods, false otherwise.
133
	 */
134
	public boolean hasReservations() {
135
		return !this.reservedPeriods.isEmpty();
136
	}
137
}
138