Route and Results buttons updated.
[speedfreak] / Server / system / libraries / Calendar.php
1 <?php defined('SYSPATH') OR die('No direct access allowed.');
2 /**
3  * Calendar creation library.
4  *
5  * $Id: Calendar.php 3769 2008-12-15 00:48:56Z zombor $
6  *
7  * @package    Calendar
8  * @author     Kohana Team
9  * @copyright  (c) 2007-2008 Kohana Team
10  * @license    http://kohanaphp.com/license.html
11  */
12 class Calendar_Core extends Event_Subject {
13
14         // Start the calendar on Sunday by default
15         public static $start_monday = FALSE;
16
17         // Month and year to use for calendaring
18         protected $month;
19         protected $year;
20
21         // Week starts on Sunday
22         protected $week_start = 0;
23
24         // Observed data
25         protected $observed_data;
26
27         /**
28          * Returns an array of the names of the days, using the current locale.
29          *
30          * @param   integer  left of day names
31          * @return  array
32          */
33         public static function days($length = TRUE)
34         {
35                 // strftime day format
36                 $format = ($length > 3) ? '%A' : '%a';
37
38                 // Days of the week
39                 $days = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
40
41                 if (Calendar::$start_monday === TRUE)
42                 {
43                         // Push Sunday to the end of the days
44                         array_push($days, array_shift($days));
45                 }
46
47                 if (strpos(Kohana::config('locale.language.0'), 'en') !== 0)
48                 {
49                         // This is a bit awkward, but it works properly and is reliable
50                         foreach ($days as $i => $day)
51                         {
52                                 // Convert the English names to i18n names
53                                 $days[$i] = strftime($format, strtotime($day));
54                         }
55                 }
56
57                 if (is_int($length) OR ctype_digit($length))
58                 {
59                         foreach ($days as $i => $day)
60                         {
61                                 // Shorten the days to the expected length
62                                 $days[$i] = utf8::substr($day, 0, $length);
63                         }
64                 }
65
66                 return $days;
67         }
68
69         /**
70          * Create a new Calendar instance. A month and year can be specified.
71          * By default, the current month and year are used.
72          *
73          * @param   integer  month number
74          * @param   integer  year number
75          * @return  object
76          */
77         public static function factory($month = NULL, $year = NULL)
78         {
79                 return new Calendar($month, $year);
80         }
81
82         /**
83          * Create a new Calendar instance. A month and year can be specified.
84          * By default, the current month and year are used.
85          *
86          * @param   integer  month number
87          * @param   integer  year number
88          * @return  void
89          */
90         public function __construct($month = NULL, $year = NULL)
91         {
92                 empty($month) and $month = date('n'); // Current month
93                 empty($year)  and $year  = date('Y'); // Current year
94
95                 // Set the month and year
96                 $this->month = (int) $month;
97                 $this->year  = (int) $year;
98
99                 if (Calendar::$start_monday === TRUE)
100                 {
101                         // Week starts on Monday
102                         $this->week_start = 1;
103                 }
104         }
105
106         /**
107          * Allows fetching the current month and year.
108          *
109          * @param   string  key to get
110          * @return  mixed
111          */
112         public function __get($key)
113         {
114                 if ($key === 'month' OR $key === 'year')
115                 {
116                         return $this->$key;
117                 }
118         }
119
120         /**
121          * Calendar_Event factory method.
122          *
123          * @param   string  unique name for the event
124          * @return  object  Calendar_Event
125          */
126         public function event($name = NULL)
127         {
128                 return new Calendar_Event($this);
129         }
130
131         /**
132          * Calendar_Event factory method.
133          *
134          * @chainable
135          * @param   string  standard event type
136          * @return  object
137          */
138         public function standard($name)
139         {
140                 switch ($name)
141                 {
142                         case 'today':
143                                 // Add an event for the current day
144                                 $this->attach($this->event()->condition('timestamp', strtotime('today'))->add_class('today'));
145                         break;
146                         case 'prev-next':
147                                 // Add an event for padding days
148                                 $this->attach($this->event()->condition('current', FALSE)->add_class('prev-next'));
149                         break;
150                         case 'holidays':
151                                 // Base event
152                                 $event = $this->event()->condition('current', TRUE)->add_class('holiday');
153
154                                 // Attach New Years
155                                 $holiday = clone $event;
156                                 $this->attach($holiday->condition('month', 1)->condition('day', 1));
157
158                                 // Attach Valentine's Day
159                                 $holiday = clone $event;
160                                 $this->attach($holiday->condition('month', 2)->condition('day', 14));
161
162                                 // Attach St. Patrick's Day
163                                 $holiday = clone $event;
164                                 $this->attach($holiday->condition('month', 3)->condition('day', 17));
165
166                                 // Attach Easter
167                                 $holiday = clone $event;
168                                 $this->attach($holiday->condition('easter', TRUE));
169
170                                 // Attach Memorial Day
171                                 $holiday = clone $event;
172                                 $this->attach($holiday->condition('month', 5)->condition('day_of_week', 1)->condition('last_occurrence', TRUE));
173
174                                 // Attach Independance Day
175                                 $holiday = clone $event;
176                                 $this->attach($holiday->condition('month', 7)->condition('day', 4));
177
178                                 // Attach Labor Day
179                                 $holiday = clone $event;
180                                 $this->attach($holiday->condition('month', 9)->condition('day_of_week', 1)->condition('occurrence', 1));
181
182                                 // Attach Halloween
183                                 $holiday = clone $event;
184                                 $this->attach($holiday->condition('month', 10)->condition('day', 31));
185
186                                 // Attach Thanksgiving
187                                 $holiday = clone $event;
188                                 $this->attach($holiday->condition('month', 11)->condition('day_of_week', 4)->condition('occurrence', 4));
189
190                                 // Attach Christmas
191                                 $holiday = clone $event;
192                                 $this->attach($holiday->condition('month', 12)->condition('day', 25));
193                         break;
194                         case 'weekends':
195                                 // Weekend events
196                                 $this->attach($this->event()->condition('weekend', TRUE)->add_class('weekend'));
197                         break;
198                 }
199
200                 return $this;
201         }
202
203         /**
204          * Returns an array for use with a view. The array contains an array for
205          * each week. Each week contains 7 arrays, with a day number and status:
206          * TRUE if the day is in the month, FALSE if it is padding.
207          *
208          * @return  array
209          */
210         public function weeks()
211         {
212                 // First day of the month as a timestamp
213                 $first = mktime(1, 0, 0, $this->month, 1, $this->year);
214
215                 // Total number of days in this month
216                 $total = (int) date('t', $first);
217
218                 // Last day of the month as a timestamp
219                 $last  = mktime(1, 0, 0, $this->month, $total, $this->year);
220
221                 // Make the month and week empty arrays
222                 $month = $week = array();
223
224                 // Number of days added. When this reaches 7, start a new week
225                 $days = 0;
226                 $week_number = 1;
227
228                 if (($w = (int) date('w', $first) - $this->week_start) < 0)
229                 {
230                         $w = 6;
231                 }
232
233                 if ($w > 0)
234                 {
235                         // Number of days in the previous month
236                         $n = (int) date('t', mktime(1, 0, 0, $this->month - 1, 1, $this->year));
237
238                         // i = number of day, t = number of days to pad
239                         for ($i = $n - $w + 1, $t = $w; $t > 0; $t--, $i++)
240                         {
241                                 // Notify the listeners
242                                 $this->notify(array($this->month - 1, $i, $this->year, $week_number, FALSE));
243
244                                 // Add previous month padding days
245                                 $week[] = array($i, FALSE, $this->observed_data);
246                                 $days++;
247                         }
248                 }
249
250                 // i = number of day
251                 for ($i = 1; $i <= $total; $i++)
252                 {
253                         if ($days % 7 === 0)
254                         {
255                                 // Start a new week
256                                 $month[] = $week;
257                                 $week = array();
258
259                                 $week_number++;
260                         }
261
262                         // Notify the listeners
263                         $this->notify(array($this->month, $i, $this->year, $week_number, TRUE));
264
265                         // Add days to this month
266                         $week[] = array($i, TRUE, $this->observed_data);
267                         $days++;
268                 }
269
270                 if (($w = (int) date('w', $last) - $this->week_start) < 0)
271                 {
272                         $w = 6;
273                 }
274
275                 if ($w >= 0)
276                 {
277                         // i = number of day, t = number of days to pad
278                         for ($i = 1, $t = 6 - $w; $t > 0; $t--, $i++)
279                         {
280                                 // Notify the listeners
281                                 $this->notify(array($this->month + 1, $i, $this->year, $week_number, FALSE));
282
283                                 // Add next month padding days
284                                 $week[] = array($i, FALSE, $this->observed_data);
285                         }
286                 }
287
288                 if ( ! empty($week))
289                 {
290                         // Append the remaining days
291                         $month[] = $week;
292                 }
293
294                 return $month;
295         }
296
297         /**
298          * Adds new data from an observer. All event data contains and array of CSS
299          * classes and an array of output messages.
300          *
301          * @param   array  observer data.
302          * @return  void
303          */
304         public function add_data(array $data)
305         {
306                 // Add new classes
307                 $this->observed_data['classes'] += $data['classes'];
308
309                 if ( ! empty($data['output']))
310                 {
311                         // Only add output if it's not empty
312                         $this->observed_data['output'][] = $data['output'];
313                 }
314         }
315
316         /**
317          * Resets the observed data and sends a notify to all attached events.
318          *
319          * @param   array  UNIX timestamp
320          * @return  void
321          */
322         public function notify($data)
323         {
324                 // Reset observed data
325                 $this->observed_data = array
326                 (
327                         'classes' => array(),
328                         'output' => array(),
329                 );
330
331                 // Send a notify
332                 parent::notify($data);
333         }
334
335         /**
336          * Convert the calendar to HTML using the kohana_calendar view.
337          *
338          * @return  string
339          */
340         public function render()
341         {
342                 $view =  new View('kohana_calendar', array
343                 (
344                         'month'  => $this->month,
345                         'year'   => $this->year,
346                         'weeks'  => $this->weeks(),
347                 ));
348
349                 return $view->render();
350         }
351
352         /**
353          * Magically convert this object to a string, the rendered calendar.
354          *
355          * @return  string
356          */
357         public function __toString()
358         {
359                 return $this->render();
360         }
361
362 } // End Calendar