<?php
/**
* Renders classes.
*
* @version  $Id: PhpdocHTMLClassRenderer.php,v 1.4 2002/04/11 15:39:33 timmyg Exp $
*/
class PhpdocHTMLClassRenderer extends PhpdocHTMLDocumentRenderer {

    /**
    * Internal array of "&nbsp;" strings to format HTML output.
    *
    * @var  array
    */
    var $indent = array();

    /**
    * Array of variables found in the xml document.
    *
    * @var  array
    */
    var $variables = array();

    /**
    * Sets the xml and template root directory.
    * 
    * @param    string  XML file path
    * @param    string  Template file path
    * @param    string  Name of the current application
    * @param    string  Filename extension
    * @see      setPath(), setTemplateRoot()
    */
    function PhpdocHTMLClassRenderer($path, $templateRoot, $application, $extension = ".html") {

        $this->setPath($path);
        $this->setTemplateRoot($templateRoot);
        $this->application = $application;
        $this->file_extension = $extension;
        
        $this->accessor = new PhpdocClassAccessor;
        $this->tpl = new IntegratedTemplate($this->templateRoot);
        $this->fileHandler = new PhpdocFileHandler;

    } // end constructor

    /**
    * Renders a class.
    *
    * @param    string  XML source file
    * @param    string  Name of the HTML target file.
    * @access   public
    */    
    function renderClass($xmlfile, $htmlfile = "") {

        $this->tpl->loadTemplatefile("class.html");    
        if ("" == $htmlfile)
            $htmlfile = substr($xmlfile, 6, -4) . $this->file_extension;

        $this->accessor->loadXMLFile($this->path.$xmlfile);
        
        $this->renderSubclasses();
        $this->renderInherited();
        $this->renderFunctions();
        $this->renderVariables();
        $this->renderUses();
        $this->renderConstants();
        
        $class = $this->accessor->getClassdata();
        $tplvars = array();

        $tplvars["CLASS_FILE"]      = $class["file"]["value"];
        $tplvars["CLASS_NAME"]      = $class["name"];
        $tplvars["CLASS_ACCESS"]    = $class["access"];
        $tplvars["CLASS_PACKAGE"]   = $class["package"];

        if ("" != $class["extends"])
            $tplvars["CLASS_EXTENDS"] = sprintf('extends <a href="%s">%s</a>', 
                                                $class["extends"].$this->file_extension, 
                                                $class["extends"]
                                            );
            
        $tplvars["CLASS_UNDOC"]    = ("true" == $class["undoc"]) ? $this->undocumented : "";
        
        $tplvars["CLASS_ABSTRACT"] = ("true" == $class["abstract"]) ? "abstract" : "";
        $tplvars["CLASS_STATIC"]   = ("true" == $class["static"]) ? "static" : "";
        $tplvars["CLASS_FINAL"]    = ("true" == $class["final"]) ? "final" : "";
        
        $tplvars["CLASS_TREE"]     = $this->getClasstree($class["name"]);
        
        if (isset($class["doc"]["link"]))
            $this->renderLinks($class["doc"]["link"], "class_");
            
        if (isset($class["doc"]["author"]))
            $this->renderAuthors($class["doc"]["author"], "class_");
            
        if (isset($class["doc"]["see"]))
            $this->renderSee($class["doc"]["see"], "class_");
        
        $fields = array("version", "deprecated", "copyright", "since", "magic");
        reset($fields);
        while (list($k, $field) = each($fields)) 
            if (isset($class["doc"][$field])) {
                $this->tpl->setCurrentBlock("class_" . strtolower($field));
                $this->tpl->setVariable(strtoupper($field), $class["doc"][$field]["value"]);
                $this->tpl->parseCurrentBlock();
            }

        $fields = array( "description", "shortdescription" );

        reset($fields);
        while (list($k, $field) = each($fields)) 
            if (isset($class["doc"][$field]))
                $tplvars["CLASS_".strtoupper($field)] = $this->encode($class["doc"][$field]["value"]);

        $this->tpl->setCurrentBlock("__global__");
        $this->tpl->setVariable($tplvars);

        // 3/11/2002 - Tim Gallagher added the next two lines
        // so the version and link could be put in and easily
        // changed as versions, and urls change.
        $this->tpl->setVariable("PHPDOCVERSION", PHPDOC_VERSION);
        $this->tpl->setVariable("PHPDOC_LINK", PHPDOC_LINK);
        $this->tpl->setVariable("PHPDOC_GENERATED_DATE", PHPDOC_GENERATED_DATE);
        
        $this->tpl->setVariable("APPNAME", $this->application);

        $this->fileHandler->createFile($this->path.$htmlfile, $this->tpl->get());
        $this->tpl->free();    

    } // end func renderClass

    /**
    * Renders a list of inherited elements.
    *
    * @see  renderInheritedElements()
    */
    function renderInherited() {

        $this->renderInheritedElements(    $this->accessor->getInheritedFunctions(),
                                            "inheritedfunctions",
                                            "function"
                                        );
                                                                    
        $this->renderInheritedElements( $this->accessor->getInheritedVariables(),
                                            "inheritedvariables",
                                            "variable"
                                        );

        $this->renderInheritedElements( $this->accessor->getInheritedConstants(),
                                            "inheritedconstants",
                                            "constant"
                                        );

        $this->renderInheritedElements(    $this->accessor->getInheritedUses(),
                                            "inheriteduses",
                                            "uses"
                                        );

    } // end func renderInherited

    /**
    * Renders a list of a certain inherited element.
    *
    * @param    array   List of inherited elements.
    * @param    string  Templateblockname
    * @param    string  Element type: function, variable...
    * @see      renderInherited()
    */
    function renderInheritedElements($inherited, $block, $type) {
        
        if (0 == count($inherited))
            return;

        $this->tpl->setCurrentBlock($block);

        reset($inherited);
        while (list($source, $elements) = each($inherited)) {
            
            $value = "";
            
            reset($elements);
            while (list($k, $element) = each($elements))
                $value .= sprintf('<a href="%s#%s_%s">%s</a>, ', 
                                        $source.$this->file_extension,
                                        $type, 
                                        $element, 
                                        $element
                                );
            $value = substr($value, 0, -2);
            
            $this->tpl->setVariable("SOURCE", $source);
            $this->tpl->setVariable("ELEMENTS", $value);
            $this->tpl->parseCurrentBlock();
        }

    } // end func renderInheritedElements

    /**
    * Renders a list of direct known subclasses.
    */
    function renderSubclasses() {
        
        $subclasses = $this->accessor->getSubclasses();
        if (0 == count($subclasses)) 
            return;
        
        $elements = "";
        reset($subclasses);
        while (list($k, $subclass) = each($subclasses))
            $elements .= sprintf('<a href="%s">%s</a>, ', $subclass.$this->file_extension, $subclass);
        
        $elements    = substr($elements, 0, -2);
        
        if ("" != $elements) {
        
            $this->tpl->setCurrentBlock("subclasses");
            $this->tpl->setVariable("ELEMENTS", $elements);
            $this->tpl->parseCurrentBlock();
        }

    } // end func renderSubclasses

    /**
    * Adds a summary and a detailed list of all variables to the template.
    *
    * @see  renderVariableSummary(), renderVariableDetail()
    */
    function renderVariables() {
        
        $this->variables["private"] = $this->accessor->getVariablesByAccess("private");
        $this->variables["public"]     = $this->accessor->getVariablesByAccess("public");
        
        if (0 == count($this->variables["private"]) && 0 == count($this->variables["public"]))
            return;
        
        $this->renderVariableSummary();
        $this->renderVariableDetail();

        $this->variables = array();

    } // end func renderVariables

    /**
    * Adds a summary of all variables to the template.
    * 
    * The function assumes that there is a block named "variablesummary" and
    * within it a block names "variablesummay_loop" in the template.
    *
    * @see  renderVariableDetail()
    */    
    function renderVariableSummary() {

        reset($this->accessModifiers);
        while (list($k, $access) = each($this->accessModifiers)) {

            if (0 == count($this->variables[$access]))
                continue;
                
            $this->tpl->setCurrentBlock("variablesummary_loop");
            
            reset($this->variables[$access]);
            while (list($name, $variable) = each($this->variables[$access])) {
                
                $this->tpl->setVariable("NAME", $name);
                $this->tpl->setVariable("TYPE", $variable["type"]);
                
                if (isset($variable["doc"]["shortdescription"]))
                    $this->tpl->setVariable("SHORTDESCRIPTION", $this->encode($variable["doc"]["shortdescription"]["value"]));
            
                $this->tpl->parseCurrentBlock();                
                
            }
            
            $this->tpl->setCurrentBlock("variablesummary");
            $this->tpl->setVariable("ACCESS", ucfirst($access));
            $this->tpl->parseCurrentBlock();
            
        }

    } // end func renderVariableSummary

    /**
    * Adds a detailed list of all variables to the template.
    * 
    * The function assumes that there is a block named "variabledetails"
    * and within it a block names "variablesdetails_loop" in the template.
    *
    * @see  renderVariableSummary()
    */    
    function renderVariableDetail() {
        
        reset($this->accessModifiers);
        while (list($k, $access) = each($this->accessModifiers)) {

            if (0 == count($this->variables[$access]))
                continue;

            reset($this->variables[$access]);
            while (list($name, $variable) = each($this->variables[$access])) {
            
                $tplvars = array();
                $tplvars["NAME"]    =    $variable["name"];
                $tplvars["ACCESS"]  = $variable["access"];
                $tplvars["TYPE"]    = $variable["type"];
                $tplvars["VALUE"]   = htmlentities($variable["value"]);

                if ("true" == $variable["undoc"]) 
                    $tplvars["UNDOC"] = $this->undocumented;

                if ("true" == $variable["static"])
                    $tplvars["STATIC"] = "static";

                if ("true" == $variable["final"])
                    $tplvars["FINAL"] = "final";

                if (isset($variable["doc"]["shortdescription"]))
                    $tplvars["SHORTDESCRIPTION"] = $this->encode($variable["doc"]["shortdescription"]["value"]);

                if (isset($variable["doc"]["description"]))
                    $tplvars["DESCRIPTION"] = $this->encode($variable["doc"]["description"]["value"]);

                $this->renderCommonDocfields("variabledetails_", $variable);

                $this->tpl->setCurrentBlock("variabledetails_loop");    
                $this->tpl->setVariable($tplvars);
                $this->tpl->parseCurrentBlock();    

            }

            $this->tpl->setCurrentBlock("variabledetails");
            $this->tpl->setVariable("ACCESS", ucfirst($access) );
            $this->tpl->parseCurrentBlock();

        }

    } // end func renderVariableDetail

    /**
    * Returns a html string that shows the class tree.
    *
    * @param    string  name of the current class
    * @return   string  HTML that shows the tree
    */
    function getClasstree($class) {
        
        $path = $this->accessor->getClasstree();
        $level = 0;
        $num = count($path) - 1;
        
        for ($i = $num; $i >= 0; --$i) {

            $indent = $this->getIndent($level);
            // 3/7/2002 - Tim Gallagher<timg@sunflowerroad.com>
            // modified the line below to remove an extra space before the pipe character.
            if ($level > 0)
                $value.= sprintf("%s |<br>%s+-- ", $indent, $indent);

            $value.= sprintf('<a href="%s">%s</a><br>', 
                                $path[$i] . $this->file_extension,
                                $path[$i]
                            );
            ++$level;
            
        }

        $indent = $this->getIndent($level);
        // 3/7/2002 - Tim Gallagher<timg@sunflowerroad.com>
        // modified the line below to remove an extra space before the pipe character.
        if ($level > 0)
            $value.= sprintf("%s |<br>%s+-- ", $indent, $indent);

        $value.= sprintf('%s<br>', $class);

        return $value;
    } // end func getClasstree

    /**
    * Returns a certain number of "&nbsp;"s.
    *
    * @param    int     number of "&nbsp;" required.
    * @see      $indent
    * @return   string   A string with the requested number of nunbreakable html spaces
    */
    function getIndent($level) {

        if (!isset($this->indent[$level])) {

            $html = "";
            for ($i = 0; $i < $level; ++$i)
                $html .= "&nbsp;&nbsp;";

            $this->indent[$level] = $html;

        }

        return $this->indent[$level];
    } // end func getIndent

} // end class PhpdocHTMLClassRenderer
?>
