package net.iponweb.disthene.reader.graph;
import net.iponweb.disthene.reader.beans.TimeSeries;
import net.iponweb.disthene.reader.beans.TimeSeriesOption;
import net.iponweb.disthene.reader.exceptions.LogarithmicScaleNotAllowed;
import net.iponweb.disthene.reader.handler.parameters.ImageParameters;
import net.iponweb.disthene.reader.handler.parameters.RenderParameters;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author Andrei Ivanov
*/
public class LineGraph extends Graph {
public LineGraph(RenderParameters renderParameters, List<TimeSeries> data) {
super(renderParameters, data);
}
@Override
public byte[] drawGraph() throws LogarithmicScaleNotAllowed {
if (data.size() == 0) {
return drawNoData();
}
for (DecoratedTimeSeries ts : data) {
startTime = Math.min(startTime, ts.getFrom());
endTime = Math.max(endTime, ts.getTo());
if (ts.hasOption(TimeSeriesOption.SECOND_Y_AXIS)) {
secondYAxis = true;
dataRight.add(ts);
if (imageParameters.getRightColor() != null) ts.setOption(TimeSeriesOption.COLOR, imageParameters.getRightColor());
//todo dash length constant
if (imageParameters.getRightDashed()) ts.setOption(TimeSeriesOption.DASHED, (float) 5);
if (imageParameters.getRightWidth() != null) ts.setOption(TimeSeriesOption.LINE_WIDTH, imageParameters.getRightWidth().floatValue());
} else {
dataLeft.add(ts);
if (imageParameters.getLeftColor() != null) ts.setOption(TimeSeriesOption.COLOR, imageParameters.getLeftColor());
//todo dash length constant
if (imageParameters.getLeftDashed()) ts.setOption(TimeSeriesOption.DASHED, (float) 5);
if (imageParameters.getLeftWidth() != null) ts.setOption(TimeSeriesOption.LINE_WIDTH, imageParameters.getLeftWidth().floatValue());
}
}
// Set stacked options where needed right away
if ((imageParameters.getAreaMode().equals(ImageParameters.AreaMode.STACKED) || imageParameters.getAreaMode().equals(ImageParameters.AreaMode.ALL)) && !secondYAxis) {
for (DecoratedTimeSeries ts : data) {
if (!ts.hasOption(TimeSeriesOption.DRAW_AS_INFINITE)) {
ts.addOption(TimeSeriesOption.STACKED);
}
}
} else if (imageParameters.getAreaMode().equals(ImageParameters.AreaMode.FIRST) && !secondYAxis) {
if (data.size() > 0) {
data.get(0).addOption(TimeSeriesOption.STACKED);
}
}
if (imageParameters.getAreaMode().equals(ImageParameters.AreaMode.STACKED)) {
int length = data.get(0).getValues().length;
double[] total = new double[length];
for (DecoratedTimeSeries ts : getStackedData(data)) {
for (int i = 0; i < length; i++) {
if (ts.getValues()[i] != null) {
double original = ts.getValues()[i];
ts.getValues()[i] += total[i];
total[i] += original;
}
}
}
}
if (imageParameters.isGraphOnly()) {
imageParameters.setHideLegend(true);
imageParameters.setHideGrid(true);
imageParameters.setHideAxes(true);
imageParameters.setHideYAxis(false);
imageParameters.setyAxisSide(ImageParameters.Side.LEFT);
imageParameters.setTitle("");
imageParameters.setVerticalTitle("");
imageParameters.setMargin(0);
xMin = 0;
xMax = imageParameters.getWidth();
yMin = 0;
yMax = imageParameters.getHeight();
}
if (secondYAxis) {
imageParameters.setyAxisSide(ImageParameters.Side.LEFT);
}
if (imageParameters.getLineMode().equals(ImageParameters.LineMode.SLOPE)) {
for (DecoratedTimeSeries ts : data) {
if (ts.getValues().length <= 1) {
imageParameters.setLineMode(ImageParameters.LineMode.STAIRCASE);
}
}
}
//assign colors
int i = 0;
for (DecoratedTimeSeries ts : data) {
if (!ts.hasOption(TimeSeriesOption.COLOR)) {
ts.setOption(TimeSeriesOption.COLOR, imageParameters.getColorList().get(i % imageParameters.getColorList().size()));
i++;
}
}
if (!imageParameters.getTitle().isEmpty()) {
drawTitle();
}
if (!imageParameters.getVerticalTitle().isEmpty()) {
drawVerticalTitle(false);
}
if (secondYAxis && !imageParameters.getVerticalTitleRight().isEmpty()) {
drawVerticalTitle(true);
}
//todo: config legend max items
if ((!imageParameters.isHideLegend() || (data.size() <= 10)) && !imageParameters.isHideLegendCompletely()) {
List<String> legends = new ArrayList<>();
List<Color> colors = new ArrayList<>();
List<Boolean> secondYAxes = new ArrayList<>();
for (DecoratedTimeSeries ts : data) {
legends.add(ts.getName());
colors.add((Color) ts.getOption(TimeSeriesOption.COLOR));
secondYAxes.add(ts.hasOption(TimeSeriesOption.SECOND_Y_AXIS));
}
drawLegend(legends, colors, secondYAxes, imageParameters.isUniqueLegend());
}
if (!imageParameters.isHideAxes()) {
FontMetrics fontMetrics = g2d.getFontMetrics(imageParameters.getFont());
yMax -= fontMetrics.getMaxAscent() * 2;
}
consolidateDataPoints();
int currentXMin = xMin;
int currentXMax = xMax;
if (secondYAxis) {
setupTwoYAxes();
} else {
setupYAxis();
}
while (currentXMin != xMin || currentXMax != xMax) {
consolidateDataPoints();
currentXMin = xMin;
currentXMax = xMax;
if (secondYAxis) {
setupTwoYAxes();
} else {
setupYAxis();
}
}
setupXAxis();
if (!imageParameters.isHideAxes()) {
drawLabels();
if (!imageParameters.isHideGrid()) {
drawGridLines();
}
}
drawData();
return getBytes();
}
private byte[] drawNoData() {
int x = imageParameters.getWidth() / 2;
int y = imageParameters.getHeight() / 2;
g2d.setPaint(ColorTable.RED);
Font font = new Font(imageParameters.getFont().getName(), imageParameters.getFont().getStyle(),
(int) Math.log(imageParameters.getHeight() * imageParameters.getWidth()));
drawText(x, y, "No Data", font, ColorTable.RED, HorizontalAlign.CENTER, VerticalAlign.TOP);
return getBytes();
}
}