<?php

require_once 'Horde/Template.php';

/**
 * This class represent a view of multiple free busy information sets.
 *
 * Copyright 2003-2006 Mike Cochrane <mike@graftonhall.co.nz>
 * Copyright 2004-2006 Jan Schneider <jan@horde.org>
 *
 * See the enclosed file COPYING for license information.
 *
 * $Horde: kronolith/lib/FBView.php,v 1.10.10.9 2006/11/29 11:23:36 jan Exp $
 *
 * @author  Mike Cochrane <mike@graftonhall.co.nz>
 * @author  Jan Schneider <jan@horde.org>
 * @package Kronolith
 */
class Kronolith_FreeBusy_View {

    var $_requiredMembers = array();
    var $_optionalMembers = array();

    var $_startHour;
    var $_endHour;

    var $_startStamp;
    var $_endStamp;

    function addRequiredMember($vFreebusy)
    {
        $this->_requiredMembers[] = Util::cloneObject($vFreebusy);
    }

    function addOptionalMember($vFreebusy)
    {
        $this->_optionalMembers[] = Util::cloneObject($vFreebusy);
    }

    function render($day = null)
    {
        global $prefs;

        $this->_startHour = floor($prefs->getValue('day_hour_start') / 2);
        $this->_endHour = floor(($prefs->getValue('day_hour_end') + 1) / 2);

        $this->_render($day);

        require_once 'Horde/iCalendar.php';
        $vCal = &new Horde_iCalendar();
        $required = &Horde_iCalendar::newComponent('vfreebusy', $vCal);
        foreach ($this->_requiredMembers as $member) {
            $required->merge($member, false);
        }
        $required->simplify();

        $optional = &Horde_iCalendar::newComponent('vfreebusy', $vCal);
        foreach ($this->_optionalMembers as $member) {
            $optional->merge($member, false);
        }
        $optional->simplify();

        $optimal = &Horde_iCalendar::newComponent('vfreebusy', $vCal);
        $optimal->merge($required, false);
        $optimal->merge($optional);

        $base_url = Horde::selfUrl();
        $base_url = Util::removeParameter($base_url, 'date');
        $base_url = Util::removeParameter($base_url, 'fbview');
        $base_url = Util::addParameter($base_url, 'fbview', $this->view);

        $template = &new Horde_Template();
        $template->set('title', $this->_title());

        $html = $template->fetch(KRONOLITH_TEMPLATES . '/fbview/header.tpl') .
            '<div class="fbgrid">';

        $hours_html = $this->_hours();

        // set C locale to avoid localized decimal separators during CSS width
        // calculation.
        $lc = setlocale(LC_NUMERIC, 0);
        setlocale(LC_NUMERIC, 'C');

        // Required to attend.
        if (count($this->_requiredMembers) > 0) {
            $template = &new Horde_Template();
            $rows = '';
            foreach ($this->_requiredMembers as $member) {
                $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.tpl', _("Busy"));
                $template = &new Horde_Template();
                $template->set('blocks', $blocks);
                $template->set('name', $member->getName());
                $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.tpl');
            }

            $template = &new Horde_Template();
            $template->set('title', _("Required Attendees"));
            $template->set('rows', $rows);
            $template->set('span', count($this->_timeBlocks));
            $template->set('hours', $hours_html);
            $template->set('legend', '');
            $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.tpl');
        }

        // Optional to attend.
        if (count($this->_optionalMembers) > 0) {
            $template = &new Horde_Template();
            $rows = '';
            foreach ($this->_optionalMembers as $member) {
                $blocks = $this->_getBlocks($member, $member->getBusyPeriods(), 'busyblock.tpl', _("Busy"));
                $template = &new Horde_Template();
                $template->set('blocks', $blocks);
                $template->set('name', $member->getName());
                $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.tpl');
            }

            $template = &new Horde_Template();
            $template->set('title', _("Optional Attendees"));
            $template->set('rows', $rows);
            $template->set('span', count($this->_timeBlocks));
            $template->set('hours', $hours_html);
            $template->set('legend', '');
            $html .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.tpl');
        }

        // Possible meeting times.
        $optimal->setAttribute('ORGANIZER', _("All Attendees"));
        $blocks = $this->_getBlocks($optimal,
                                    $optimal->getFreePeriods($this->_startStamp, $this->_endStamp),
                                    'meetingblock.tpl', _("All Attendees"));

        $template = &new Horde_Template();
        $template->set('name', _("All Attendees"));
        $template->set('blocks', $blocks);
        $rows = $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.tpl');

        // Possible meeting times.
        $required->setAttribute('ORGANIZER', _("Required Attendees"));
        $blocks = $this->_getBlocks($required,
                                    $required->getFreePeriods($this->_startStamp, $this->_endStamp),
                                    'meetingblock.tpl', _("Required Attendees"));

        $template = &new Horde_Template();
        $template->set('name', _("Required Attendees"));
        $template->set('blocks', $blocks);
        $rows .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/row.tpl');

        // Reset locale.
        setlocale(LC_NUMERIC, $lc);

        $template = &new Horde_Template();
        $template->set('rows', $rows);
        $template->set('title', _("Overview"));
        $template->set('span', count($this->_timeBlocks));
        $template->set('hours', $hours_html);
        if ($prefs->getValue('show_fb_legend')) {
            $template->setOption('gettext', true);
            $template->set('legend', $template->fetch(KRONOLITH_TEMPLATES . '/fbview/legend.tpl'));
        } else {
            $template->set('legend', '');
        }

        return $html . $template->fetch(KRONOLITH_TEMPLATES . '/fbview/section.tpl') . '</div>';
    }

    /**
     * Attempts to return a concrete Kronolith_FreeBusy_View instance based on
     * $view.
     *
     * @param string $view  The type of concrete Kronolith_FreeBusy_View
     *                      subclass to return.
     *
     * @return mixed  The newly created concrete Kronolith_FreeBusy_View
     *                instance, or false on an error.
     */
    function &factory($view)
    {
        $driver = basename($view);
        require_once dirname(__FILE__) . '/FBView/' . $driver . '.php';
        $class = 'Kronolith_FreeBusy_View_' . $driver;
        if (class_exists($class)) {
            $fbview = new $class($user, $params);
        } else {
            $fbview = false;
        }

        return $fbview;
    }

    /**
     * Attempts to return a reference to a concrete Kronolith_FreeBusy_View
     * instance based on $view.  It will only create a new instance if no
     * Kronolith_FreeBusy_View instance with the same parameters currently
     * exists.
     *
     * This method must be invoked as:
     * $var = &Kronolith_FreeBusy_View::singleton()
     *
     * @param string $view  The type of concrete Kronolith_FreeBusy_View
     *                      subclass to return.
     *
     * @return mixed  The created concrete Kronolith_FreeBusy_View instance, or
     *                false on an error.
     */
    function &singleton($view)
    {
        static $instances;

        if (!isset($instances)) {
            $instances = array();
        }

        if (!isset($instances[$view])) {
            $instances[$view] = &Kronolith_FreeBusy_View::factory($view);
        }

        return $instances[$view];
    }

    function _getBlocks($member, $periods, $blockfile, $label)
    {
        $template = &new Horde_Template();
        $template->set('label', $label);

        reset($periods);
        list($periodStart, $periodEnd) = each($periods);

        $blocks = '';
        foreach ($this->_timeBlocks as $start => $end) {
            if ($member->getStart() > $start ||
                $member->getEnd() < $end) {
                $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/unknownblock.tpl');
                continue;
            }

            while ($end > $periodEnd &&
                   list($periodStart, $periodEnd) = each($periods));

            if ($start <= $periodEnd && $end >= $periodStart) {
                $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/' . $blockfile);
            } else {
                $blocks .= $template->fetch(KRONOLITH_TEMPLATES . '/fbview/emptyblock.tpl');
            }
        }

        return $blocks;
    }

}
