aboutsummaryrefslogtreecommitdiff
path: root/lib/calendar/CalendarColumn.php
blob: 78a38090e6d0d7bb1cd2b13e468681268c00dcb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
<?php
# Lifter010: TODO
/**
 * CalendarColumn.php - a column for a CalendarView
 *
 * This class represents an entry-column like "monday" in the calendar
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * @author      Rasmus Fuhse <fuhse@data-quest.de>
 * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
 * @category    Stud.IP
 *
 * @deprecated since Stud.IP 5.5
 */

class CalendarColumn
{
    protected static $number = 0;
    protected $title = "";
    protected $id = "";
    public    $entries = [];
    protected $url = "";
    protected $grouped = false;
    protected $sorted_entries = null;

    /**
     * creates instance of type CalendarColumn
     *
     * @param string  $id  necessary if you want JavaScript enabled for this calendar
     * @return CalendarColumn
     */
    static public function create($id = null) {
        $column = new CalendarColumn($id);
        return $column;
    }

    /**
     * constructor
     *
     * @param string  $id  necessary if you want JavaScript enabled for this column
     */
    public function __construct($id = null) {
        $id !== null || $id = md5(uniqid("CalendarColumn_".self::$number++));
        $this->setId($id);
    }

    /**
     * returns the id of the column
     *
     * @return string
     */
    public function getId() {
        return $this->id;
    }

    /**
     * sets the id for this column, which is only necessary if you want
     * Javascript to be enabled for this calendar
     *
     * @param string  $id  new id for this column
     * @return CalendarColumn
     */
    public function setId($id) {
        $this->id = $id;
        return $this;
    }

    /**
     * sets a title like "monday" for this column, which will be displayed in the calendar
     *
     * @param string  $new_title  new title
     * @return CalendarColumn
     */
    public function setTitle($new_title) {
        $this->title = $new_title;
        return $this;
    }

    /**
     * returns the title of this column like "monday"
     *
     * @return string title of column
     */
    public function getTitle() {
        return $this->title;
    }

    /**
     * sets the url to be directed to when clicking on the title of the column.
     * Usually this is a single-day-view of the calendar.
     *
     * @param string  $new_url  an url
     * @return CalendarColumn
     */
    public function setURL($new_url) {
        $this->url = $new_url;
        return $this;
    }

    /**
     * returns the URL of the column (see setURL)
     *
     * @return string an url
     */
    public function getURL() {
        return $this->url;
    }

    /**
     * adds a new entry in the column. The entry needs to be an associative array
     * with parameters as follows:
     *
     * @param array  $entry_array  associative array for an entry in the column like
     * array (
     *    'color' => the color in hex (css-like, without the #)
     *    'start' => the (start hour * 100) + (start minute)
     *    'end'   => the (end hour * 100) + (end minute)
     *    'title' => the entry`s title
     *    'content' => whatever shall be the content of the entry as a string
     * )
     */
    public function addEntry($entry_array) {
        if (!isset($entry_array['start']) || !isset($entry_array['end'])
                || !isset($entry_array['title']) ) {
            throw new InvalidArgumentException('The entry '. print_r($entry_array, true) .' does not follow the specifications!');
        } else {
            $this->entries[] = $entry_array;
        }
        return $this;
    }

    /**
     * adds many entries to the column. For the syntax of an entry see addEntry()
     *
     * @param array  $entries_array
     * @return CalendarColumn
     */
    public function addEntries($entries_array = []) {
        foreach ($entries_array as $entry_array) {
            $this->addEntry($entry_array);
        }
        return $this;
    }

    /**
     * returns all entries of this column
     *
     * @return array of arrays like
     * array (
     *    'color' => the color in hex (css-like, without the #)
     *    'start' => the (start hour * 100) + (start minute)
     *    'end'   => the (end hour * 100) + (end minute)
     *    'title' => the entry`s title
     *    'content' => whatever shall be the content of the entry as a string
     * )
     */
    public function getEntries() {
        return $this->entries;
    }

    /**
     * deletes all entries of this column. So the only way to edit an entry is
     * getting all entries with getEntries, edit this entry, eraseEntries() and
     * addEntries(). Not very short, but at least it works.
     *
     * @return CalendarColumn
     */
    public function eraseEntries() {
        $this->entries = [];
        return $this;
    }

    /**
     * Returns an array of calendar-entries, grouped by day and additionally grouped by same start and end
     * if groupEntries(true) has been called.
     *
     * @return  mixed  the (double-)grouped entries
     */
    public function getGroupedEntries()
    {
        if (empty($this->sorted_entries)) {
            if ($this->isGrouped()) {
                $this->sorted_entries = $this->sortAndGroupEntries();
            } else {
                $this->sorted_entries = $this->sortEntries();
            }
        }

        return $this->sorted_entries;
    }

    /**
     * sorts and groups entries and returns them
     * only used by columns with grouped entries like instituteschedules
     *
     * @return array
     */
    public function sortAndGroupEntries()
    {
        $day = $this->getTitle();

        $entries_for_column = $this->getEntries();
        $result = [];
        $new_entries = [];

        // 1st step - group all entries with the same duration
        foreach ($entries_for_column as $entry_id => $entry) {
            $new_entries[$entry['start'] .'_'. $entry['end']][] = $entry;
        }

        $column = 0;

        // 2nd step - optimize the groups
        while (sizeof($new_entries) > 0) {
            $lstart = 2399; $lend = 0;

            foreach ($new_entries as $time => $grouped_entries) {
                list($start, $end) = explode('_', $time);
                if ($start < $lstart /*&& ($end - $start) >= ($lend - $lstart)*/ )  {
                    $lstart = $start;
                    $lend = $end;
                }
            }

            $result['col_'. $column][] = $new_entries[$lstart .'_'. $lend];
            unset($new_entries[$lstart .'_'. $lend]);

            $hit = true;

            while ($hit) {
                $hit = false;
                $hstart = 2399; $hend = 2399;

                // check, if there is something, that can be placed after
                foreach ($new_entries as $time => $grouped_entries) {
                    list($start, $end) = explode('_', $time);

                    if ( ($start >= $lend) && ($start < $hstart) ) {
                        $hstart = $start;
                        $hend = $end;
                        $hit = true;
                    }
                }

                if ($hit) {
                    $lend = $hend;
                    $result['col_'. $column][] = $new_entries[$hstart .'_'. $hend];
                    unset($new_entries[$hstart .'_'. $hend]);
                }
            }

            $column++;
        } // 2nd step

        return $result;

    }

    /**
     * sorts entries and returns them
     *
     * @return array
     */
    public function sortEntries()
    {
        $entries_for_column = $this->getEntries();

        $result = [];
        $column = 0;

        // 2nd step - optimize the groups
        while (sizeof($entries_for_column) > 0) {
            $lstart = 2399; $lend = 0; $lkey = null;

            foreach ($entries_for_column as $entry_key => $entry) {
                if ($entry['start'] < $lstart /*&& ($end - $start) >= ($lend - $lstart)*/ )  {
                    $lstart = $entry['start'];
                    $lend = $entry['end'];
                    $lkey = $entry_key;
                }
            }

            $result['col_'. $column][] = $entries_for_column[$lkey];
            unset($entries_for_column[$lkey]);

            $hit = true;

            while ($hit) {
                $hit = false;
                $hstart = 2399; $hend = 2399; $hkey = null;

                // check, if there is something, that can be placed after
                foreach ($entries_for_column as $entry_key => $entry) {
                    if ( ($entry['start'] >= $lend) && ($entry['start'] < $hstart) ) {
                        // && (($end - $start) > ($hend - $hstart)) ) {
                        $hstart = $entry['start'];
                        $hend = $entry['end'];
                        $hkey = $entry_key;
                        $hit = true;
                    }
                }

                if ($hit) {
                    $lend = $hend;
                    $result['col_'. $column][] = $entries_for_column[$hkey];
                    unset($entries_for_column[$hkey]);
                }
            }

            $column++;
        } // 2nd step
        return $result;

    }

    /**
     * returns a matrix that tells the number of entries for a given timeslot
     *
     * @return array
     */
    public function getMatrix() {
        $group_matrix = [];
        foreach ($this->getGroupedEntries() as $groups) {
            foreach ($groups as $group) {
                if (isset($group[0]) && is_array($group[0])) {
                    $data = $group[0];
                } else {
                    $data = $group;
                }

                for ($i = floor($data['start'] / 100); $i <= floor($data['end'] / 100); $i++) {
                    for ($j = 0; $j < 60; $j++) {
                        if (($i * 100) + $j >= $data['start'] && ($i * 100) + $j < $data['end']) {
                            if (!isset($group_matrix[$i * 100 + $j])) {
                                $group_matrix[$i * 100 + $j] = 0;
                            }
                            $group_matrix[$i * 100 + $j]++;
                        }
                    }
                }
            }
        }
        return $group_matrix;
    }

    /**
     * check, if a grouped view of the entries is requested
     *
     * @return bool true if grouped, false otherwise
     */
    public function isGrouped()
    {
        return $this->grouped;
    }

    /**
     * Call this function th enable/disable the grouping of entries with the same start and end.
     *
     * @param  bool  $group optional, defaults to true
     * @return void
     */
    public function groupEntries($grouped = true)
    {
        $this->grouped = $grouped;
    }

}