/**
 * Horde Tree Javascript Class
 *
 * Provides the javascript class to create dynamic trees.
 *
 * 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/templates/javascript/tree.js,v 1.12 2003/07/30 20:13:31 chuck Exp $
 *
 * @author Marko Djukic <marko@oblo.com>
 * @version $Revision: 1.12 $
 * @package horde
 */

function Horde_Tree(instanceName)
{
    /* Set up this class instance for function calls from the page. */
    this._instanceName = instanceName;

    /* Image variables. */
    this.imgDir         = '<?php echo $GLOBALS['registry']->getParam('graphics', 'horde') . '/tree'; ?>';
    this.imgLine        = 'line.gif';
    this.imgBlank       = 'blank.gif';
    this.imgJoin        = 'join.gif';
    this.imgJoinBottom  = 'joinbottom.gif';
    this.imgPlus        = 'plus.gif';
    this.imgPlusBottom  = 'plusbottom.gif';
    this.imgPlusOnly    = 'plusonly.gif';
    this.imgMinus       = 'minus.gif';
    this.imgMinusBottom = 'minusbottom.gif';
    this.imgMinusOnly   = 'minusonly.gif';
    this.imgFolder      = 'folder.gif';
    this.imgFolderOpen  = 'folderopen.gif';
    this.imgLeaf        = 'leaf.gif';

    /* Tree building variables. */
    this.rootNodeId     = '';
    this.target         = '';
    this.nodes          = new Array();
    this.node_pos       = new Array();
    this.dropline       = new Array();
    this.output         = '';
    this.altCount       = 0;
    this.getThis = function()
    {
        return this;
    }

    this.setTableStart = function(tableParams)
    {
        this.tableStart = '<table' + tableParams + '>';
    }

    this.setImgDir = function(imgDir)
    {
        this.imgDir = imgDir;
    }

    this.renderTree = function(rootNodeId)
    {
        this._setCookie(this._instanceName + '_expanded', '');
        this.rootNodeId = rootNodeId;
        this.nodes = eval('n_' + this._instanceName);
        this.options = eval('o_' + this._instanceName);
        this.target = 't_' + this._instanceName;
        this._renderTree();
    }

    this._renderTree = function()
    {
        this.output = '';
        this.buildTree(this.rootNodeId);
        document.getElementById(this.target).innerHTML = this.tableStart + this.output + '</table>';
        this.altCount = 0;
    }

    /*
     * Recursive function to walk through the tree array and build
     * the output.
     */
    this.buildTree = function(nodeId)
    {
        this.output += this.buildLine(nodeId);

        if (typeof(this.nodes[nodeId]['children']) != 'undefined' &&
                this.nodes[nodeId]['expanded']) {
            var numSubnodes = this.nodes[nodeId]['children'].length;
            for (var c = 0; c < numSubnodes; c++) {
                var childNodeId = this.nodes[nodeId]['children'][c];
                this.node_pos[childNodeId] = new Array();
                this.node_pos[childNodeId]['pos'] = c + 1;
                this.node_pos[childNodeId]['count'] = numSubnodes;
                this.buildTree(childNodeId);
            }
        }

        return true;
    }

    this.buildLine = function(nodeId)
    {
        var nodeClass = '';
        if (this.options['alternate']) {
            this.altCount = (this.altCount ? 0 : 1);
        }

        if (this.nodes[nodeId]['class']) {
            nodeClass = ' class="' + this.nodes[nodeId]['class'] + '"';
        } else if (this.options['class']) {
            nodeClass = ' class="' + this.options['class'] + this.altCount + '"';
        }

        var line = '<tr><td' + nodeClass + '>';

        for (var i = 0; i < this.nodes[nodeId]['indent']; i++) {
            if (this.dropline[i]) {
                line += '<img src="' + this.imgDir + '/' + this.imgLine + '" height="20" width="20" align="middle" border="0" />';
            } else {
                line += '<img src="' + this.imgDir + '/' + this.imgBlank + '" height="20" width="20" align="middle" border="0" />';
            }
        }

        line += this._setNodeToggle(nodeId) + this._setNodeIcon(nodeId) + this._setLabel(nodeId) + '</td>';

        if (typeof(this.nodes[nodeId]['extra']) != 'undefined') {
            var extra = this.nodes[nodeId]['extra'];
            for (var c = 0; c < extra.length; c++) {
                line += '<td' + nodeClass + ' align="center">' + extra[c] + '</td>';
            }
            for (var d = c; d < extraCols; d++) {
                line += '<td' + nodeClass + '>&nbsp;</td>';
            }
        } else {
            for (var c = 0; c < extraCols; c++) {
                line += '<td' + nodeClass + '>&nbsp;</td>';
            }
        }
        line += '</tr>';

        return line;
    }

    this._setLabel = function(nodeId)
    {
        var label = this.nodes[nodeId]['label'];
        var onClick = '';
        if (this.nodes[nodeId]['onclick']) {
            onClick = ' onclick="' + this.nodes[nodeId]['onclick'] + '"';
        }
        if (this.nodes[nodeId]['url']) {
            label = '<a href="' + this.nodes[nodeId]['url'] + '">' + label + '</a>';
        }
        return '<span' + onClick + '>' + label + '</span></td>';
    }

    this._setNodeToggle = function(nodeId)
    {
        var attrib = '';
        if (nodeId == this.rootNodeId &&
            typeof(this.nodes[nodeId]['children']) != 'undefined') {
            /* Root, and children. */
            img = (this.nodes[nodeId]['expanded']) ? this.imgMinusOnly : this.imgPlusOnly;
            this.dropline[0] = false;
            attrib = ' style="cursor:pointer;cursor:hand;" onclick="' + this._instanceName + '.toggle(\'' + nodeId + '\')"';
        } else if (nodeId != this.rootNodeId &&
            typeof(this.nodes[nodeId]['children']) == 'undefined') {
            /* Node no children. */
            if (this.node_pos[nodeId]['pos'] < this.node_pos[nodeId]['count']) {
                /* Not last node. */
                img = this.imgJoin;
                this.dropline[this.nodes[nodeId]['indent']] = true;
            } else {
                /* Last node. */
                img = this.imgJoinBottom;
                this.dropline[this.nodes[nodeId]['indent']] = false;
            }
        } else if (typeof(this.nodes[nodeId]['children']) != 'undefined') {
            /* Node with children. */
            if (this.node_pos[nodeId]['pos'] < this.node_pos[nodeId]['count']) {
                /* Not last node. */
                img = (this.nodes[nodeId]['expanded']) ? this.imgMinus : this.imgPlus;
                this.dropline[this.nodes[nodeId]['indent']] = true;
            } else {
                /* Last node. */
                img = (this.nodes[nodeId]['expanded']) ? this.imgMinusBottom : this.imgPlusBottom;
                this.dropline[this.nodes[nodeId]['indent']] = false;
            }
            attrib = ' style="cursor:pointer;cursor:hand;" onclick="' + this._instanceName + '.toggle(\'' + nodeId + '\')"';
        } else {
            /* Root only, no children. */
            img = this.imgMinusOnly;
            this.dropline[0] = false;
        }

        return '<img src="' + this.imgDir + '/' + img + '" ' + attrib + ' height="20" width="20" align="middle" border="0" />';
    }

    this._setNodeIcon = function(nodeId)
    {
        var imgDir = (this.nodes[nodeId]['icondir']) ? this.nodes[nodeId]['icondir']
                                                     : this.imgDir;
        if (typeof(this.nodes[nodeId]['icon']) != 'undefined') {
            /* Node has a user defined icon. */
            if (typeof(this.nodes[nodeId]['iconopen']) != 'undefined' && this.nodes[nodeId]['expanded']) {
                img = this.nodes[nodeId]['iconopen'];
            } else {
                img = this.nodes[nodeId]['icon'];
            }
        } else {
            /* Use standard icon set. */
            if (typeof(this.nodes[nodeId]['children']) != 'undefined') {
                /* Node with children. */
                img = (this.nodes[nodeId]['expanded']) ? this.imgFolderOpen
                                                       : this.imgFolder;
            } else {
                /* Node no children. */
                img = this.imgLeaf;
            }
        }

        return '<img src="' + imgDir + '/' + img + '" align="middle" border="0" />';
    }

    this.toggle = function(nodeId)
    {
        this.nodes[nodeId]['expanded'] = (this.nodes[nodeId]['expanded']) ? false : true;
        this.saveState(nodeId, this.nodes[nodeId]['expanded'])
        this._renderTree();
    }

    this.saveState = function(nodeId, expanded)
    {
        var newCookie = '';
        var oldCookie = this._getCookie(this._instanceName + '_expanded');
        if (expanded) {
            /* Expand requested so add to cookie. */
            newCookie = (oldCookie) ? oldCookie + ',' : '';
            newCookie = newCookie + nodeId;
        } else {
            /* Collapse requested so remove from cookie. */
            var nodes = oldCookie.split(',');
            var newNodes = new Array();
            for (var i = 0; i < nodes.length; i++) {
                if (nodes[i] != nodeId) {
                    newNodes.push(nodes[i]);
                }
            }
            newCookie = newNodes.join(',');
        }
        this._setCookie(this._instanceName + '_expanded', newCookie);
    }

    this._getCookie = function(name)
    {
        var dc = document.cookie;
        var prefix = name + "=";
        var begin = dc.indexOf("; " + prefix);
        if (begin == -1) {
            begin = dc.indexOf(prefix);
            if (begin != 0) return null;
        } else {
            begin += 2;
        }
        var end = document.cookie.indexOf(";", begin);
        if (end == -1) {
            end = dc.length;
        }
        return unescape(dc.substring(begin + prefix.length, end));
    }

    this._setCookie = function(name, value)
    {
        var curCookie = name + '=' + escape(value);
        document.cookie = curCookie;
    }

}
