/*
 *	aegis - project change supervisor
 *	Copyright (C) 1997, 1998, 2001-2003 Peter Miller;
 *	All rights reserved.
 *
 *	This program 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 2 of the License, or
 *	(at your option) any later version.
 *
 *	This program 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 this program; if not, write to the Free Software
 *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 *
 * MANIFEST: report statistics about a project
 */

auto pn;
pn = project_name();

auto script_name;
script_name = getenv("SCRIPT_NAME");
if (script_name == "")
	script_name = "http://localhost/cgi-bin/aegis.cgi";

columns({width = 1000; });
print("Content-Type: text/html");
print("");
print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\""
	## "\"http://www.w3.org/TR/REC-html40/loose.dtd\">");
print("<html><head>");
print("<meta name=\"ROBOTS\" content=\"NOINDEX, NOFOLLOW\">");
print("<meta name=\"GENERATOR\" content=\"" ## script_name ## "\">");
print("<meta http-equiv=\"Content-Type\" "
	## "content=\"text/html; charset=ISO-8859-1\">");
print("<style type=\"text/css\"> "
	## "tr.even-group { background-color: #CCCCCC; } "
	## "body { background-color: white; } "
	## "</style>");
/*
 * Netscape 4.x has numerous CSS bugs, two of which need mentioning.
 * 1. If a style sheet is not present Netscape says 404 Not found, when
 * it should silently ignore it.  2. Style sheets who's media is not
 * "screen" will be ignored.  Fortunately we can use (2) to get around (1).
 */
print("<link rel=\"stylesheet\" type=\"text/css\" href=\"/aedefault.css\" "
	## "media=\"all\">");
auto stack, depth, n;
depth=0;
stack[depth] = project[pn].state.name;
while ("" != ( n = project[stack[depth]].state.parent_name )) {
  stack[++depth] = n;
}
while ( depth >= 0) {
    print("<link rel=\"stylesheet\" type=\"text/css\" href=\"/" ##
      stack[depth--] ## ".css\" " ## "media=\"all\">");
}
print("<title>");
print("Project " ## quote_html(pn) ## " Statistics");
print("</title></head><body><h1 align=center>");

auto href;
print("<a href=\"" ## script_name ## "\">Project</a>");
auto long_project_name;
auto prj_name_parts;
prj_name_parts = split(pn, '.');
href = script_name ## "?file@proj_menu+project@"
	## quote_url(prj_name_parts[0]);
long_project_name = "<a href=\"" ## href ## "\" >"
	## quote_html(prj_name_parts[0]) ## "</a>";
auto j;
for (j = 1; j < count(prj_name_parts); j++)
{
    href ##= '.' ## prj_name_parts[j];
    long_project_name ##= ".<a href=\"" ## href ## "\" >"
    	## quote_html(prj_name_parts[j]) ## "</a>";
};
long_project_name = "``" ## long_project_name ## "'',<br>";
/* HTTP limits lines to 510 characters */
for (j in wrap(long_project_name, 510))
    print(j);

print("Statistics");
print("</h1>");
print("<div class=\"information\">");

print("This page provides a number of statistical projections of the");
print("audit data collected as changes progress through the development");
print("process.");

auto p, ps;
p = project[pn];
ps = p.state.branch;

/*
 * traverse each change
 */
auto cause_stats, cause_total;
auto file_action_stats, file_action_total;
auto file_usage_stats, file_usage_total;
auto hist_now, hist_time, hist_state, hist_stats, hist_total;
auto hist_total_min, hist_total_max;
auto hist_chan, hist_min, hist_max;
hist_now = now();
auto cn, cs, idx;
hist_min = { garbage = 0; };
hist_max = { garbage = 0; };
for (cn in keys(ps.change))
{
    cs = ps.change[cn];
    cause_stats[cs.cause]++;
    cause_total++;

    for (idx in cs.src)
    {
       	file_action_stats[idx.action]++;
       	file_action_total++;
       	if (idx.usage != build || idx.action != modify)
       	{
	    file_usage_stats[idx.usage]++;
	    file_usage_total++;
       	}
    }

    cs.history ##= [{ when = hist_now; what = integrate_pass; }];
    hist_chan = { garbage = 0; };
    for (idx in cs.history)
    {
       	if (idx.what == new_change)
       	{
	    hist_time = idx.when;
	    hist_state = awaiting_development;
	    continue;
       	}
       	hist_chan[hist_state] += working_days(hist_time, idx.when);
       	hist_time = idx.when;
       	if (idx.what == new_change)
	    hist_state = awaiting_development;
       	else if (idx.what == develop_begin)
	    hist_state = being_developed;
       	else if (idx.what == develop_begin_undo)
	    hist_state = awaiting_development;
       	else if (idx.what == develop_end)
	    hist_state = being_reviewed;
       	else if (idx.what == develop_end_2ar)
	    hist_state = awaiting_review;
       	else if (idx.what == develop_end_2ai)
	    hist_state = awaiting_integration;
       	else if (idx.what == develop_end_undo)
	    hist_state = being_developed;
       	else if (idx.what == review_begin)
	    hist_state = being_reviewed;
       	else if (idx.what == review_begin_undo)
	    hist_state = awaiting_review;
       	else if (idx.what == review_fail)
	    hist_state = being_developed;
       	else if (idx.what == review_pass)
	    hist_state = awaiting_integration;
       	else if (idx.what == review_pass_undo)
	    hist_state = being_reviewed;
       	else if (idx.what == integrate_begin)
	    hist_state = being_integrated;
       	else if (idx.what == integrate_begin_undo)
	    hist_state = awaiting_integration;
       	else if (idx.what == integrate_fail)
	    hist_state = being_developed;
       	else
	    break;
    }

    for (idx in [awaiting_development, being_developed, awaiting_review,
       	being_reviewed, awaiting_integration, being_integrated])
    {
       	j = hist_chan[idx];
       	hist_stats[idx] += j;
       	if (!hist_min[idx] || j < hist_min[idx])
	    hist_min[idx] = j;
       	if (j > hist_max[idx])
	    hist_max[idx] = j;
    }
    j = working_days(cs.history[0].when, hist_time);
    hist_total += j;
    if (!hist_total_min || j < hist_total_min)
       	hist_total_min = j;
    if (j > hist_total_max)
	hist_total_max = j;
}

/*
 * print statistics about change state durations
 */
print("<hr>");
print("<h2>Change Duration By State</h2>");
print("<table align=center>");
print("<tr><th>Change State</th><th>Working Days</th><th>Minimum</th>");
print("<th>Average</th><th>Maximum</th></tr>");
for (idx in [awaiting_development, being_developed, awaiting_review,
    being_reviewed, awaiting_integration, being_integrated])
{
    hist_time = hist_stats[idx];
    print("<tr><td valign=top>");
    print(idx);
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f", hist_time));
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f", hist_min[idx]));
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f", hist_time * 1. / cause_total));
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f", hist_max[idx]));
    print("</td></tr>");
}
print("<tr><td></td><td><hr></td><td><hr></td><td><hr></td><td><hr></td></tr>");
print("<tr><td valign=top>Total");
print("</td><td valign=top align=right>");
print(sprintf("%.2f", hist_total));
print("</td><td valign=top align=right>");
print(sprintf("%.2f", hist_total_min));
print("</td><td valign=top align=right>");
print(sprintf("%.2f", hist_total * 1. / cause_total));
print("</td><td valign=top align=right>");
print(sprintf("%.2f", hist_total_max));
print("</td></tr>");
print("</table>");

/*
 * print statistics about change causes
 */
print("<hr>");
print("<h2>Change Cause Distribution</h2>");
print("<table align=center>");
print("<tr><th>Change Cause</th><th>Count</th><th>Percent</th></tr>");
for (idx in sort(keys(cause_stats)))
{
    print("<tr><td valign=top>");
    print(idx);
    print("</td><td valign=top align=right>");
    print(cause_stats[idx]);
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f%%", 100. * cause_stats[idx] / cause_total));
    print("</td></tr>");
}
print("<tr><td></td><td><hr></td><td></td></tr>");
print("<tr><td valign=top>Total");
print("</td><td valign=top align=right>");
print(cause_total);
print("</td><td valign=top align=right>");
print("</td></tr>");
print("</table>");

/*
 * print statistics about file actions
 */
print("<hr>");
print("<h2>Change File Action Distribution</h2>");
print("<table align=center>");
print("<tr><th>Action</th><th>Count</th>");
print("<th>Percent</th><th>Average</th></tr>");
for (idx in sort(keys(file_action_stats)))
{
    print("<tr><td valign=top>");
    print(idx);
    print("</td><td valign=top align=right>");
    print(file_action_stats[idx]);
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f%%", 100. * file_action_stats[idx] / file_action_total));
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f", file_action_stats[idx] * 1. / cause_total));
    print("</td></tr>");
}
print("<tr><td></td><td><hr></td><td></td><td><hr></td></tr>");
print("<tr><td valign=top>Total");
print("</td><td valign=top align=right>");
print(file_action_total),
print("</td><td></td><td valign=top align=right>");
print(sprintf("%.2f", file_action_total * 1. / cause_total));
print("</td></tr>");
print("</table>");

/*
 * print statistics about file usages
 */
print("<hr>");
print("<h2>Change File Type Distribution</h2>");
print("<table align=center>");
print("<tr><th>Type</th><th>Count</th><th>Percent</th><th>Average</th></tr>");
for (idx in sort(keys(file_usage_stats)))
{
    print("<tr><td valign=top>");
    print(idx);
    print("</td><td valign=top align=right>");
    print(file_usage_stats[idx]);
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f%%", 100. * file_usage_stats[idx] / file_usage_total));
    print("</td><td valign=top align=right>");
    print(sprintf("%.2f", file_usage_stats[idx] * 1. / cause_total));
    print("</td></tr>");
}
print("<tr><td></td><td><hr></td><td></td><td><hr></td></tr>");
print("<tr><td valign=top>Total");
print("</td><td valign=top align=right>");
print(file_usage_total);
print("</td><td></td><td valign=top align=right>");
print(sprintf("%.2f", file_usage_total * 1. / cause_total));
print("</td></tr>");
print("</table>");
print("</div>");

print("<hr>");
print("<div class=\"report-cmd\">");
print("A similar report may be obtained from the command line, with");
print("<blockquote><samp>aer proj_stats -p " ## pn ## "</samp></blockquote>");
print("</div>");

print("<hr>");
print("<p align=center class=\"navbar\">[");
print("<a href=\"" ## script_name ## "\">Project List</a> |");
href = script_name ## "?file@proj_menu+project@" ## quote_url(pn);
print("<a href=\"" ## href ## "\">Project Menu</a>");
print("]</p>");

print("<hr>");
print("This page was generated " ## now() ## ".");
print("</body></html>");
