<?php
require_once('database.php');
require_once('errors.php');
/*
* This is the implementation of the statistics renderer.
*/
/* __ Interface ___________________________________________________________ */
/* These are the allowed graphic types. For each of them, several
* restrictions and features apply.
*/
define('TTST_GRAPHTYPE_COLUMNS', 0);
define('TTST_GRAPHTYPE_STACKED_COLUMNS', 1);
define('TTST_GRAPHTYPE_PERCENT_STACKED_COLUMNS', 2);
define('TTST_GRAPHTYPE_BOXES', 3);
define('TTST_GRAPHTYPE_BARS', 4);
define('TEXT_ROW_HEIGHT', 20);
define('COLUMN_WIDTH', 20);
define('Y_SERIE_WIDTH', 70);
$seriesColors = array('#FF6666',
'#FFCCCC',
'#CCCCFF',
'#6666FF',
'#009999',
'#009900',
'#',
'#',
'#');
/* __ State _______________________________________________________________ */
/* These variables keep track of the render state. Their values should be
* set by the appropiate funtions, and will alter the output of the render.
* All of them should have a default value. Values changed, however, are
* preserved between renders in the same page.
*/
/* Level of grouping needed. Up to 2 levels are supported.
* Possible values: 1 - 2
*/
$ttst_numLevels = 1;
$ttst_mainColumn = "";
$ttst_childColumn = "";
$ttst_countColumn = "";
$ttst_dataQuery = "";
$ttst_graphicType = TTST_GRAPHTYPE_STACKED_COLUMNS;
/* These are referred to the complete size of the graph, including legend
* and all formatting aids.
*/
$ttst_graphWidth = 700;
$ttst_graphHeight = 200;
/*
* Temp assignments, only for development.
*/
$ttst_numLevels = 2;
$ttst_mainColumn = "month";
$ttst_childColumn = "type";
$ttst_countColumn = "count";
$ttst_dataQuery = "select count(d.iid) as count,t.sname as type,".
"extract(month from d.ddetectdate) as month ".
"from defect d, defectstatus t where ".
"d.iiddefectstatus=t.iid ".
"group by t.sname, month ".
"order by month";
$ttst_graphicType = TTST_GRAPHTYPE_STACKED_COLUMNS;
$ttst_graphWidth = 400;
$ttst_graphHeight = 200;
/*
* New test
*/
$ttst_numLevels = 2;
$ttst_mainColumn = "priority";
$ttst_childColumn = "type";
$ttst_countColumn = "count";
$ttst_dataQuery = "select count(d.iid), p.sname as priority, ".
"t.sname as type FROM defect d, defecttype t, ".
"priority p WHERE ".
" d.iidpriority = p.iid AND d.iiddefecttype = t.iid ".
" GROUP BY priority,type ORDER BY priority";
$ttst_graphicType = TTST_GRAPHTYPE_STACKED_COLUMNS;
$ttst_graphWidth = 400;
$ttst_graphHeight = 200;
/* __ Implementation ______________________________________________________ */
/* __ Dataset analisys ____________________________________________________ */
/* Sets the elements of $childArray to the different childColumn values
* present in the data query.
*/
function getChildElements($connection, &$childArray)
{
global $ttst_childColumn;
global $ttst_dataQuery;
$query = "SELECT DISTINCT($ttst_childColumn) AS distinctfields ".
"FROM ($ttst_dataQuery) as f";
$res = ttdb_execQuery($connection, $query);
while (($fields = ttdb_getArray($res)) != false) {
$key = $fields['distinctfields'];
$childArray[$key] = 0; // init all values to 0
}
}
/* Sums all the values of all elements in the given array, and
* clears it.
*/
function getTotalAndClearArray(&$childArray)
{
$total = 0;
foreach ($childArray as $key => $value) {
$total += $value;
$childArray[$key] = 0;
}
return $total;
}
/* Gets the maximum values that a single mainColumn can reach.
* This function can be used for both 1 and 2 level querys.
* When used for 1 level queries, childColumn should be the same
* as mainColumn.
* TODO: This function can take some significant time in case of long
* recordsets, and is a point to optimize. However, normal statistical
* querys to be used for graphics will not be very long (otherwise,
* the won't fit in the screen anyway)
*/
function getChildLimits($connection, &$childArray, &$maximum, &$numColumns)
{
global $ttst_mainColumn;
global $ttst_childColumn;
global $ttst_dataQuery;
global $ttst_countColumn;
$maximum = 0; // will hold the maximum value found so far.
$numColumns = 0;
// Issue the query
$res = ttdb_execQuery($connection, $ttst_dataQuery);
//echo $ttst_dataQuery;
// Count values until a different maincolumn value is found.
// This is one place where the 'ORDER BY <mainColumn>' requirement is used.
$oldMainColumnValue = "";
$fields = ttdb_getArray($res);
if (!is_array($fields)) {
tter_errorWithBackButton("No defects found with the given conditions.");
exit;
}
do {
//print_r($fields);
//echo "Count column: ".$ttst_countColumn.". ";
$newMainColumnValue = $fields[$ttst_mainColumn];
//echo "new: $newMainColumnValue, old: $oldMainColumnValue<br>";
//print_r($fields); echo "<br>";
if ($oldMainColumnValue != $newMainColumnValue) {
// row changed, get the total and prepare it for the next
$sum = getTotalAndClearArray($childArray);
if ($sum > $maximum)
$maximum = $sum;
//echo "sum for '$oldMainColumnValue' = $sum. Max = $maximum<br>";
$oldMainColumnValue = $newMainColumnValue;
// will compensate for the first "fake" change by
// not adding the last one. Tricky.
$numColumns++;
}
$childArray[$fields[$ttst_childColumn]] = $fields[$ttst_countColumn];
//print_r($childArray); echo "<br>";
} while (($fields = ttdb_getArray($res)) != false);
// last case is not evaluated
$sum = getTotalAndClearArray($childArray);
if ($sum > $maximum)
$maximum = $sum;
//return $maximum;
}
/* __ Bars renderer _______________________________________________________ */
/* __ Stacked Columns Render ______________________________________________ */
/*
*
*/
function drawColumnData(&$childs, $maxValue, $clientHeight)
{
global $seriesColors;
echo "<td valign ='bottom' align='center'>\n";
echo "<table width=\"".COLUMN_WIDTH."\" border=\"0\" cellpadding=\"0\" cellspacing=\"1\">\n";
$bgColor = 0;
foreach ($childs as $key => $value) {
$currHeight = $clientHeight * $value / $maxValue;
// This is for netscape, it won't render the cell if it is empty.
// Anyway, it doesn´t render the nice black separation line.
// This is why everybody uses resized images for this effect.
// (these are the kind of arguments they used to beat MS...)
if ($value != 0) $text = " "; else $text = "";
echo "<tr bgcolor='".$seriesColors[$bgColor]."'><td height=\"$currHeight\">$text</td></tr>\n";
$bgColor++;
$childs[$key] = 0;
}
echo "</table>\n";
echo "</td>\n";
}
/*
*
*/
function drawStackedColumnsData($recordset, &$childs, $maxValue,
$clientHeight, &$XColumnData)
{
global $ttst_mainColumn;
global $ttst_childColumn;
global $ttst_countColumn;
$fields = ttdb_getArray($recordset);
$oldMainColumnValue = $fields[$ttst_mainColumn];
$XColumnData[] = $oldMainColumnValue; // add to the x axis data array
do {
$newMainColumnValue = $fields[$ttst_mainColumn];
if ($oldMainColumnValue != $newMainColumnValue) {
// mainColumn value changed, draw child table
drawColumnData(&$childs, $maxValue, $clientHeight);
$oldMainColumnValue = $newMainColumnValue;
$XColumnData[] = $oldMainColumnValue; // add to the x axis data array
}
$childs[$fields[$ttst_childColumn]] = $fields[$ttst_countColumn];
} while (($fields = ttdb_getArray($recordset)) != false);
// Last change is not detected, draw it manually.
drawColumnData(&$childs, $maxValue, $clientHeight);
}
/*
* Draws the legend of the given graph
*/
function drawLegendData($fields)
{
global $seriesColors;
echo "<table align='center' border='0' cellpadding='10' cellspacing='0'>\n";
echo "<tr>\n";
$colorIndex = 0;
foreach ($fields as $key => $value) {
echo "<td>\n";
echo "<font size=2 color='".$seriesColors[$colorIndex++]."'>";
echo "<b>".$key."</b>";
echo "</font>\n</td>\n";
}
echo "</tr>\n";
echo "</table>\n";
}
/*
*
*/
function drawXColumnData($XColumnData)
{
global $ttst_mainColumn;
// It expects the trs from outside (maybe to specify height)
echo "<td align='right'><font size=2>$ttst_mainColumn:</font></td>";
foreach ($XColumnData as $key => $value) {
echo "<td align='center'>\n";
echo "<font size=2>";
echo "<b>".$value."</b>";
echo "</font>\n</td>\n";
}
}
/* Performs the actual drawing of the series.
*
*/
function drawStackedColumns($connection, $childs, $maxValue, $maxColumns)
{
global $ttst_childColumn;
global $ttst_dataQuery;
global $ttst_graphWidth;
global $ttst_graphHeight;
// Issue query
$res = ttdb_execQuery($connection, $ttst_dataQuery);
// primary table (format)
echo "<table name='mainData' width='$ttst_graphWidth' border='0'".
" height='$ttst_graphHeight' align='center' cellspacing='0'".
" cellpadding='0'>\n";
// first row: data maximum
echo "<tr height='".TEXT_ROW_HEIGHT."'>\n";
echo "<td valign='bottom' align='right'><font size=2>$maxValue".
"</font></td>\n";
echo "</tr>\n";
// separation line
echo "<tr>\n";
for ($i = 0; $i <= $maxColumns; $i++) {
if ($i == 0)
$width = Y_SERIE_WIDTH;
else
$width = $ttst_graphWidth / $maxColumns;
echo "<td bgcolor='black' height=1 width=".
$width.">";
}
echo "</tr>\n";
// second row: cell with minValue (always 0) and columns
echo "<tr>\n";
echo "<td width='".Y_SERIE_WIDTH."' valign='bottom' align='right'>".
"<font size=2>0</font></td>\n"; // First cell with legend
drawStackedColumnsData($res, $childs, $maxValue,
$ttst_graphHeight - 3 * TEXT_ROW_HEIGHT, $XColumnData);
echo "</tr>\n";
// separation line
echo "<tr>\n";
for ($i = 0; $i <= $maxColumns; $i++) echo "<td bgcolor='black' height=1>";
echo "</tr>\n";
// mainColumn data row
echo "<tr height='".TEXT_ROW_HEIGHT."'>\n";
drawXColumnData($XColumnData);
echo "</tr>\n";
echo "</table>"; // primary table
// legend (childColumn data)
drawLegendData($childs);
}
/* Private renderer implementation depending on the type of graphic
* selected.
*/
function ttst_renderStackedColumns($connection)
{
global $ttst_numLevels;
global $ttst_mainColumn;
global $ttst_childColumn;
global $ttst_dataQuery;
global $ttst_graphicType; // opengl jamás se programará en php...
// first case, only one level
if ($ttst_numLevels == 1) {
}
// Second case, two levels have to be handled
if ($ttst_numLevels == 2) {
// Get child elements
getChildElements($connection, $childs);
// Get the limits for those elements
getChildLimits($connection, $childs, $maxValue, $maxColumns);
// Draw the table
drawStackedColumns($connection, $childs, $maxValue, $maxColumns);
}
}
/* __ Exported API ________________________________________________________ */
/*
*
*/
function ttst_render($connection)
{
// Check that all needed parameters are available
global $ttst_numLevels;
global $ttst_mainColumn;
global $ttst_childColumn;
global $ttst_dataQuery;
global $ttst_graphicType; // opengl jamás se programará en php...
global $ttst_countColumn;
// First, data columns.
switch ($ttst_numLevels) {
case 1:
if ($ttst_mainColumn == "") {
tter_error("Main column not set, Renderer will not be invoked.");
return;
}
break;
case 2:
if ($ttst_mainColumn == "") {
tter_error("Main column not set, Renderer will not be invoked.");
return;
}
if ($ttst_childColumn == "") {
tter_error("Child column not set, Renderer will not be invoked.");
return;
}
break;
default:
tter_error("Number of graphic levels not correct ($ttst_numLevels). ".
"Renderer will not be invoked");
return;
}
// Second, query
if ($ttst_dataQuery == "") {
tter_error("Statistic query not set, Renderer will not be invoked.");
return;
}
// Invoke the right renderer based on the graphic type.
switch ($ttst_graphicType) {
case TTST_GRAPHTYPE_STACKED_COLUMNS:
return ttst_renderStackedColumns($connection);
default:
tter_error("Specified graphic type not supported.");
}
}
/* __ Required Functions __________________________________________________ */
/* It will always be neeeded to call at least these funtions in order to
* invoke the render method.
*/
/*
*
*/
function ttst_setDataQuery($query)
{
// TODO: add validity checks
global $ttst_dataQuery;
$ttst_dataQuery = $query;
}
/*
*
*/
function ttst_setMainColumn($columnName)
{
// TODO: add validity checks
global $ttst_mainColumn;
$ttst_mainColumn = $columnName;
}
/*
*
*/
function ttst_setChildColumn($columnName)
{
// TODO: add validity checks
global $ttst_childColumn;
$ttst_childColumn = $columnName;
}
/*
*
*/
function ttst_setCountColumn($columnName)
{
// TODO: add validity checks
global $ttst_countColumn;
$ttst_countColumn = $columnName;
}
/*
*
*/
function ttst_setNumberOfLevels($numLevels)
{
// TODO: add validity checks
global $ttst_numLevels;
$ttst_numLevels = $numLevels;
}
/*
*
*/
function ttst_setGraphicType($type)
{
// TODO: add validity checks
global $ttst_graphicType;
$ttst_graphicType = $type;
}
/*
*
*/
function ttst_setGraphicDimensions($width, $height)
{
global $ttst_graphWidth, $ttst_graphHeight;
$ttst_graphWidth = $width;
$ttst_graphHeight = $height;
}
?>