<?php
/*
Copyright 2008 Josh Heidenreich
 
This file is part of Pelzini.
 
Pelzini 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, either version 3 of the License, or
(at your option) any later version.
 
Pelzini 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 Pelzini.  If not, see <http://www.gnu.org/licenses/>.
*/
 
/**
 * Shows information about a specific class
 *
 * @package Viewer
 * @author Josh Heidenreich
 * @since 0.1
 * @see ParserClass
 * @tag i18n-done
 **/
 
require_once 'functions.php';
 
 
define('PAGE_CLASS_GENERAL',  0); define('PAGE_CLASS_USED_BY',  1); define('PAGE_CLASS_EXTENDS',  2); define('PAGE_CLASS_SOURCE',   3);  
 
$_GET['page'] = (int) @$_GET['page'];
 
 
$sql_name = db_quote($_GET['name']);
$q = new SelectQuery();
$q->addFields('classes.id, classes.name, namespaces.name AS namespace, classes.description, classes.extends, files.name as filename,
  classes.final, classes.abstract, classes.sinceid, classes.projectid, classes.deprecated');
$q->setFrom('classes');
$q->addInnerJoin('files ON classes.fileid = files.id');
$q->addLeftJoin('namespaces ON classes.namespaceid = namespaces.id');
$q->addWhere("classes.name = {$sql_name}");
$q->addProjectWhere();
 
if (isset($_GET['file'])) {     $sql_name = db_quote($_GET['file']);
    $q->addWhere("files.name = {$sql_name}");
}
 
$q = $q->buildQuery();
$res = db_query($q);
 
if (db_num_rows($res) == 0) {
    require_once 'head.php';
    echo '<h2>', str(STR_ERROR_TITLE), '</h2>';
    echo '<p>', str(STR_CLASS_INVALID), '</p>';
    require_once 'foot.php';
 
} else if (db_num_rows($res) > 1) {
    require_once 'head.php';
    echo '<h2>', str
(STR_MULTIPLE_TITLE
, 'NUM', db_num_rows
($res), 'TYPE', strtolower(str
(STR_CLASSES
))), '</h2>';  
    echo '<div class="list">';
    while ($row = db_fetch_assoc($res)) {
        $name_parts[] = str(STR_IN_FILE, 'VAL', $row['filename']);
 
 
        echo '<div class="item">';
        echo '</div>';
    }
    echo '</div>';
 
    require_once 'foot.php';
 
} else {
    $class = db_fetch_assoc($res);
}
 
 
$skin['page_name'] = str(STR_CLASS_BROWSER_TITLE, 'name', $class['name']);
require_once 'head.php';
 
 
// Pages
    str(STR_CLASS_PAGE_GENERAL),
    str(STR_CLASS_PAGE_USED_BY),
    str(STR_CLASS_PAGE_EXTENDS),
    str(STR_CLASS_PAGE_SOURCE)
);
 
echo "<div class=\"viewer_options\">";
echo '<p><b>', str(STR_CLASS_PAGE), '</b></p>';
foreach ($pages as $num => $page) {
    if ($_GET['page'] == $num) {
        echo "<p class=\"on\"><a href=\"class?name={$url_name}&page={$num}\">{$page}</a></p>";
    } else {
        echo "<p><a href=\"class?name={$url_name}&page={$num}\">{$page}</a></p>";
    }
}
echo "</div>";
 
// Page options
if ($_GET['page'] == 0) {
    echo "<div class=\"viewer_options\">";
    echo '<p><b>', str(STR_CLASS_OPTIONS), '</b></p>';
    if (@$_GET['complete'] == 1) {
        echo "<p class=\"on\"><a href=\"class?name={$url_name}\">", str(STR_CLASS_INHERITED), "</a></p>";
    } else {
        echo "<p><a href=\"class?name={$url_name}&complete=1\">", str(STR_CLASS_INHERITED), "</a></p>";
    }
    echo "</div>";
}
 
 
 
 
echo '<h2>', str(STR_CLASS_PAGE_TITLE, 'name', $class['name']), '</h2>';
 
if ($class['deprecated'] !== null) {
    echo '<p><span class="deprecated">', str(STR_CLASS_DEPRECATED), '</span></p>';
    if ($class['deprecated']) echo '<br>', process_inline($class['deprecated']);
    echo '</p>';
}
 
echo '<div class="main-description">';
echo process_inline($class['description']);
echo '</div>';
 
 
// Basic class details
echo "<ul>";
echo '<li>', str(STR_FILE, 'filename', $class['filename']), '</li>';
 
if ($class['namespace'] != null) {
    echo '<li>', str(STR_NAMESPACE, 'name', get_namespace_link($class['namespace'])), '</li>';
}
 
if ($class['extends'] != null) {
    echo '<li>', str(STR_CLASS_EXTENDS, 'link', get_object_link($class['extends'])), '</li>';
}
 
// Show implements
$q = "SELECT name FROM class_implements WHERE classid = {$class['id']}";
$res = db_query ($q);
 
if (db_num_rows ($res) > 0) {
    echo '<li>', str(STR_CLASS_IMPLEMENTS);
 
    $j = 0;
    while ($row = db_fetch_assoc ($res)) {
        if ($j++ > 0) echo ', ';
        echo get_object_link ($row['name']);
    }
    echo '</li>';
}
 
if ($class['abstract'] == 1) echo '<li>', str(STR_CLASS_ABSTRACT), '</li>';
if ($class['final'] == 1) echo '<li>', str(STR_CLASS_FINAL), '</li>';
 
if ($class['sinceid']) {
    echo '<li>', str(STR_AVAIL_SINCE, 'version', get_since_version($class['sinceid'])), '</li>';
}
echo "</ul>";
 
 
show_examples($class['id'], LINK_TYPE_CLASS);
 
 
switch ($_GET['page']) {
case PAGE_CLASS_GENERAL:
    // Determine a list of variables and functions
 
    if (@$_GET['complete'] == 1) {
        $name = $class['name'];
        $filename = $class['filename'];
 
        do {
            $result = load_class($project['id'], $name, $filename);
            if ($result == null) break;
 
            list ($funcs, $vars, $parent) = $result;  
 
            $name = $parent;
            $filename = null;
        } while ($name != null);
 
    } else {
        list($functions, $variables) = load_class
($project['id'], $class['name'], $class['filename']);     }
 
 
    show_authors ($class['id'], LINK_TYPE_CLASS);
    show_tables ($class['id'], LINK_TYPE_CLASS);
 
 
    // Show variables
    if (count($variables) > 0) {         echo '<a name="variables"></a>';
        echo '<h3>', str(STR_VARIABLES), '</h3>';
        echo "<table class=\"function-list\">\n";
        echo '<tr><th>', str(STR_NAME), '</th><th>', str(STR_VISIBILITY), '</th><th>', str(STR_DESCRIPTION), "</th></tr>\n";
        foreach ($variables as $row) {
            if (!isset($row['visibility'])) $row['visibility'] = '';  
            // encode for output
            if ($row['description'] == null) $row['description'] = ' ';
 
            if ($row['static']) $row['visibility'] .= ' ' . str(STR_CLASS_VAR_STATIC);
 
            // display
            echo "<tr>";
            echo "<td><code>{$row['name']}</code></td>";
            echo "<td>{$row['visibility']}</td>";
            echo "<td>{$row['description']}</td>";
            echo "</tr>\n";
        }
        echo "</table>\n";
    }
 
    // Show functions
    if (count($functions) > 0) {     	$base_url = $_SERVER['REQUEST_URI'];
        echo '<h3>', str(STR_FUNCTIONS), '</h3>';
        echo "<table class=\"function-list\">\n";
        echo '<tr><th>', str(STR_NAME), '</th><th>', str(STR_VISIBILITY), "</th><th>", str(STR_DESCRIPTION), "</th></tr>\n";
        foreach ($functions as $row) {
            if (!isset($row['visibility'])) $row['visibility'] = '';  
            // encode for output
 
            if ($row['description'] == null) {
                $summary = ' ';
            } else {
                $summary = delink_inline($lines[0]);
            }
 
            if ($row['static']) $row['visibility'] .= ' ' . str(STR_CLASS_VAR_STATIC);
 
			$url = get_function_link($row['classname'], $row['name']);
 
            // display
            echo "<tr>";
            echo "<td>{$url}</td>";
            echo "<td>{$row['visibility']}</td>";
            echo "<td>{$summary}</td>";
            echo "</tr>\n";
        }
        echo "</table>\n";
    }
 
 
    // Show functions
    if (count($functions) > 0) {         foreach ($functions as $row) {
            if ($row['description'] == null) {
                $row['description'] = '<em>This function does not have a description</em>';
            }
 
            // display
            echo "<a name=\"func-", $row['name'], "\"></a>";
            echo "<h3>{$row['visibility']} ", get_function_link($row['classname'], $row['name']);
            if ($row['classname'] != $class['name']) {
                echo " <small>(from ", get_class_link($row['classname']), ")</small>";
            }
            echo "</h3>";
 
            show_function_usage($row['id']);
            echo '<br>';
            echo process_inline($row['description']);
        }
    }
    break;
 
 
case PAGE_CLASS_USED_BY:
    // Loads the classes tree
    // and finds this class within it
    $root = create_classes_tree();
    $matcher = new FieldTreeNodeMatcher('name', $class['name']);
    $node = $root->findNode($matcher);
 
    // If our class was found - which it should be - find the top ancestor
    // and then draw unordered lists of the class structure
    if ($node != null) {
        echo '<h3>', str(STR_CLASS_STRUCTURE), '</h3>';
 
        $ancestors = $node->findAncestors();
 
        echo "<ul class=\"tree\">\n";
        draw_class_tree
($top, array($node));        echo "</ul>\n";
    }
 
 
    $sql_class_name = db_quote ($class['name']);
 
    // Query to get functions which return this class
    $q = "SELECT functions.id, functions.name, functions.description, functions.classid,
          files.name as filename, functions.fileid, classes.name as class
      FROM functions
      INNER JOIN files ON functions.fileid = files.id
      INNER JOIN returns ON returns.functionid = functions.id
      LEFT JOIN classes ON functions.classid = classes.id
      WHERE returns.type = {$sql_class_name}
        AND functions.projectid = {$class['projectid']}
      ORDER BY functions.name";
    $res = db_query ($q);
 
    // Display any functions which return this class
    if (db_num_rows ($res) > 0) {
        echo '<h3>', str(STR_CLASS_FUNC_RETURN), '</h3>';
 
        echo '<div class="list">';
        while ($row = db_fetch_assoc ($res)) {
            $class = 'item';
            if ($alt) $class .= '-alt';
 
            echo "<div class=\"{$class}\">";
            echo "<img src=\"assets/icon_remove.png\" alt=\"\" title=\"Hide this result\" onclick=\"hide_content(event)\" class=\"showhide\">";
            echo "<p><strong>", get_function_link($row['class'], $row['name']), "</strong>";
 
            if ($row['class'] != null) {
                echo " <small>from class ", get_class_link($row['class']), "</small>";
            }
 
            echo "<div class=\"content\">";
            echo delink_inline($row['description']);
            echo "<br><small>From ", get_file_link($row['filename']), "</small></div>";
            echo "</div>";
 
            $alt = ! $alt;
        }
        echo '</div>';
    }
 
 
    // Query to get functions which use this class as an argument
    $q = "SELECT functions.id, functions.name, functions.description, functions.classid,
          files.name as filename, functions.fileid, classes.name as class, arguments.name as argname
      FROM functions
      INNER JOIN arguments ON arguments.functionid = functions.id
      INNER JOIN files ON functions.fileid = files.id
      LEFT JOIN classes ON functions.classid = classes.id
      WHERE arguments.type = {$sql_class_name}
        AND functions.projectid = {$class['projectid']}
      ORDER BY functions.name";
    $res = db_query ($q);
 
    // Display any functions which use this class as an argument
    if (db_num_rows ($res) > 0) {
        echo '<h3>', str(STR_CLASS_FUNC_ARG), '</h3>';
 
        echo '<div class="list">';
        while ($row = db_fetch_assoc ($res)) {
            $class = 'item';
            if ($alt) $class .= '-alt';
 
            echo "<div class=\"{$class}\">";
            echo "<img src=\"assets/icon_remove.png\" alt=\"\" title=\"Hide this result\" onclick=\"hide_content(event)\" class=\"showhide\">";
            echo "<p><strong>", get_function_link($row['class'], $row['name']), "</strong>";
 
            if ($row['class'] != null) {
                echo " <small>from class ", get_class_link($row['class']), "</small>";
            }
 
            echo "<div class=\"content\">";
            echo delink_inline($row['description']);
            echo "<br><small>Argument name: {$row['argname']}</small>";
            echo "<br><small>From ", get_file_link($row['filename']), "</small>";
            echo "</div>";
            echo "</div>";
 
            $alt = ! $alt;
        }
        echo '</div>';
    }
    break;
 
 
case PAGE_CLASS_EXTENDS:
    echo '<h3>', str(STR_CLASS_EXTENDING), '</h3>';
 
    require_once 'php_code_renderer.php';
    $renderer = new PHPCodeRenderer();
    $code = $renderer->drawClassExtends ($class['id']);
 
    echo "<pre class=\"source\">";
    echo "</pre>";
    break;
 
 
case PAGE_CLASS_SOURCE:
    require_once 'search_functions.php';
    search_source ($class['name'], true);
    break;
 
 
default:
    echo '<h3>', str(STR_ERROR_TITLE), '</h3>';
    echo '<p>', str(STR_CLASS_INVALID_INFO), '</p>';
    break;
}
 
show_see_also ($class['id'], LINK_TYPE_CLASS);
show_tags ($class['id'], LINK_TYPE_CLASS);
 
 
require_once 'foot.php';
 
 
/**
 * @param int $project_id
 * @param string $name
 * @param string $filename
 * @return array
 * [0] => functions
 * [1] => variables
 * [2] => name of parent class
 **/
function load_class($project_id, $name, $filename = null)
{
    $project_id = (int) $project_id;
 
    // determine parent class
    $name_sql = db_escape($name);
    $q = "SELECT classes.id, classes.extends
        FROM classes
        INNER JOIN files ON classes.fileid = files.id
        WHERE classes.projectid = {$project_id}
          AND classes.name LIKE '{$name_sql}'";
 
    if ($filename) {
        $name_sql = db_escape($filename);
        $q .= " AND files.name = '{$name_sql}'";
    }
 
    $res = db_query($q);
    if (db_num_rows($res) != 1) {
        return null;
    }
 
    $row = db_fetch_assoc($res);
    $id = $row['id'];
    $parent = $row['extends'];
 
    // determine functions
    $q = "SELECT *, '{$name}' AS classname FROM functions WHERE classid = {$id}";
    $res = db_query($q);
    while ($row = db_fetch_assoc($res)) {
        $functions[$row['name']] = $row;
    }
 
    // determine variables
    $q = "SELECT *, '{$name}' AS classname FROM variables WHERE classid = {$id}";
    $res = db_query($q);
    while ($row = db_fetch_assoc($res)) {
        $variables[$row['name']] = $row;
    }
 
    return array($functions, $variables, $parent); }
 
 
/**
 * Draws the tree from this node and below as unordered lists within unordered lists
 *
 * @param array $higlight_nodes The nodes to put class="on" for the LI element.
 **/
function draw_class_tree($node, $higlight_nodes)
{
    // Draw this item
    if (in_array($node, $higlight_nodes, true)) {         echo '<li class="on">', get_object_link($node['name']);
    } else {
        echo '<li>', get_object_link($node['name']);
    }
 
    // Draw its children if it has any
    $children = $node->getChildren();
    usort($children, 'nodenamesort');  
    if (count($children) > 0) {         echo "<ul>\n";
        foreach ($children as $child) {
            draw_class_tree($child, $higlight_nodes);
        }
        echo "</ul>\n";
    }
 
    echo "</li>\n";
}
 
 
function nodenamesort($a, $b)
{
}
 
 
?>