summaryrefslogtreecommitdiff
path: root/kohana/libraries/Calendar_Event.php
diff options
context:
space:
mode:
Diffstat (limited to 'kohana/libraries/Calendar_Event.php')
-rw-r--r--kohana/libraries/Calendar_Event.php297
1 files changed, 297 insertions, 0 deletions
diff --git a/kohana/libraries/Calendar_Event.php b/kohana/libraries/Calendar_Event.php
new file mode 100644
index 00000000..9878924e
--- /dev/null
+++ b/kohana/libraries/Calendar_Event.php
@@ -0,0 +1,297 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+/**
+ * Calendar event observer class.
+ *
+ * $Id$
+ *
+ * @package Calendar
+ * @author Kohana Team
+ * @copyright (c) 2007-2008 Kohana Team
+ * @license http://kohanaphp.com/license.html
+ */
+class Calendar_Event_Core extends Event_Observer {
+
+ // Boolean conditions
+ protected $booleans = array
+ (
+ 'current',
+ 'weekend',
+ 'first_day',
+ 'last_day',
+ 'last_occurrence',
+ 'easter',
+ );
+
+ // Rendering conditions
+ protected $conditions = array();
+
+ // Cell classes
+ protected $classes = array();
+
+ // Cell output
+ protected $output = '';
+
+ /**
+ * Adds a condition to the event. The condition can be one of the following:
+ *
+ * timestamp - UNIX timestamp
+ * day - day number (1-31)
+ * week - week number (1-5)
+ * month - month number (1-12)
+ * year - year number (4 digits)
+ * day_of_week - day of week (1-7)
+ * current - active month (boolean) (only show data for the month being rendered)
+ * weekend - weekend day (boolean)
+ * first_day - first day of month (boolean)
+ * last_day - last day of month (boolean)
+ * occurrence - occurrence of the week day (1-5) (use with "day_of_week")
+ * last_occurrence - last occurrence of week day (boolean) (use with "day_of_week")
+ * easter - Easter day (boolean)
+ * callback - callback test (boolean)
+ *
+ * To unset a condition, call condition with a value of NULL.
+ *
+ * @chainable
+ * @param string condition key
+ * @param mixed condition value
+ * @return object
+ */
+ public function condition($key, $value)
+ {
+ if ($value === NULL)
+ {
+ unset($this->conditions[$key]);
+ }
+ else
+ {
+ if ($key === 'callback')
+ {
+ // Do nothing
+ }
+ elseif (in_array($key, $this->booleans))
+ {
+ // Make the value boolean
+ $value = (bool) $value;
+ }
+ else
+ {
+ // Make the value an int
+ $value = (int) $value;
+ }
+
+ $this->conditions[$key] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a CSS class for this event. This can be called multiple times.
+ *
+ * @chainable
+ * @param string CSS class name
+ * @return object
+ */
+ public function add_class($class)
+ {
+ $this->classes[$class] = $class;
+
+ return $this;
+ }
+
+ /**
+ * Remove a CSS class for this event. This can be called multiple times.
+ *
+ * @chainable
+ * @param string CSS class name
+ * @return object
+ */
+ public function remove_class($class)
+ {
+ unset($this->classes[$class]);
+
+ return $this;
+ }
+
+ /**
+ * Set HTML output for this event.
+ *
+ * @chainable
+ * @param string HTML output
+ * @return object
+ */
+ public function output($str)
+ {
+ $this->output = $str;
+
+ return $this;
+ }
+
+ /**
+ * Add a CSS class for this event. This can be called multiple times.
+ *
+ * @chainable
+ * @param string CSS class name
+ * @return object
+ */
+ public function notify($data)
+ {
+ // Split the date and current status
+ list ($month, $day, $year, $week, $current) = $data;
+
+ // Get a timestamp for the day
+ $timestamp = mktime(0, 0, 0, $month, $day, $year);
+
+ // Date conditionals
+ $condition = array
+ (
+ 'timestamp' => (int) $timestamp,
+ 'day' => (int) date('j', $timestamp),
+ 'week' => (int) $week,
+ 'month' => (int) date('n', $timestamp),
+ 'year' => (int) date('Y', $timestamp),
+ 'day_of_week' => (int) date('w', $timestamp),
+ 'current' => (bool) $current,
+ );
+
+ // Tested conditions
+ $tested = array();
+
+ foreach ($condition as $key => $value)
+ {
+ // Test basic conditions first
+ if (isset($this->conditions[$key]) AND $this->conditions[$key] !== $value)
+ return FALSE;
+
+ // Condition has been tested
+ $tested[$key] = TRUE;
+ }
+
+ if (isset($this->conditions['weekend']))
+ {
+ // Weekday vs Weekend
+ $condition['weekend'] = ($condition['day_of_week'] === 0 OR $condition['day_of_week'] === 6);
+ }
+
+ if (isset($this->conditions['first_day']))
+ {
+ // First day of month
+ $condition['first_day'] = ($condition['day'] === 1);
+ }
+
+ if (isset($this->conditions['last_day']))
+ {
+ // Last day of month
+ $condition['last_day'] = ($condition['day'] === (int) date('t', $timestamp));
+ }
+
+ if (isset($this->conditions['occurrence']))
+ {
+ // Get the occurance of the current day
+ $condition['occurrence'] = $this->day_occurrence($timestamp);
+ }
+
+ if (isset($this->conditions['last_occurrence']))
+ {
+ // Test if the next occurance of this date is next month
+ $condition['last_occurrence'] = ((int) date('n', $timestamp + 604800) !== $condition['month']);
+ }
+
+ if (isset($this->conditions['easter']))
+ {
+ if ($condition['month'] === 3 OR $condition['month'] === 4)
+ {
+ // This algorithm is from Practical Astronomy With Your Calculator, 2nd Edition by Peter
+ // Duffett-Smith. It was originally from Butcher's Ecclesiastical Calendar, published in
+ // 1876. This algorithm has also been published in the 1922 book General Astronomy by
+ // Spencer Jones; in The Journal of the British Astronomical Association (Vol.88, page
+ // 91, December 1977); and in Astronomical Algorithms (1991) by Jean Meeus.
+
+ $a = $condition['year'] % 19;
+ $b = (int) ($condition['year'] / 100);
+ $c = $condition['year'] % 100;
+ $d = (int) ($b / 4);
+ $e = $b % 4;
+ $f = (int) (($b + 8) / 25);
+ $g = (int) (($b - $f + 1) / 3);
+ $h = (19 * $a + $b - $d - $g + 15) % 30;
+ $i = (int) ($c / 4);
+ $k = $c % 4;
+ $l = (32 + 2 * $e + 2 * $i - $h - $k) % 7;
+ $m = (int) (($a + 11 * $h + 22 * $l) / 451);
+ $p = ($h + $l - 7 * $m + 114) % 31;
+
+ $month = (int) (($h + $l - 7 * $m + 114) / 31);
+ $day = $p + 1;
+
+ $condition['easter'] = ($condition['month'] === $month AND $condition['day'] === $day);
+ }
+ else
+ {
+ // Easter can only happen in March or April
+ $condition['easter'] = FALSE;
+ }
+ }
+
+ if (isset($this->conditions['callback']))
+ {
+ // Use a callback to determine validity
+ $condition['callback'] = call_user_func($this->conditions['callback'], $condition, $this);
+ }
+
+ $conditions = array_diff_key($this->conditions, $tested);
+
+ foreach ($conditions as $key => $value)
+ {
+ if ($key === 'callback')
+ {
+ // Callbacks are tested on a TRUE/FALSE basis
+ $value = TRUE;
+ }
+
+ // Test advanced conditions
+ if ($condition[$key] !== $value)
+ return FALSE;
+ }
+
+ $this->caller->add_data(array
+ (
+ 'classes' => $this->classes,
+ 'output' => $this->output,
+ ));
+ }
+
+ /**
+ * Find the week day occurrence for a specific timestamp. The occurrence is
+ * relative to the current month. For example, the second Saturday of any
+ * given month will return "2" as the occurrence. This is used in combination
+ * with the "occurrence" condition.
+ *
+ * @param integer UNIX timestamp
+ * @return integer
+ */
+ protected function day_occurrence($timestamp)
+ {
+ // Get the current month for the timestamp
+ $month = date('m', $timestamp);
+
+ // Default occurrence is one
+ $occurrence = 1;
+
+ // Reduce the timestamp by one week for each loop. This has the added
+ // benefit of preventing an infinite loop.
+ while ($timestamp -= 604800)
+ {
+ if (date('m', $timestamp) !== $month)
+ {
+ // Once the timestamp has gone into the previous month, the
+ // proper occurrence has been found.
+ return $occurrence;
+ }
+
+ // Increment the occurrence
+ $occurrence++;
+ }
+ }
+
+} // End Calendar Event