package org.jenkinsci.plugins.codedx;
import hudson.model.Run;
import hudson.util.ChartUtil.NumberOnlyBuildLabel;
import hudson.util.DataSetBuilder;
import hudson.util.ShiftedCategoryAxis;
import java.awt.Color;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import org.jenkinsci.plugins.codedx.model.CodeDxGroupStatistics;
import org.jenkinsci.plugins.codedx.model.StatisticGroup;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItem;
import org.jfree.chart.LegendItemCollection;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.CategoryDataset;
import org.jfree.ui.RectangleInsets;
/**
*
* @author ademartini This file is heavily derived from the sloccount-plugin (author: lordofthepigs)
*/
public class CodeDxChartBuilder implements Serializable {
/** Serial version UID. */
private static final long serialVersionUID = 0L;
private static Set<StatisticGroup> hiddenGroups = new HashSet<StatisticGroup>() {{
add(StatisticGroup.Gone);
}};
private CodeDxChartBuilder(){
}
public static JFreeChart buildChart(CodeDxBuildAction action,
int numBuildsInGraph, String statisticsName, Map<String,Color> colors){
CategoryDataset dataset = buildDataset(action, numBuildsInGraph, statisticsName);
JFreeChart chart = ChartFactory.createStackedAreaChart(null, null,
"Findings", dataset,
PlotOrientation.VERTICAL, true, false, true);
chart.setBackgroundPaint(Color.white);
CategoryPlot plot = chart.getCategoryPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.setOutlinePaint(null);
plot.setForegroundAlpha(0.8f);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.black);
CategoryAxis domainAxis = new ShiftedCategoryAxis(null);
plot.setDomainAxis(domainAxis);
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
domainAxis.setLowerMargin(0.0);
domainAxis.setUpperMargin(0.0);
domainAxis.setCategoryMargin(0.0);
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// crop extra space around the graph
plot.setInsets(new RectangleInsets(0, 0, 0, 5.0));
List rows = dataset.getRowKeys();
List<Color> colorList = new ArrayList<Color>();
if(colors != null){
for(Object row : rows){
if(colors.containsKey(row.toString())){
colorList.add(colors.get(row.toString()));
}
}
}
if(colorList.size() == rows.size()){
plot.setRenderer(new CodeDxAreaRenderer(colorList));
}
else{
plot.setRenderer(new CodeDxAreaRenderer(null));
}
ArrayList<LegendItem> legendItems = new ArrayList<LegendItem>();
Iterator<LegendItem> itr = plot.getLegendItems().iterator();
while (itr.hasNext()) {
legendItems.add(itr.next());
}
//Reverse the order
Collections.sort(legendItems, new Comparator<LegendItem>() {
public int compare(LegendItem lhs, LegendItem rhs) {
return rhs.getSeriesKey().compareTo(lhs.getSeriesKey());
}
});
LegendItemCollection newItems = new LegendItemCollection();
for (LegendItem item : legendItems) {
newItems.add(item);
}
plot.setFixedLegendItems(newItems);
return chart;
}
private static CategoryDataset buildDataset(CodeDxBuildAction lastAction,
int numBuildsInGraph, String statisticsName){
DataSetBuilder<StatisticGroup, NumberOnlyBuildLabel> builder = new DataSetBuilder<StatisticGroup, NumberOnlyBuildLabel>();
Set<StatisticGroup> allGroups = new HashSet<StatisticGroup>();
CodeDxBuildAction action = lastAction;
int numBuilds = 0;
// numBuildsInGraph <= 1 means unlimited
while(action != null && (numBuildsInGraph <= 1 || numBuilds < numBuildsInGraph)){
CodeDxResult result = action.getResult();
if(result != null){
NumberOnlyBuildLabel buildLabel = new NumberOnlyBuildLabel((Run<?, ?>)action.getBuild());
for (String group : result.getStatistics(statisticsName).getAllGroups()) {
StatisticGroup statisticGroup = StatisticGroup.forValue(group);
if (! hiddenGroups.contains(statisticGroup)) {
allGroups.add(StatisticGroup.forValue(group));
}
}
Set<StatisticGroup> remainingGroups = StatisticGroup.valuesForStatistic(statisticsName);
for(CodeDxGroupStatistics groupStats : result.getStatistics(statisticsName).getStatistics()){
StatisticGroup statisticGroup = StatisticGroup.forValue(groupStats.getGroup());
if (! hiddenGroups.contains(statisticGroup))
builder.add(groupStats.getFindings(), statisticGroup, buildLabel);
remainingGroups.remove(StatisticGroup.forValue(groupStats.getGroup()));
}
for(StatisticGroup group : remainingGroups) {
builder.add(0, group, buildLabel);
}
++numBuilds;
}
action = action.getPreviousAction();
}
return builder.build();
}
}