+package net.jaekl.cfb.analyze;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import net.jaekl.cfb.CfbBundle;
+import net.jaekl.cfb.store.Location;
+import net.jaekl.cfb.xml.BugInstance;
+import net.jaekl.cfb.xml.messages.BugPattern;
+import net.jaekl.cfb.xml.messages.MessageCollection;
+
+public class HtmlReport {
+ CfbBundle m_bundle;
+ MessageCollection m_msgColl;
+
+ public HtmlReport(CfbBundle bundle, MessageCollection msgColl)
+ {
+ m_bundle = bundle;
+ m_msgColl = msgColl;
+ }
+
+ public void write(File output, Delta delta) throws IOException
+ {
+ try ( FileOutputStream fos = new FileOutputStream(output);
+ PrintWriter pw = new PrintWriter(fos); )
+ {
+ write(pw, delta);
+ }
+ }
+
+ void write(PrintWriter pw, Delta delta)
+ {
+ startPage(pw, delta);
+ }
+
+ void startPage(PrintWriter pw, Delta delta)
+ {
+ writeHeader(pw, delta);
+ pw.println(" <BODY>");
+ writeBody(pw, delta);
+ pw.println(" </BODY>");
+ pw.println("</HTML>");
+ }
+
+ String trans(String key, Object... arguments) {
+ return m_bundle.get(key, arguments);
+ }
+
+ void writeBody(PrintWriter pw, Delta delta)
+ {
+ writeSummary(pw, delta);
+ writeBugs(pw, CfbBundle.NEW_BUGS, delta.getNew());
+ writeBugs(pw, CfbBundle.FIXED_BUGS, delta.getFixed());
+ writeBugs(pw, CfbBundle.OLD_BUGS, delta.getCommon());
+ }
+
+ void writeBugLocations(PrintWriter pw, BugInstance bug)
+ {
+ for (Location loc : bug.getLocations()) {
+ StringBuffer sb = new StringBuffer();
+
+ if (null != loc) {
+ if (null != loc.getClassName()) {
+ sb.append(loc.getClassName());
+ }
+ if ((null != loc.getMethodName()) && (loc.getMethodName().length() > 0)) {
+ sb.append(".").append(loc.getMethodName()).append("()");
+ }
+ int start = loc.getStart();
+ int end = loc.getEnd();
+ if (start > 0) {
+ sb.append(":").append("" + start);
+ if ((end > 0) && (end > start)) {
+ sb.append("-").append("" + end);
+ }
+ }
+
+ if (null != loc.getMethodRole()) {
+ sb.append(" (" + loc.getMethodRole() + ")");
+ }
+ }
+
+ pw.write(" <TR>");
+ pw.write(" <TD COLSPAN=\"2\" CLASS=\"Loc\">" + sb.toString() + "</TD>");
+ pw.write(" </TR>");
+ }
+ }
+
+ void writeBugs(PrintWriter pw, String key, BugInstance[] bugs)
+ {
+ if (null == bugs || bugs.length < 1) {
+ return;
+ }
+
+ writeSectionHeading(pw, trans(key));
+
+ for (BugInstance bug : bugs) {
+ BugPattern pattern = m_msgColl.getPattern(bug.getType());
+
+ pw.write(" <P>");
+ pw.write(" <TABLE CLASS=\"bug\">");
+ pw.write(" <TR>");
+ pw.write(" <TD WIDTH=\"20%\">" + bug.getCategory() + "</TD>");
+ pw.write(" <TD>" + bug.getType() + "</TD>");
+ pw.write(" </TR>");
+ writeBugLocations(pw, bug);
+ pw.write(" <TR>");
+ pw.write(" <TD COLSPAN=\"2\">" + pattern.getShort() + "</TD>");
+ pw.write(" </TR>");
+ pw.write(" <TR>");
+ pw.write(" <TD COLSPAN=\"2\">" + pattern.getDetails() + "</TD>");
+ pw.write(" </TR>");
+ pw.write(" </TABLE>");
+ pw.write(" </P>");
+ }
+ }
+
+ void writeHeader(PrintWriter pw, Delta delta)
+ {
+ String title = trans(CfbBundle.CFB_REPORT);
+
+ pw.println("<HTML>");
+ pw.println(" <HEAD>");
+ pw.println(" <META CHARSET=\"UTF-8\"/>");
+ pw.println(" <TITLE>" + title + "</TITLE>");
+ writeStyle(pw);
+ pw.println(" </HEAD>");
+ }
+
+ void writeSectionHeading(PrintWriter pw, String heading)
+ {
+ pw.println(" <P CLASS=\"SectionHead\">");
+ pw.println(" <TABLE WIDTH=\"100%\"><TR><TD>" + heading + "</TD></TR></TABLE>");
+ pw.println(" </P>");
+ }
+
+ void writeSummary(PrintWriter pw, Delta delta)
+ {
+ final String SEP = ": ";
+
+ writeSectionHeading(pw, trans(CfbBundle.CFB_REPORT));
+ pw.println(" <P>");
+ pw.println(" <TABLE>");
+ pw.println(" <TR>");
+ pw.println(" <TD CLASS=\"CategoryName\">" + trans(CfbBundle.NEW_VERSION) + SEP + "</TD>");
+ pw.println(" <TD CLASS=\"CategoryValue\">" + delta.getLater().constructVersionText(m_bundle) + "</TD>");
+ pw.println(" </TR>");
+ pw.println(" <TR>");
+ pw.println(" <TD CLASS=\"CategoryName\">" + trans(CfbBundle.OLD_VERSION) + SEP + "</TD>");
+ pw.println(" <TD CLASS=\"CategoryValue\">" + delta.getEarlier().constructVersionText(m_bundle) + "</TD>");
+ pw.println(" </TR>");
+ pw.println(" <TR><TD> </TD></TR>");
+ pw.println(" <TR>");
+ pw.println(" <TD CLASS=\"CategoryName\">" + trans(CfbBundle.NEW_BUGS) + SEP + "</TD>");
+ pw.println(" <TD CLASS=\"CategoryValue\">" + trans(CfbBundle.NUM_BUGS, delta.getNumNew()) + "</TD>");
+ pw.println(" </TR>");
+ pw.println(" <TR>");
+ pw.println(" <TD CLASS=\"CategoryName\">" + trans(CfbBundle.FIXED_BUGS) + SEP + "</TD>");
+ pw.println(" <TD CLASS=\"CategoryValue\">" + trans(CfbBundle.NUM_BUGS, delta.getNumFixed()) + "</TD>");
+ pw.println(" </TR>");
+ pw.println(" <TR>");
+ pw.println(" <TD CLASS=\"CategoryName\">" + trans(CfbBundle.OLD_BUGS) + SEP + "</TD>");
+ pw.println(" <TD CLASS=\"CategoryValue\">" + trans(CfbBundle.NUM_BUGS_OLD, delta.getNumCommon()) + "</TD>");
+ pw.println(" </TR>");
+ pw.println(" </TABLE>");
+ pw.println(" </P>");
+ }
+
+ void writeStyle(PrintWriter pw)
+ {
+ pw.println(" <STYLE>");
+ pw.println(" body { background-color: #F0F0FF; }");
+ pw.println(" .CategoryName { text-align: right; }");
+ pw.println(" .CategoryValue { text-align: left; }");
+ pw.println(" .Loc { font-family: monospace; }");
+ pw.println(" .SectionHead td { background-color: #0000FF; color: #FFFFFF; font-size: 1.25em; font-weight: bold; }");
+ pw.println(" </STYLE>");
+ }
+}