package org.rrd4j.graph;
import java.io.IOException;
import org.rrd4j.core.Util;
import org.rrd4j.data.DataProcessor;
public abstract class DummyGraph {
protected ImageWorker imageWorker;
protected RrdGraphDef graphDef;
protected ImageParameters imageParameters;
protected Mapper graphMapper;
protected DataProcessor dataProcessor;
protected void buildGraph() throws IOException {
//For the test only; when creating the mock object above, if we include ".withConstructor(100,100)"
// easymock calls the constructor but the call to resize doesn't happen properly.
// But it's imperative to setup internal state in the ImageWorker. So, call it here.
imageWorker.resize(100,100);
//The imageParameters setup code is duplicated and simplified from that in similarly named functions
// in RrdGraph. It would be nice if this could be re-used somehow, but that would require
// being able to pass in an ImageWorker to RrdGraph. But currently the imageworker is created
// and used immediately in the constructor of RrdGraph.
// And we need some existing unit tests to be able to prove that it's doing the right thing first
// before we can refactor it so that we can write better unit tests. Mr Chicken, meet Mr Egg.
// So, this is about the best we can do at this stage.
// The called functions are named the same as in RrdGraph, but are generally simplified for the purposes of this test
// eliminating code that we don't use
imageParameters = new ImageParameters();
dataProcessor = fetchData(imageParameters, graphDef);
calculatePlotValues(graphDef, dataProcessor);
findMinMaxValues(imageParameters, graphDef);
identifySiUnit(imageParameters, graphDef);
expandValueRange(imageParameters, graphDef);
initializeLimits(imageParameters, graphDef);
imageWorker.resize(imageParameters.xgif, imageParameters.ygif);
graphMapper = new Mapper(graphDef, imageParameters);
}
protected double getSmallFontCharWidth() {
return imageWorker.getStringWidth("a", graphDef.getFont(RrdGraphDef.FONTTAG_LEGEND));
}
protected double getSmallFontHeight() {
return imageWorker.getFontHeight(graphDef.getFont(RrdGraphDef.FONTTAG_LEGEND));
}
protected double getLargeFontHeight() {
return imageWorker.getFontHeight(graphDef.getFont(RrdGraphDef.FONTTAG_TITLE));
}
protected void initializeLimits(ImageParameters imageParameters, RrdGraphDef gdef) {
imageParameters.xsize = gdef.width;
imageParameters.ysize = gdef.height;
imageParameters.unitslength = gdef.unitsLength;
if (gdef.onlyGraph) {
if (imageParameters.ysize > 64) {
throw new RuntimeException("Cannot create graph only, height too big");
}
imageParameters.xorigin = 0;
}
else {
imageParameters.xorigin = (int) (RrdGraphConstants.PADDING_LEFT + imageParameters.unitslength * getSmallFontCharWidth());
}
if (gdef.verticalLabel != null) {
imageParameters.xorigin += getSmallFontHeight();
}
if (gdef.onlyGraph) {
imageParameters.yorigin = imageParameters.ysize;
}
else {
imageParameters.yorigin = RrdGraphConstants.PADDING_TOP + imageParameters.ysize;
}
if (gdef.title != null) {
imageParameters.yorigin += getLargeFontHeight() + RrdGraphConstants.PADDING_TITLE;
}
if (gdef.onlyGraph) {
imageParameters.xgif = imageParameters.xsize;
imageParameters.ygif = imageParameters.yorigin;
}
else {
imageParameters.xgif = RrdGraphConstants.PADDING_RIGHT + imageParameters.xsize + imageParameters.xorigin;
imageParameters.ygif = imageParameters.yorigin + (int) (RrdGraphConstants.PADDING_PLOT * getSmallFontHeight());
}
}
protected void expandValueRange(ImageParameters imageParameters, RrdGraphDef gdef) {
imageParameters.ygridstep = (gdef.valueAxisSetting != null) ? gdef.valueAxisSetting.gridStep : Double.NaN;
imageParameters.ylabfact = (gdef.valueAxisSetting != null) ? gdef.valueAxisSetting.labelFactor : 0;
if (!gdef.rigid && !gdef.logarithmic) {
double sensiblevalues[] = {
1000.0, 900.0, 800.0, 750.0, 700.0, 600.0, 500.0, 400.0, 300.0, 250.0, 200.0, 125.0, 100.0,
90.0, 80.0, 75.0, 70.0, 60.0, 50.0, 40.0, 30.0, 25.0, 20.0, 10.0,
9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.5, 3.0, 2.5, 2.0, 1.8, 1.5, 1.2, 1.0,
0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0, -1
};
double scaled_min, scaled_max, adj;
if (Double.isNaN(imageParameters.ygridstep)) {
if (gdef.altYMrtg) { /* mrtg */
imageParameters.decimals = Math.ceil(Math.log10(Math.max(Math.abs(imageParameters.maxval), Math.abs(imageParameters.minval))));
imageParameters.quadrant = 0;
if (imageParameters.minval < 0) {
imageParameters.quadrant = 2;
if (imageParameters.maxval <= 0) {
imageParameters.quadrant = 4;
}
}
switch (imageParameters.quadrant) {
case 2:
imageParameters.scaledstep = Math.ceil(50 * Math.pow(10, -(imageParameters.decimals)) * Math.max(Math.abs(imageParameters.maxval),
Math.abs(imageParameters.minval))) * Math.pow(10, imageParameters.decimals - 2);
scaled_min = -2 * imageParameters.scaledstep;
scaled_max = 2 * imageParameters.scaledstep;
break;
case 4:
imageParameters.scaledstep = Math.ceil(25 * Math.pow(10,
-(imageParameters.decimals)) * Math.abs(imageParameters.minval)) * Math.pow(10, imageParameters.decimals - 2);
scaled_min = -4 * imageParameters.scaledstep;
scaled_max = 0;
break;
default: /* quadrant 0 */
imageParameters.scaledstep = Math.ceil(25 * Math.pow(10, -(imageParameters.decimals)) * imageParameters.maxval) *
Math.pow(10, imageParameters.decimals - 2);
scaled_min = 0;
scaled_max = 4 * imageParameters.scaledstep;
break;
}
imageParameters.minval = scaled_min;
imageParameters.maxval = scaled_max;
}
else if (gdef.altAutoscale) {
/* measure the amplitude of the function. Make sure that
graph boundaries are slightly higher then max/min vals
so we can see amplitude on the graph */
double delt, fact;
delt = imageParameters.maxval - imageParameters.minval;
adj = delt * 0.1;
fact = 2.0 * Math.pow(10.0,
Math.floor(Math.log10(Math.max(Math.abs(imageParameters.minval), Math.abs(imageParameters.maxval)))) - 2);
if (delt < fact) {
adj = (fact - delt) * 0.55;
}
imageParameters.minval -= adj;
imageParameters.maxval += adj;
}
else if (gdef.altAutoscaleMax) {
/* measure the amplitude of the function. Make sure that
graph boundaries are slightly higher than max vals
so we can see amplitude on the graph */
adj = (imageParameters.maxval - imageParameters.minval) * 0.1;
imageParameters.maxval += adj;
}
else {
scaled_min = imageParameters.minval / imageParameters.magfact;
scaled_max = imageParameters.maxval / imageParameters.magfact;
for (int i = 1; sensiblevalues[i] > 0; i++) {
if (sensiblevalues[i - 1] >= scaled_min && sensiblevalues[i] <= scaled_min) {
imageParameters.minval = sensiblevalues[i] * imageParameters.magfact;
}
if (-sensiblevalues[i - 1] <= scaled_min && -sensiblevalues[i] >= scaled_min) {
imageParameters.minval = -sensiblevalues[i - 1] * imageParameters.magfact;
}
if (sensiblevalues[i - 1] >= scaled_max && sensiblevalues[i] <= scaled_max) {
imageParameters.maxval = sensiblevalues[i - 1] * imageParameters.magfact;
}
if (-sensiblevalues[i - 1] <= scaled_max && -sensiblevalues[i] >= scaled_max) {
imageParameters.maxval = -sensiblevalues[i] * imageParameters.magfact;
}
}
}
}
else {
imageParameters.minval = (double) imageParameters.ylabfact * imageParameters.ygridstep *
Math.floor(imageParameters.minval / ((double) imageParameters.ylabfact * imageParameters.ygridstep));
imageParameters.maxval = (double) imageParameters.ylabfact * imageParameters.ygridstep *
Math.ceil(imageParameters.maxval / ((double) imageParameters.ylabfact * imageParameters.ygridstep));
}
}
}
protected void identifySiUnit(ImageParameters imageParameters, RrdGraphDef gdef) {
imageParameters.unitsexponent = gdef.unitsExponent;
imageParameters.base = gdef.base;
if (!gdef.logarithmic) {
final char symbol[] = {'a', 'f', 'p', 'n', 'u', 'm', ' ', 'k', 'M', 'G', 'T', 'P', 'E'};
int symbcenter = 6;
double digits;
if (imageParameters.unitsexponent != Integer.MAX_VALUE) {
digits = Math.floor(imageParameters.unitsexponent / 3.0);
}
else {
digits = Math.floor(Math.log(Math.max(Math.abs(imageParameters.minval), Math.abs(imageParameters.maxval))) / Math.log(imageParameters.base));
}
imageParameters.magfact = Math.pow(imageParameters.base, digits);
if (((digits + symbcenter) < symbol.length) && ((digits + symbcenter) >= 0)) {
imageParameters.symbol = symbol[(int) digits + symbcenter];
}
else {
imageParameters.symbol = '?';
}
}
}
protected void findMinMaxValues(ImageParameters imageParameters, RrdGraphDef gdef) {
double minval = Double.NaN, maxval = Double.NaN;
for (PlotElement pe : gdef.plotElements) {
if (pe instanceof SourcedPlotElement) {
minval = Util.min(((SourcedPlotElement) pe).getMinValue(), minval);
maxval = Util.max(((SourcedPlotElement) pe).getMaxValue(), maxval);
}
}
if (Double.isNaN(minval)) {
minval = 0D;
}
if (Double.isNaN(maxval)) {
maxval = 1D;
}
imageParameters.minval = gdef.minValue;
imageParameters.maxval = gdef.maxValue;
/* adjust min and max values */
if (Double.isNaN(imageParameters.minval) || ((!gdef.logarithmic && !gdef.rigid) && imageParameters.minval > minval)) {
imageParameters.minval = minval;
}
if (Double.isNaN(imageParameters.maxval) || (!gdef.rigid && imageParameters.maxval < maxval)) {
if (gdef.logarithmic) {
imageParameters.maxval = maxval * 1.1;
}
else {
imageParameters.maxval = maxval;
}
}
/* make sure min is smaller than max */
if (imageParameters.minval > imageParameters.maxval) {
imageParameters.minval = 0.99 * imageParameters.maxval;
}
/* make sure min and max are not equal */
if (Math.abs(imageParameters.minval - imageParameters.maxval) < .0000001) {
imageParameters.maxval *= 1.01;
if (!gdef.logarithmic) {
imageParameters.minval *= 0.99;
}
/* make sure min and max are not both zero */
if (imageParameters.maxval == 0.0) {
imageParameters.maxval = 1.0;
}
}
}
protected void calculatePlotValues(RrdGraphDef gdef, DataProcessor dproc) {
for (PlotElement pe : gdef.plotElements) {
if (pe instanceof SourcedPlotElement) {
((SourcedPlotElement) pe).assignValues(dproc);
}
}
}
protected DataProcessor fetchData(ImageParameters imageParameters, RrdGraphDef gdef) throws IOException {
DataProcessor dproc = new DataProcessor(gdef.startTime, gdef.endTime);
dproc.setPoolUsed(gdef.poolUsed);
if (gdef.step > 0) {
dproc.setStep(gdef.step);
}
for (Source src : gdef.sources) {
src.requestData(dproc);
}
dproc.processData();
imageParameters.start = gdef.startTime;
imageParameters.end = gdef.endTime;
return dproc;
}
}