Bed.java
1 |
|
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 |