<?php
/**
 * Horde_Tree_html Class
 *
 * The Horde_Tree_html:: class extends the Horde_Tree class to provide html
 * specific rendering functions.
 *
 * Copyright 2003 Marko Djukic <marko@oblo.com>
 *
 * See the enclosed file COPYING for license information (GPL). If you did not
 * receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * $Horde: horde/lib/Tree/html.php,v 1.5 2003/07/30 17:27:32 chuck Exp $
 *
 * @author  Marko Djukic <marko@oblo.com>
 * @version $Revision: 1.5 $
 * @package horde.tree
 */
class Horde_Tree_html extends Horde_Tree {

    /* Image variables. */
    var $img_dir;
    var $img_line;
    var $img_blank;
    var $img_join;
    var $img_join_bottom;
    var $img_plus;
    var $img_plus_bottom;
    var $img_plus_only;
    var $img_minus;
    var $img_minus_bottom;
    var $img_minus_only;
    var $img_folder;
    var $img_folder_open;
    var $img_leaf;

    /* Tree building variables. */
    var $nodes            = array();
    var $node_pos         = array();
    var $dropline         = array();

    function Horde_Tree_html($tree_name)
    {
        parent::Horde_Tree($tree_name);

        $this->img_dir          = $GLOBALS['registry']->getParam('graphics', 'horde') . '/tree';
        $this->img_line         = 'line.gif';
        $this->img_blank        = 'blank.gif';
        $this->img_join         = 'join.gif';
        $this->img_join_bottom  = 'joinbottom.gif';
        $this->img_plus         = 'plus.gif';
        $this->img_plus_bottom  = 'plusbottom.gif';
        $this->img_plus_only    = 'plusonly.gif';
        $this->img_minus        = 'minus.gif';
        $this->img_minus_bottom = 'minusbottom.gif';
        $this->img_minus_only   = 'minusonly.gif';
        $this->img_folder       = 'folder.gif';
        $this->img_folder_open  = 'folderopen.gif';
        $this->img_leaf         = 'leaf.gif';
    }
    
    /**
     * Render the tree.
     *
     * @access public
     * @todo Add _width, _border, _style class vars like javascript.
     */
    function renderTree()
    {
        echo $this->_setTableStart();
        echo $this->_buildTree($this->_root_node_id);
        echo '</table>';
    }

    /**
     * Gets the starting html to the table.
     *
     * @access private
     */
    function _setTableStart()
    {
        $table = sprintf('<table%s%s%s%s%s>',
                         $this->getOption('border', true),
                         $this->getOption('width', true),
                         $this->getOption('class', true),
                         $this->getOption('cellpadding', true),
                         $this->getOption('cellspacing', true));
        return $table;
    }

    /**
     * Recursive function to walk through the tree array and build the output.
     *
     * @access private
     */
    function _buildTree($node_id)
    {
        static $output;

        $output .= $this->_buildLine($node_id);

        if (isset($this->nodes[$node_id]['children']) &&
                $this->nodes[$node_id]['expanded']) {
            $num_subnodes = count($this->nodes[$node_id]['children']);
            for ($c = 0; $c < $num_subnodes; $c++) {
                $child_node_id = $this->nodes[$node_id]['children'][$c];
                $this->node_pos[$child_node_id] = array();
                $this->node_pos[$child_node_id]['pos'] = $c . 1;
                $this->node_pos[$child_node_id]['count'] = $num_subnodes;
                $this->_buildTree($child_node_id);
            }
        }

        return $output;

    }

    /**
     * Function to create a single line of the tree.
     *
     * @access private
     */
    function _buildLine($node_id)
    {
        static $alt_count = 0;
        $node_class = '';
        if (!empty($this->nodes[$node_id]['class'])) {
            $node_class = ' class="' . $this->nodes[$node_id]['class'] . '"';
        }

        $line = '<tr';
        /* If using alternating row shading, work out correct shade. */
        if ($this->getOption('alternate')) {
            $line .= ' class="item' . $alt_count . '"';
            $alt_count = ($alt_count ? 0 : 1);
        }
        $line .= '><td' . $node_class . '>';

        for ($i = 0; $i < $this->nodes[$node_id]['indent']; $i++) {
            if ($this->dropline[$i]) {
                $line .= '<img src="' . $this->img_dir . '/' . $this->img_line . '" height="20" width="20" align="middle" border="0" />';
            } else {
                $line .= '<img src="' . $this->img_dir . '/' . $this->img_blank . '" height="20" width="20" align="middle" border="0" />';
            }
        }
        $line .= $this->_setNodeToggle($node_id) . $this->_setNodeIcon($node_id) . $this->_setLabel($node_id) . '</td>';

        if (isset($this->nodes[$node_id]['extra'])) {
            $extra = $this->nodes[$node_id]['extra'];
            $cMax = count($extra);
            for ($c = 0; $c < $cMax; $c++) {
                $line .= '<td' . $node_class . ' align="center">' . $extra[$c] . '</td>';
            }
        }
        $line .= "</tr>\n";

        return $line;
    }

    /**
     * Set the label on the tree line.
     *
     * @access private
     */
    function _setLabel($node_id)
    {
        $label = $this->nodes[$node_id]['label'];
        $on_click = '';
        if (!empty($this->nodes[$node_id]['onclick'])) {
            $on_click = ' onclick="' . $this->nodes[$node_id]['onclick'] . '"';
        }
        if (!empty($this->nodes[$node_id]['url'])) {
            $label = '<a href="' . $this->nodes[$node_id]['url'] . '">' . $label . '</a>';
        }
        return '<span' . $on_click . '>' . $label . '</span></td>';
    }

    /**
     * Set the label on the tree line.
     *
     * @access private
     */
    function _setNodeToggle($node_id)
    {
        $link_start = '';
        if ($node_id == $this->_root_node_id &&
            isset($this->nodes[$node_id]['children'])) {
            /* Root, and children. */
            $img = ($this->nodes[$node_id]['expanded']) ? $this->img_minus_only : $this->img_plus_only;
            $this->dropline[0] = false;
            $url = Horde::addParameter(Horde::selfURL(), 'toggle_' . $this->_instance, $node_id);
            $link_start = Horde::link($url);
        } elseif ($node_id != $this->_root_node_id &&
            !isset($this->nodes[$node_id]['children'])) {
            /* Node no children. */
            if ($this->node_pos[$node_id]['pos'] < $this->node_pos[$node_id]['count']) {
                /* Not last node. */
                $img = $this->img_join;
                $this->dropline[$this->nodes[$node_id]['indent']] = true;
            } else {
                /* Last node. */
                $img = $this->img_join_bottom;
                $this->dropline[$this->nodes[$node_id]['indent']] = false;
            }
        } elseif (isset($this->nodes[$node_id]['children'])) {
            /* Node with children. */
            if ($this->node_pos[$node_id]['pos'] < $this->node_pos[$node_id]['count']) {
                /* Not last node. */
                $img = ($this->nodes[$node_id]['expanded']) ? $this->img_minus : $this->img_plus;
                $this->dropline[$this->nodes[$node_id]['indent']] = true;
            } else {
                /* Last node. */
                $img = ($this->nodes[$node_id]['expanded']) ? $this->img_minus_bottom : $this->img_plus_bottom;
                $this->dropline[$this->nodes[$node_id]['indent']] = false;
            }
            $url = Horde::addParameter(Horde::selfURL(), 'toggle_' . $this->_instance, $node_id);
            $link_start = Horde::link($url);
        } else {
            /* Root only, no children. */
            $img = $this->img_minus_only;
            $this->dropline[0] = false;
        }

        $link_end = ($link_start) ? '</a>' : '';
        return $link_start . '<img src="' . $this->img_dir . '/' . $img . '" height="20" width="20" align="middle" border="0" />' . $link_end;
    }


    /**
     * Sets the icon for the node.
     *
     * @access private
     */
    function _setNodeIcon($node_id)
    {
        $img_dir = (!empty($this->nodes[$node_id]['icondir'])) ? $this->nodes[$node_id]['icondir']
                                                     : $this->img_dir;
        if (isset($this->nodes[$node_id]['icon'])) {
            /* Node has a user defined icon. */
            if (isset($this->nodes[$node_id]['iconopen']) && $this->nodes[$node_id]['expanded']) {
                $img = $this->nodes[$node_id]['iconopen'];
            } else {
                $img = $this->nodes[$node_id]['icon'];
            }
        } else {
            /* Use standard icon set. */
            if (isset($this->nodes[$node_id]['children'])) {
                /* Node with children. */
                $img = ($this->nodes[$node_id]['expanded']) ? $this->img_folder_open
                                                       : $this->img_folder;
            } else {
                /* Node no children. */
                $img = $this->img_leaf;
            }
        }

        return '<img src="' . $img_dir . '/' . $img . '" align="middle" border="0" />';
    }

}
