/**
*
*/
package bixie.checker.reportprinter;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedSet;
import java.util.TreeSet;
import util.Log;
import bixie.checker.report.Report;
import bixie.checker.report.Report.FaultExplanation;
/**
* @author schaef
*
*/
public class BasicReportPrinter implements ReportPrinter {
/* Sorted report is a map from severity (Integer) to
* a map from file name to list of reports (list of integer).
* This data structure is used to ensure that the printed report
* is always deterministic and not dependent on the order in which
* reports come in.
*/
Map<Integer, Map<String, List<List<Integer>>>> sortedReport = new HashMap<Integer, Map<String, List<List<Integer>>>>();
int cirtical, errorhandling, unreachable;
/**
*
*/
public BasicReportPrinter() {
cirtical = 0;
errorhandling = 0;
unreachable = 0;
}
/* (non-Javadoc)
* @see bixie.checker.reportprinter.ReportPrinter#printReport(bixie.checker.report.Report)
*/
@Override
public void printReport(Report r) {
consumeReport(r);
String s = r.toString();
if (s!=null && !s.isEmpty()) Log.info(r.toString());
}
public Map<Integer, Map<String, List<List<Integer>>>> getSortedReports() {
return this.sortedReport;
}
public String printSummary() {
SortedSet<String> knownFiles = new TreeSet<String>();
// now sort the list of lists of lines to ensure that
// printing is always deterministic.
for (Map<String, List<List<Integer>>> perFile : sortedReport.values()) {
for (List<List<Integer>> lines : perFile.values()) {
sortListOfInts(lines);
knownFiles.addAll(perFile.keySet());
}
}
StringBuilder sb = new StringBuilder();
for (String fname : knownFiles) {
//TODO: don't hard code the keys.
sb.append("In File: " + fname+"\n");
cirtical+= printReportForFileBySeverity(sb, fname, 0, "** Critical **");
unreachable += printReportForFileBySeverity(sb, fname, 1, " - Unreachable -");
}
sb.append("Summary: fwd=");
sb.append(cirtical);
sb.append("\tbwd=");
sb.append(unreachable);
sb.append("\n");
return sb.toString();
}
private int printReportForFileBySeverity(StringBuilder sb, String fname, Integer severity, String severityText) {
int lineCount = 0;
if (sortedReport.containsKey(severity) && sortedReport.get(severity).containsKey(fname)) {
sb.append(severityText+"\n");
for (List<Integer> lines : sortedReport.get(severity).get(fname) ) {
lineCount++;
sb.append("\tLines: ");
String comma = "";
for (Integer i : lines) {
sb.append(comma);
sb.append(i);
comma = ", ";
}
sb.append("\n");
}
}
return lineCount;
}
protected void consumeReport(Report r) {
for (Entry<Integer, List<FaultExplanation>> entry : r.getReports().entrySet()) {
if (!sortedReport.containsKey(entry.getKey())) {
sortedReport.put(entry.getKey(), new HashMap<String, List<List<Integer>>>());
}
Map<String, List<List<Integer>>> sortedLinesPerFile = sortedReport.get(entry.getKey());
for (FaultExplanation fe : entry.getValue()) {
if (fe.locations.isEmpty()) {
continue;
}
//get the sorted list of line numbers for this report.
LinkedHashSet<Integer> lines = new LinkedHashSet<Integer>();
for (SourceLocation line : fe.locations) {
lines.add(line.StartLine);
}
LinkedList<Integer> sortedLines = new LinkedList<Integer>(lines);
Collections.sort(sortedLines);
//get the file name for this report.
String fname = fe.fileName;
if (!sortedLinesPerFile.containsKey(fname)) {
sortedLinesPerFile.put(fname, new LinkedList<List<Integer>>());
}
sortedLinesPerFile.get(fname).add(sortedLines);
}
}
}
/**
* Sort a list of sorted lists of integers. Given two lists l1 and l2,
* l1 is before l2, if the first integer that is different in l1 and l2
* is smaller in l1. If one element is a subset of the other, then the
* shorter list comes first.
* @param list
*/
private void sortListOfInts(List<List<Integer>> list) {
Collections.sort(list, new Comparator<List<Integer>>(){
@Override
public int compare(List<Integer> l1, List<Integer> l2) {
Iterator<Integer> i1 = l1.iterator();
Iterator<Integer> i2 = l2.iterator();
while (i1.hasNext() && i2.hasNext()) {
int v1 = i1.next();
int v2 = i2.next();
if (v1<v2) return -1;
if (v1>v2) return 1;
}
if (i1.hasNext()) {
return 1;
}
if (i2.hasNext()) {
return -1;
}
return 0;
}
});
}
@Override
public int countReports() {
return this.cirtical + this.errorhandling + this.unreachable;
}
}