Completed
Push — master ( 7eeb67...03a48a )
by WEBEWEB
02:00
created

TimeSlot::fullJoinWithout()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.2888
c 0
b 0
f 0
cc 5
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 (false === DateTimeHelper::isLessThan($startDate, $endDate)) {
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 full join ?
132
        if (false === self::hasFullJoin($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
     * Full join two time slots without time slots intersection.
146
     *
147
     * @param TimeSlot $a The time slot A.
148
     * @param TimeSlot $b The time slot B.
149
     * @return TimeSlot[] Returns the time slots in case of success, null otherwise.
150
     */
151
    public static function fullJoinWithout(TimeSlot $a, TimeSlot $b) {
152
153
        // Initialize the time slots.
154
        $leftJoins  = self::leftJoinWithout($a, $b);
155
        $rightJoins = self::rightJoinWithout($a, $b);
156
157
        // Check the time slots.
158
        if (null === $leftJoins && null === $rightJoins) {
159
            return null;
160
        }
161
        if (null === $leftJoins) {
162
            return $rightJoins;
163
        }
164
        if (null === $rightJoins) {
165
            return $leftJoins;
166
        }
167
168
        // Return the time slots.
169
        return array_merge($leftJoins, $rightJoins);
170
    }
171
172
    /**
173
     * Get the duration.
174
     *
175
     * @return int Returns the duration.
176
     */
177
    public function getDuration() {
178
        return DateTimeHelper::getDuration($this->getStartDate(), $this->getEndDate());
179
    }
180
181
    /**
182
     * Get the end date.
183
     *
184
     * @return DateTime Returns the end date.
185
     */
186
    public function getEndDate() {
187
        return $this->endDate;
188
    }
189
190
    /**
191
     * Get the start date.
192
     *
193
     * @return DateTime Returns the start date.
194
     */
195
    public function getStartDate() {
196
        return $this->startDate;
197
    }
198
199
    /**
200
     * Get the time slots.
201
     *
202
     * @return TimeSlot[] Returns the time slots.
203
     */
204
    public function getTimeSlots() {
205
        return $this->timeSlots;
206
    }
207
208
    /**
209
     * Determines if a time slot A has full join with time slot B.
210
     *
211
     * @param TimeSlot $a The time slot A.
212
     * @param TimeSlot $b The time slot B.
213
     * @return bool Returns true in case of success, false otherwise.
214
     */
215
    public static function hasFullJoin(TimeSlot $a, TimeSlot $b) {
216
        return true === self::hasInnerJoin($a, $b);
217
    }
218
219
    /**
220
     * Determines if a time slot A has an inner join with time slot B.
221
     *
222
     * @param TimeSlot $a The time slot A.
223
     * @param TimeSlot $b The time slot B.
224
     * @return bool Returns true in case of success, false otherwise.
225
     */
226
    public static function hasInnerJoin(TimeSlot $a, TimeSlot $b) {
227
        $c1 = DateTimeHelper::isBetween($b->getStartDate(), $a->getStartDate(), $a->getEndDate());
228
        $c2 = DateTimeHelper::isBetween($b->getEndDate(), $a->getStartDate(), $a->getEndDate());
229
        $c3 = DateTimeHelper::isBetween($a->getStartDate(), $b->getStartDate(), $b->getEndDate());
230
        $c4 = DateTimeHelper::isBetween($a->getEndDate(), $b->getStartDate(), $b->getEndDate());
231
        return $c1 || $c2 || $c3 || $c4;
232
    }
233
234
    /**
235
     * Inner join two time slots.
236
     *
237
     * @param TimeSlot $a The time slot A.
238
     * @param TimeSlot $b The time slot B.
239
     * @return TimeSlot|null Returns a time slot in case of success, null otherwise.
240
     */
241
    public static function innerJoin(TimeSlot $a, TimeSlot $b) {
242
243
        // Has inner join ?
244
        if (false === self::hasInnerJoin($a, $b)) {
245
            return null;
246
        }
247
248
        // Initialize the date/times.
249
        $startDate = DateTimeHelper::getGreater($a->getStartDate(), $b->getStartDate());
250
        $endDate   = DateTimeHelper::getSmaller($a->getEndDate(), $b->getEndDate());
251
252
        // Return the time slot.
253
        return new TimeSlot(clone $startDate, clone $endDate);
254
    }
255
256
    /**
257
     * Left join two time slots.
258
     *
259
     * @param TimeSlot $a The time slot A.
260
     * @param TimeSlot $b The time slot B.
261
     * @return TimeSlot Returns the time slot in case of success, null otherwise.
262
     */
263
    public static function leftJoin(TimeSlot $a, TimeSlot $b) {
264
265
        // Has inner join ?
266
        if (false === self::hasInnerJoin($a, $b)) {
267
            return null;
268
        }
269
270
        // Return the time slot.
271
        return new TimeSlot(clone $a->getStartDate(), clone $a->getEndDate());
272
    }
273
274
    /**
275
     * Left join two time slots without time slot B intersection.
276
     *
277
     * @param TimeSlot $a The time slot A.
278
     * @param TimeSlot $b The time slot B.
279
     * @return TimeSlot[] Returns the time slots in case of success, null otherwise.
280
     */
281
    public static function leftJoinWithout(TimeSlot $a, TimeSlot $b) {
282
283
        // Has inner join ?
284
        if (false === self::hasInnerJoin($a, $b) || true === self::contains($b, $a)) {
285
            return null;
286
        }
287
288
        // Contains ?
289
        if (true === self::contains($a, $b)) {
290
            return [
291
                new Timeslot(clone $a->getStartDate(), clone $b->getStartDate()),
292
                new Timeslot(clone $b->getEndDate(), clone $a->getEndDate()),
293
            ];
294
        }
295
296
        // Initialize the date/times.
297
        $startDate = true === DateTimeHelper::isLessThan($a->getStartDate(), $b->getStartDate()) ? $a->getStartDate() : $b->getEndDate();
298
        $endDate   = true === DateTimeHelper::isGreaterThan($a->getEndDate(), $b->getEndDate()) ? $a->getEndDate() : $b->getStartDate();
299
300
        // Return the time slots.
301
        return [
302
            new TimeSlot(clone $startDate, clone $endDate),
303
        ];
304
    }
305
306
    /**
307
     * Remove a time slot.
308
     *
309
     * @param TimeSlot $timeSlot The time slot.
310
     * @return TimeSlot Returns this time slot.
311
     */
312
    public function removeTimeSlot(TimeSlot $timeSlot) {
313
        for ($i = count($this->timeSlots) - 1; 0 <= $i; --$i) {
314
            if (true === self::equals($timeSlot, $this->timeSlots[$i])) {
315
                unset($this->timeSlots[$i]);
316
                break;
317
            }
318
        }
319
        return $this;
320
    }
321
322
    /**
323
     * Right join two time slots.
324
     *
325
     * @param TimeSlot $a The time slot A.
326
     * @param TimeSlot $b The time slot B.
327
     * @return TimeSlot Returns the time slot in case of success, null otherwise.
328
     */
329
    public static function rightJoin(TimeSlot $a, TimeSlot $b) {
330
        return self::leftJoin($b, $a);
331
    }
332
333
    /**
334
     * Right join two time slots without time slot B intersection.
335
     *
336
     * @param TimeSlot $a The time slot A.
337
     * @param TimeSlot $b The time slot B.
338
     * @return TimeSlot[] Returns the time slots in case of success, null otherwise.
339
     */
340
    public static function rightJoinWithout(TimeSlot $a, TimeSlot $b) {
341
        return self::leftJoinWithout($b, $a);
342
    }
343
344
    /**
345
     * Set the end date.
346
     *
347
     * @param DateTime $endDate The end date.
348
     * @return TimeSlot Returns this time slot.
349
     */
350
    protected function setEndDate(DateTime $endDate) {
351
        $this->endDate = $endDate;
352
        return $this;
353
    }
354
355
    /**
356
     * Set the start date.
357
     *
358
     * @param DateTime $startDate The start date.
359
     * @return TimeSlot Returns this time slot.
360
     */
361
    protected function setStartDate(DateTime $startDate) {
362
        $this->startDate = $startDate;
363
        return $this;
364
    }
365
366
    /**
367
     * Set the time slots.
368
     *
369
     * @param TimeSlot[] $timeSlots The time slots.
370
     * @return TimeSlot Returns this time slot.
371
     */
372
    protected function setTimeSlots($timeSlots) {
373
        $this->timeSlots = $timeSlots;
374
        return $this;
375
    }
376
377
}
378