<?php
/*=====================================================================*\
|| ###################################################################
|| # Kalens [#]version[#]
|| # Copyright 2002-[#]year[#] Iris Studios, Inc.
|| #
|| # 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; version [#]gpl[#] of the License.
|| #
|| # This program is distributed in the hope that it will be useful, but
|| # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|| # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|| # more details.
|| #
|| # You should have received a copy of the GNU General Public License along
|| # with this program; if not, write to the Free Software Foundation, Inc.,
|| # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|| ###################################################################
\*=====================================================================*/
require_once('./includes/class_calendar_week.php');
require_once('./includes/functions_names.php');
/**
* Monthly Calendar Display
*
* This class is responsible for creating the actual calendar interface display.
* Parts of this class have been adapted from http://www.cascade.org.uk/software/php/calendar/Calendar.txt
*
* @author Blue Static
* @copyright Copyright 2002 - [#]year[#], Blue Static
* @version $Revision$
* @package Kalens
*
*/
class CalendarMonth
{
/**
* Numeric month
* @var integer
*/
private $month;
/**
* Year (four-year)
* @var integer
*/
private $year;
/**
* User-set start day of the week
* @var integer
*/
private $weekStartDay = DAY_SUNDAY;
/**
* Number of days in the month
* @var integer
*/
private $daysInMonth;
/**
* Internal date number that will be displayed *next* getNextDay()
* @var integer
*/
private $nextDay;
/**
* Event list; week number => day => event
* @var array
*/
private $events = array();
// ###################################################################
/**
* Constructor: set the current date, if zero then use current
*
* @param integer Month to display
* @param integer Year to display
*/
public function __construct($month, $year)
{
$this->month = intval(($month == 0 ? date('m') : $month));
$this->year = intval(($year == 0 ? date('Y') : $year));
}
// ###################################################################
/**
* Gets the calendar's month
*
* @return integer Month number
*/
public function getMonth()
{
return $this->month;
}
// ###################################################################
/**
* Gets the calendar's year
*
* @return integer Year (four-digit)
*/
public function getYear()
{
return $this->year;
}
// ###################################################################
/**
* Sets the displayed start day of the week
*
* @param integer Day of the week to start on
*/
public function setWeekStartDay($startdow)
{
$this->weekStartDay = $startdow;
}
// ###################################################################
/**
* Calls a series of internal routines to generate all the calendar
* HTML and process data.
*/
public function generate()
{
$this->_getDaysInMonth();
$firstDay = gmdate('w', gmmktime(0, 0, 0, $this->month, 1, $this->year));
$this->nextDay = FetchWeekDayFromBitfieldDay($this->weekStartDay) + 1 - $firstDay['wday'];
while ($this->nextDay > 1)
{
$this->nextDay -= 7;
}
$this->_getEvents();
}
// ###################################################################
/**
* Returns a CalendarWeek with CalendarDays inside
*
* @return object A CalendarWeek
*/
public function getNextWeek()
{
if ($this->nextDay <= $this->daysInMonth)
{
$week = new CalendarWeek($this->nextDay, $this->month, $this->year);
$week->setWeekStartDay($this->weekStartDay);
$week->setEvents($this->events); // yes, we have extra events but whatever
$week->generate();
$this->nextDay += 7;
return $week;
}
}
// ###################################################################
/**
* Gets the number of days in the current month
*/
private function _getDaysInMonth()
{
$this->daysInMonth = gmdate('t', gmmktime(0, 0, 0, $this->month, 1, $this->year));
}
// ###################################################################
/**
* Gets all the events for the given time range and organizes them all
*/
private function _getEvents()
{
global $kalens;
$this->_processRemovedEvents();
$start = gmmktime(0, 0, 0, $this->month, 1, $this->year);
$end = gmmktime(23, 59, 59, $this->month, $this->daysInMonth, $this->year);
$events = $kalens->db->query("
SELECT * FROM " . TABLE_PREFIX . "event
WHERE
(
(pattern = " . PATTERN_SINGLE . " AND startstamp >= $start AND endstamp <= $end)
OR
(pattern = " . PATTERN_RANGED . " AND endstamp >= $start)
OR
(pattern & " . PATTERN_RECUR . " AND (endstamp >= $start OR endstamp = 0))
)" . ((is_array($kalens->userinfo['calendarids']) AND sizeof($kalens->userinfo['calendarids']) > 0) ? "
AND calendarid IN (" . implode(',', $kalens->userinfo['calendarids']) . ")" : "") . "
ORDER BY startstamp ASC
");
while ($event = $kalens->db->fetch_array($events))
{
if ($event['pattern'] == PATTERN_SINGLE)
{
$date = gmdate('d', $event['startstamp']);
$this->events[ intval($date) ]["$event[eventid]"] = $event;
}
else if ($event['pattern'] == PATTERN_RANGED)
{
$this->_processRangedEvent($event, $event['startstamp']);
}
else if ($event['pattern'] & PATTERN_RECUR)
{
$this->_processRecurringEvent($event, $event['startstamp']);
}
}
}
// ###################################################################
/**
* Queries the eventremoved table and loads any removed events into
* the event array.
*/
private function _processRemovedEvents()
{
global $kalens;
$start = gmmktime(0, 0, 0, $this->month, 1, $this->year);
$end = gmmktime(23, 59, 59, $this->month, $this->daysInMonth, $this->year);
$events = $kalens->db->query("
SELECT * FROM " . TABLE_PREFIX . "eventremoved
WHERE startstamp >= $start AND endstamp <= $end" . ((is_array($kalens->userinfo['calendarids']) AND sizeof($kalens->userinfo['calendarids']) > 0) ? "
AND calendarid IN (" . implode(',', $kalens->userinfo['calendarids']) . ")" : "") . "
ORDER BY startstamp ASC
");
while ($event = $kalens->db->fetch_array($events))
{
$date = gmdate('d', $event['startstamp']);
$this->events[ intval($date) ]["$event[eventid]"] = ($event['removed'] ? true : $event);
}
}
// ###################################################################
/**
* Recursively goes through the given event, adding events to the
* event table.
*
* @param array Event information
* @param integer Timetamp to add as an event
*/
private function _processRangedEvent($event, $stamp)
{
if ($stamp <= $event['endstamp'])
{
if (intval(gmdate('m', $stamp)) == $this->month AND intval(gmdate('Y', $stamp)) == $this->year)
{
$date = gmdate('d', $stamp);
if (!isset($this->events[ intval($date) ]["$event[eventid]"]))
{
$this->events[ intval($date) ]["$event[eventid]"] = $event;
}
}
$this->_processRangedEvent($event, $stamp + SECONDS_DAY);
}
}
// ###################################################################
/**
* Recursivelly adds events to the table from a single recurring event
* based on the repition criteria.
*
* @param array Event array
* @param integer Next timestamp to add
*/
private function _processRecurringEvent($event, $stamp)
{
if ($stamp <= $event['endstamp'])
{
$month = intval(gmdate('m', $stamp));
$year = intval(gmdate('Y', $stamp));
$date = intval(gmdate('d', $stamp));
if ($event['pattern'] & RECUR_DAY)
{
if ($month == $this->month AND $year == $this->year AND !isset($this->events[ intval($date) ]["$event[eventid]"]))
{
$this->events["$date"]["$event[eventid]"] = $event;
}
$this->_processRecurringEvent($event, $stamp + ($event['occurrence'] * SECONDS_DAY));
}
else if ($event['pattern'] & RECUR_WEEK)
{
$this->_processWeeklyRecurringEvent($event, $stamp);
}
else if ($event['pattern'] & RECUR_MONTH)
{
// we don't want the month or year to be greater than the month's
if (gmmktime(0, 0, 0, $month, 1, $year) > gmmktime(0, 0, 0, $this->month, 1, $this->year))
{
return;
}
if ($month == $this->month AND $year == $this->year AND !isset($this->events[ intval($date) ]["$event[eventid]"]))
{
$this->events["$date"]["$event[eventid]"] = $event;
}
$nextMonth = $month + $event['occurrence'];
$nextYear = gmdate('Y', $stamp);
if ($nextMonth > 12)
{
$nextMonth -= 12;
$nextYear++;
}
$this->_processRecurringEvent($event, gmmktime(0, 0, 0, $nextMonth, gmdate('d', $event['startstamp']), $nextYear));
}
else if ($event['pattern'] & RECUR_YEAR)
{
// not the right year and we're not getting any younger
if (gmdate('Y', $stamp) > $this->year)
{
return;
}
if ($month == $this->month AND $year == $this->year AND !isset($this->events[ intval($date) ]["$event[eventid]"]))
{
$this->events["$date"]["$event[eventid]"] = $event;
}
$this->_processRecurringEvent($event, $stamp + ($event['occurrence'] * SECONDS_YEAR));
}
}
}
// ###################################################################
/**
* Function to process weekly recuring events by starting at the first
* day of the month and working each day checking to see if the pattern
* matches or not and adding events.
*
* @param array Event information
* @param integer Timestamp to test
*/
private function _processWeeklyRecurringEvent($event, $stamp)
{
if ($stamp <= $event['endstamp'])
{
$dayOfWeek = gmdate('w', $stamp);
while ($dayOfWeek != 0)
{
$stamp -= SECONDS_DAY;
$dayOfWeek = gmdate('w', $stamp);
}
$workStamp = $stamp;
for ($i = 1; $i <= 7; $i++)
{
$workStamp += SECONDS_DAY;
$month = intval(gmdate('m', $workStamp));
$year = intval(gmdate('Y', $workStamp));
$date = intval(gmdate('d', $workStamp));
$dayBit = FetchBitfieldDayFromWeekDay($i);
$timeTest = gmmktime(gmdate('H', $event['startstamp']), gmdate('i', $event['startstamp']), gmdate('s', $event['startstamp']), $month, $date, $year);
if ($event['pattern'] & $dayBit AND $timeTest >= gmmktime(0, 0, 0, $this->month, 1, $this->year) AND $timeTest <= gmmktime(23, 59, 59, $this->month, $this->daysInMonth, $this->year) AND $timeTest >= $event['startstamp'] AND $timeTest <= $event['endstamp'])
{
if (!isset($this->events[ intval($date) ]["$event[eventid]"]))
{
$this->events["$date"]["$event[eventid]"] = $event;
}
}
}
$this->_processWeeklyRecurringEvent($event, $stamp + ($event['occurrence'] * 7 * SECONDS_DAY));
}
}
}
/*=====================================================================*\
|| ###################################################################
|| # $HeadURL$
|| # $Id$
|| ###################################################################
\*=====================================================================*/
?>