package org.rrd4j.graph;
import java.util.ArrayList;
import java.util.List;
class LegendComposer implements RrdGraphConstants {
private final RrdGraphDef gdef;
private final ImageWorker worker;
private int legX, legY;
private final int legWidth;
private double interLegendSpace;
private double leading;
private double smallLeading;
private double boxSpace;
LegendComposer(RrdGraph rrdGraph, int legX, int legY, int legWidth) {
this.gdef = rrdGraph.gdef;
this.worker = rrdGraph.worker;
this.legX = legX;
this.legY = legY;
this.legWidth = legWidth;
interLegendSpace = rrdGraph.getInterlegendSpace();
leading = rrdGraph.getLeading();
smallLeading = rrdGraph.getSmallLeading();
boxSpace = rrdGraph.getBoxSpace();
}
int placeComments() {
Line line = new Line();
for (CommentText comment : gdef.comments) {
if (comment.isValidGraphElement()) {
if (!line.canAccommodate(comment)) {
line.layoutAndAdvance(false);
line.clear();
}
line.add(comment);
}
}
line.layoutAndAdvance(true);
return legY;
}
class Line {
private String lastMarker;
private double width;
private int spaceCount;
private boolean noJustification;
private List<CommentText> comments = new ArrayList<CommentText>();
Line() {
clear();
}
void clear() {
lastMarker = "";
width = 0;
spaceCount = 0;
noJustification = false;
comments.clear();
}
boolean canAccommodate(CommentText comment) {
// always accommodate if empty
if (comments.size() == 0) {
return true;
}
// cannot accommodate if the last marker was \j, \l, \r, \c, \s
if (lastMarker.equals(ALIGN_LEFT_MARKER) || lastMarker.equals(ALIGN_LEFTNONL_MARKER) || lastMarker.equals(ALIGN_CENTER_MARKER) ||
lastMarker.equals(ALIGN_RIGHT_MARKER) || lastMarker.equals(ALIGN_JUSTIFIED_MARKER) ||
lastMarker.equals(VERTICAL_SPACING_MARKER)) {
return false;
}
// cannot accommodate if line would be too long
double commentWidth = getCommentWidth(comment);
if (!lastMarker.equals(GLUE_MARKER)) {
commentWidth += interLegendSpace;
}
return width + commentWidth <= legWidth;
}
void add(CommentText comment) {
double commentWidth = getCommentWidth(comment);
if (comments.size() > 0 && !lastMarker.equals(GLUE_MARKER)) {
commentWidth += interLegendSpace;
spaceCount++;
}
width += commentWidth;
lastMarker = comment.marker;
noJustification |= lastMarker.equals(NO_JUSTIFICATION_MARKER) || lastMarker.isEmpty();
comments.add(comment);
}
void layoutAndAdvance(boolean isLastLine) {
if (comments.size() > 0) {
if (lastMarker.equals(ALIGN_LEFT_MARKER) || lastMarker.equals(ALIGN_LEFTNONL_MARKER)) {
placeComments(legX, interLegendSpace);
}
else if (lastMarker.equals(ALIGN_RIGHT_MARKER)) {
placeComments(legX + legWidth - width, interLegendSpace);
}
else if (lastMarker.equals(ALIGN_CENTER_MARKER)) {
placeComments(legX + (legWidth - width) / 2.0, interLegendSpace);
}
else if (lastMarker.equals(ALIGN_JUSTIFIED_MARKER)) {
// anything to justify?
if (spaceCount > 0) {
placeComments(legX, (legWidth - width) / spaceCount + interLegendSpace);
}
else {
placeComments(legX, interLegendSpace);
}
}
else if (lastMarker.equals(VERTICAL_SPACING_MARKER)) {
placeComments(legX, interLegendSpace);
}
else {
// nothing specified, align with respect to '\J'
if (noJustification || isLastLine) {
placeComments(legX, (legWidth - width) / spaceCount + interLegendSpace);
}
else {
placeComments(legX, interLegendSpace);
}
}
if (!lastMarker.equals(ALIGN_LEFTNONL_MARKER)) {
if (lastMarker.equals(VERTICAL_SPACING_MARKER)) {
legY += smallLeading;
}
else {
legY += leading;
}
}
}
}
private double getCommentWidth(CommentText comment) {
double commentWidth = worker.getStringWidth(comment.resolvedText, gdef.getFont(FONTTAG_LEGEND));
if (comment instanceof LegendText) {
commentWidth += boxSpace;
}
return commentWidth;
}
private void placeComments(double xStart, double space) {
double x = xStart;
for (CommentText comment : comments) {
comment.x = (int) x;
comment.y = legY;
x += getCommentWidth(comment);
if (!comment.marker.equals(GLUE_MARKER)) {
x += space;
}
}
}
}
}