package org.projectusus.core.statistics;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.projectusus.core.CollectibleExtension;
import org.projectusus.core.basis.CodeProportion;
import org.projectusus.core.basis.CodeStatistic;
import org.projectusus.core.basis.FileHotspot;
import org.projectusus.core.basis.Histogram;
import org.projectusus.core.basis.Hotspot;
import org.projectusus.core.basis.LocationType;
import org.projectusus.core.basis.MetricsResults;
import org.projectusus.core.basis.SinglePackageHotspot;
import org.projectusus.core.basis.SourceCodeLocation;
import org.projectusus.core.filerelations.model.ClassDescriptor;
import org.projectusus.core.filerelations.model.Packagename;
/**
* Implementors of extensions for the <code>org.projectusus.core.statistics</code> extension point must use this implementation as a basis for their own implementations. It
* provides a default mechanism to create a CodeProportion object. Implementors need to invoke the {@link CockpitExtension#addResult(SourceCodeLocation, int)} method in order for
* this mechanism to work. Examples can be found in the <code>org.projectusus.defaultmetrics</code> project.
* <p>
* The default implementation visits the whole raw data tree. Technically, it would be possible to restrict the analysis to a subtree, but it does not really make sense to do so
* because the <code>JavaModelPath</code> object pointing to the subtree needs to be statically integrated into the visitor and thus cannot be adapted to the code currently being
* analyzed.
*
*/
public abstract class CockpitExtension extends DefaultMetricsResultVisitor implements CollectibleExtension {
public final static String EXTENSION_POINT_ID = "org.projectusus.core.statistics"; //$NON-NLS-1$
private final String unit;
private final int violationLimit;
private int basis;
private int violations;
private int violationSum;
private List<Hotspot> hotspots;
private Histogram histogram;
private IProject currentProject;
private IFile currentFile;
public CockpitExtension( String unit, int violationLimit ) {
super();
this.unit = unit;
this.violationLimit = violationLimit;
reset();
}
private void reset() {
basis = 0;
violations = 0;
violationSum = 0;
hotspots = new ArrayList<Hotspot>();
histogram = new Histogram();
}
protected void addResult( SourceCodeLocation location, int count ) {
incrementState( count, new FileHotspot( location, count, currentFile ) );
}
protected void addResult( Packagename pkg, int count, Set<ClassDescriptor> set ) {
incrementState( count, new SinglePackageHotspot( pkg, count, currentProject.getName(), set ) );
}
private void incrementState( int count, Hotspot hotspot ) {
basis++;
histogram.increment( count );
violationSum += count;
if( count > violationLimit ) {
violations++;
hotspots.add( hotspot );
}
}
@Override
public void inspectProject( IProject project, @SuppressWarnings( "unused" ) MetricsResults results ) {
currentProject = project;
}
@Override
public void inspectFile( IFile file, @SuppressWarnings( "unused" ) MetricsResults result ) {
currentFile = file;
}
public int getMetricsSum() {
return violationSum;
}
public int getViolations() {
return violations;
}
public int getBasis() {
return basis;
}
public CodeStatistic getBasisStatistic() {
return new CodeStatistic( unit, getBasis() );
}
public double getAverage() {
return calculateAverage( getViolations(), getBasis() );
}
public List<Hotspot> getHotspots() {
return hotspots;
}
public CodeProportion getCodeProportion() {
return new CodeProportion( getLabel(), getDescription(), getTooltip(), getViolations(), getBasisStatistic(), getAverage(), getHotspots(), getHistogram(), getLocationType() );
}
protected LocationType getLocationType() {
return LocationType.PATH;
}
protected String getDescription() {
return "Hotspots are " + unit + " " + hotspotsAreUnits() + getRatingFunction(); //$NON-NLS-1$
}
protected abstract String hotspotsAreUnits();
protected String getTooltip() {
return getDescription();
}
public static double calculateAverage( double numberOfViolations, double numberOfBaseElems ) {
if( numberOfBaseElems == 0 ) {
return 0.0;
}
return 100 * numberOfViolations / numberOfBaseElems;
}
protected Histogram getHistogram() {
return histogram;
}
protected String format( String string, int value ) {
return String.format( string, Integer.valueOf( value ) );
}
protected String format( String string, int value1, int value2 ) {
return String.format( string, Integer.valueOf( value1 ), Integer.valueOf( value2 ) );
}
protected String getRatingFunction() {
return linearRatingFunction( violationLimit );
}
private String linearRatingFunction( int limit ) {
return format( "\nRating function: f(value) = 1/%d value - 1", limit );
}
}