/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.shell.help.def;
import java.io.PrintWriter;
/**
* This base class for the text-mode help implementation classes provides some simple
* helper classes and methods for laying out text.
*
* @author crawley@jnode.org
*/
public abstract class TextHelpBase {
public static final String RESOURCE_NAME = "messages.properties";
// FIXME ...
static final int NOMINAL_WIDTH = 75;
/* start with 80 spaces ... */
private static String spaces =
" ";
protected void format(PrintWriter out, TextCell[] cells, String[] texts) {
if (cells.length != texts.length) {
throw new IllegalArgumentException("Number of cells and texts must match");
}
// The text remaining to be formatted for each column.
String[] remains = new String[texts.length];
// The total count of characters remaining
int remainsCount = 0;
// Initialize 'remains' and 'remainsCount' for the first iteration
for (int i = 0; i < texts.length; i++) {
remains[i] = (texts[i] == null) ? "" : texts[i].trim();
remainsCount += remains[i].length();
}
StringBuilder result = new StringBuilder();
// Repeat while there is still text to output.
while (remainsCount > 0) {
// Each iteration uses 'fit' to get up to 'cell.width' characters from each column
// and then uses 'stamp' to append to them to the buffer with the leading margin
// and trailing padding as required.
remainsCount = 0;
for (int i = 0; i < cells.length; i++) {
String field = cells[i].fit(remains[i]);
remains[i] = remains[i].substring(field.length());
remainsCount += remains[i].length();
result.append(cells[i].stamp(field.trim()));
}
result.append('\n');
}
out.print(result.toString());
}
/**
* Get a String consisting of 'count' spaces.
*
* @param count the number of spaces
* @return the string
*/
protected static String getSpaces(int count) {
// The following assumes that 1) StringBuilder.append is efficient if you
// preallocate the StringBuilder, 2) StringBuilder.toString() does no character
// copying, and 3) String.substring(...) also does no character copying.
int len = spaces.length();
if (count > len) {
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < count; i++) {
sb.append(' ');
}
spaces = sb.toString();
return spaces;
} else if (count == len) {
return spaces;
} else {
return spaces.substring(0, count);
}
}
/**
* A Cell is a template for formatting text for help messages. (It is 'protected' so that
* the unit test can declare a subclass ...)
*/
protected static class TextCell {
final String field;
final int margin;
final int width;
/**
* Construct a Cell with a leading margin and a text width.
*
* @param margin the number of leading spaces for the Cell
* @param width the width of the text part of the Cell
*/
protected TextCell(int margin, int width) {
this.margin = margin;
this.width = width;
// for performance, we pre-build the field mask
this.field = getSpaces(margin + width);
}
/**
* Heuristically, split of a head substring of 'text' to fit within this Cell's width. We try
* to split at a space character, but if this will make the text too ragged, we simply chop.
*/
protected String fit(String text) {
if (width >= text.length()) {
return text;
}
String hardFit = text.substring(0, width);
if (hardFit.endsWith(" ")) {
return hardFit;
}
int lastSpace = hardFit.lastIndexOf(' ');
if (lastSpace > 3 * width / 4) {
return hardFit.substring(0, lastSpace);
} else {
return hardFit;
}
}
/**
* Stamp out a line with leading and trailing spaces to fill the Cell.
*/
protected String stamp(String text) {
if (text.length() > field.length())
throw new IllegalArgumentException("Text length exceeds field width");
return field.substring(0, margin) + text + field.substring(0, width - text.length());
}
}
}