Completed
Push — master ( b93e82...a1a5c6 )
by WEBEWEB
01:50
created

TimeSlot::hasInnerJoin()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 4
nc 4
nop 2
1
<?php
2
3
/**
4
 * This file is part of the core-library package.
5
 *
6
 * (c) 2018 WEBEWEB
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace WBW\Library\Core\Model\Organizer;
13
14
use DateTime;
15
use WBW\Library\Core\Exception\Argument\IllegalArgumentException;
16
use WBW\Library\Core\Helper\Argument\DateTimeHelper;
17
18
/**
19
 * Time slot.
20
 *
21
 * @author webeweb <https://github.com/webeweb/>
22
 * @package WBW\Library\Core\Model\Organizer
23
 */
24
class TimeSlot {
25
26
    /**
27
     * End date.
28
     *
29
     * @var DateTime
30
     */
31
    private $endDate;
32
33
    /**
34
     * StartDate.
35
     *
36
     * @var DateTime
37
     */
38
    private $startDate;
39
40
    /**
41
     * Time slots.
42
     *
43
     * @var TimeSlot[]
44
     */
45
    private $timeSlots;
46
47
    /**
48
     * Constructor.
49
     *
50
     * @param DateTime $startDate The start date.
51
     * @param DateTime $endDate The end date.
52
     * @throws IllegalArgumentException Throws an illegal argument exception.
53
     */
54
    public function __construct(DateTime $startDate, DateTime $endDate) {
55
        if ($endDate < $startDate) {
56
            throw new IllegalArgumentException("The end date must be greater than start date");
57
        }
58
        $this->setEndDate($endDate);
59
        $this->setStartDate($startDate);
60
        $this->setTimeSlots([]);
61
    }
62
63
    /**
64
     * Add a time slot.
65
     *
66
     * @param TimeSlot $timeSlot The time slot.
67
     * @return TimeSlot Returns this time slot.
68
     */
69
    public function addTimeSlot(TimeSlot $timeSlot) {
70
        $this->timeSlots[] = $timeSlot;
71
        return $this;
72
    }
73
74
    /**
75
     * Determines if a time slot A contains a time slot b.
76
     *
77
     * @param TimeSlot $a The time slot A.
78
     * @param TimeSlot $b The time slot B.
79
     * @return bool Returns true in case of success, false otherwise.
80
     */
81
    public static function contains(TimeSlot $a, TimeSlot $b) {
82
        $c1 = DateTimeHelper::isBetween($b->getStartDate(), $a->getStartDate(), $a->getEndDate());
83
        $c2 = DateTimeHelper::isBetween($b->getEndDate(), $a->getStartDate(), $a->getEndDate());
84
        return $c1 && $c2;
85
    }
86
87
    /**
88
     * Determines if two time slots are equals.
89
     *
90
     * @param TimeSlot $a The time slot A.
91
     * @param TimeSlot $b The time slot B.
92
     * @return boolean Returns true in case of success, false otherwise.
93
     */
94
    public static function equals(TimeSlot $a, TimeSlot $b) {
95
96
        // Compare the start dates.
97
        if (false === DateTimeHelper::equals($a->getStartDate(), $b->getStartDate())) {
98
            return false;
99
        }
100
101
        // Compare the end dates.
102
        if (false === DateTimeHelper::equals($a->getEndDate(), $b->getEndDate())) {
103
            return false;
104
        }
105
106
        // Compare the time slots count.
107
        if (count($a->getTimeSlots()) !== count($b->getTimeSlots())) {
108
            return false;
109
        }
110
111
        // Handle each time slot.
112
        for ($i = count($a->getTimeSlots()) - 1; 0 <= $i; --$i) {
113
            if (false === self::equals($a->getTimeSlots()[$i], $b->getTimeSlots()[$i])) {
114
                return false;
115
            }
116
        }
117
118
        //
119
        return true;
120
    }
121
122
    /**
123
     * Full join two time slots.
124
     *
125
     * @param TimeSlot $a The time slot A.
126
     * @param TimeSlot $b The time slot B.
127
     * @return TimeSlot|null Returns a time slot in case of success, null otherwise.
128
     */
129
    public static function fullJoin(TimeSlot $a, TimeSlot $b) {
130
131
        // Has inner  ?
132
        if (false === self::hasInnerJoin($a, $b)) {
133
            return null;
134
        }
135
136
        // Initialize the date/times.
137
        $startDate = DateTimeHelper::getSmaller($a->getStartDate(), $b->getStartDate());
138
        $endDate   = DateTimeHelper::getGreater($a->getEndDate(), $b->getEndDate());
139
140
        // Return the time slot.
141
        return new TimeSlot(clone $startDate, clone $endDate);
142
    }
143
144
    /**
145
     * Get the end date.
146
     *
147
     * @return DateTime Returns the end date.
148
     */
149
    public function getEndDate() {
150
        return $this->endDate;
151
    }
152
153
    /**
154
     * Get the start date.
155
     *
156
     * @return DateTime Returns the start date.
157
     */
158
    public function getStartDate() {
159
        return $this->startDate;
160
    }
161
162
    /**
163
     * Get the time slots.
164
     *
165
     * @return TimeSlot[] Returns the time slots.
166
     */
167
    public function getTimeSlots() {
168
        return $this->timeSlots;
169
    }
170
171
    /**
172
     * Determines if a time slot A has full join with time slot B.
173
     *
174
     * @param TimeSlot $a The time slot A.
175
     * @param TimeSlot $b The time slot B.
176
     * @return bool Returns true in case of success, false otherwise.
177
     */
178
    public static function hasFullJoin(TimeSlot $a, TimeSlot $b) {
179
        return true === self::hasInnerJoin($a, $b);
180
    }
181
182
    /**
183
     * Determines if a time slot A has an inner join with time slot B.
184
     *
185
     * @param TimeSlot $a The time slot A.
186
     * @param TimeSlot $b The time slot B.
187
     * @return bool Returns true in case of success, false otherwise.
188
     */
189
    public static function hasInnerJoin(TimeSlot $a, TimeSlot $b) {
190
        $c1 = DateTimeHelper::isBetween($b->getStartDate(), $a->getStartDate(), $a->getEndDate());
191
        $c2 = DateTimeHelper::isBetween($b->getEndDate(), $a->getStartDate(), $a->getEndDate());
192
        $c3 = DateTimeHelper::isBetween($a->getStartDate(), $b->getStartDate(), $b->getEndDate());
193
        $c4 = DateTimeHelper::isBetween($a->getEndDate(), $b->getStartDate(), $b->getEndDate());
194
        return $c1 || $c2 || $c3 || $c4;
195
    }
196
197
    /**
198
     * Inner join two time slots.
199
     *
200
     * @param TimeSlot $a The time slot A.
201
     * @param TimeSlot $b The time slot B.
202
     * @return TimeSlot|null Returns a time slot in case of success, null otherwise.
203
     */
204
    public static function innerJoin(TimeSlot $a, TimeSlot $b) {
205
206
        // Has inner join ?
207
        if (false === self::hasInnerJoin($a, $b)) {
208
            return null;
209
        }
210
211
        // Initialize the date/times.
212
        $startDate = DateTimeHelper::getGreater($a->getStartDate(), $b->getStartDate());
213
        $endDate   = DateTimeHelper::getSmaller($a->getEndDate(), $b->getEndDate());
214
215
        // Return the time slot.
216
        return new TimeSlot(clone $startDate, clone $endDate);
217
    }
218
219
    /**
220
     * Left join two time slots.
221
     *
222
     * @param TimeSlot $a The time slot A.
223
     * @param TimeSlot $b The time slot B.
224
     * @return TimeSlot Returns the time slot in case of success, null otherwise.
225
     */
226
    public static function leftJoin(TimeSlot $a, TimeSlot $b) {
227
228
        // Has inner join ?
229
        if (false === self::hasInnerJoin($a, $b)) {
230
            return null;
231
        }
232
233
        // Return the time slot.
234
        return new TimeSlot(clone $a->getStartDate(), clone $a->getEndDate());
235
    }
236
237
    /**
238
     * Left join two time slots without time slot B intersection.
239
     *
240
     * @param TimeSlot $a The time slot A.
241
     * @param TimeSlot $b The time slot B.
242
     * @return TimeSlot[] Returns the time slot in case of success, null otherwise.
243
     */
244
    public static function leftJoinWithout(TimeSlot $a, TimeSlot $b) {
245
246
        // Has inner join ?
247
        if (false === self::hasInnerJoin($a, $b) || true === self::contains($b, $a)) {
248
            return null;
249
        }
250
251
        // Contains ?
252
        if (true === self::contains($a, $b)) {
253
            return [
254
                new Timeslot(clone $a->getStartDate(), clone $b->getStartDate()),
255
                new Timeslot(clone $b->getEndDate(), clone $a->getEndDate()),
256
            ];
257
        }
258
259
        // Initialize the date/times.
260
        $startDate = true === DateTimeHelper::isLessThan($a->getStartDate(), $b->getStartDate()) ? $a->getStartDate() : $b->getEndDate();
261
        $endDate   = true === DateTimeHelper::isGreaterThan($a->getEndDate(), $b->getEndDate()) ? $a->getEndDate() : $b->getStartDate();
262
263
        // Return the time slot.
264
        return [
265
            new TimeSlot(clone $startDate, clone $endDate),
266
        ];
267
    }
268
269
    /**
270
     * Remove a time slot.
271
     *
272
     * @param TimeSlot $timeSlot The time slot.
273
     * @return TimeSlot Returns this time slot.
274
     */
275
    public function removeTimeSlot(TimeSlot $timeSlot) {
276
        for ($i = count($this->timeSlots) - 1; 0 <= $i; --$i) {
277
            if (true === self::equals($timeSlot, $this->timeSlots[$i])) {
278
                unset($this->timeSlots[$i]);
279
                break;
280
            }
281
        }
282
        return $this;
283
    }
284
285
    /**
286
     * Set the end date.
287
     *
288
     * @param DateTime $endDate The end date.
289
     * @return TimeSlot Returns this time slot.
290
     */
291
    protected function setEndDate(DateTime $endDate) {
292
        $this->endDate = $endDate;
293
        return $this;
294
    }
295
296
    /**
297
     * Set the start date.
298
     *
299
     * @param DateTime $startDate The start date.
300
     * @return TimeSlot Returns this time slot.
301
     */
302
    protected function setStartDate(DateTime $startDate) {
303
        $this->startDate = $startDate;
304
        return $this;
305
    }
306
307
    /**
308
     * Set the time slots.
309
     *
310
     * @param TimeSlot[] $timeSlots The time slots.
311
     * @return TimeSlot Returns this time slot.
312
     */
313
    protected function setTimeSlots(array $timeSlots) {
314
        $this->timeSlots = $timeSlots;
315
        return $this;
316
    }
317
318
}
319