package com.hwlcn.ldap.util;
import com.hwlcn.core.annotation.NotMutable;
import com.hwlcn.core.annotation.ThreadSafety;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date;
import static com.hwlcn.ldap.util.UtilityMessages.*;
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
public final class ColumnFormatter
implements Serializable
{
private static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS =
new DecimalFormatSymbols();
static
{
DECIMAL_FORMAT_SYMBOLS.setInfinity("inf");
DECIMAL_FORMAT_SYMBOLS.setNaN("NaN");
}
private static final OutputFormat DEFAULT_OUTPUT_FORMAT =
OutputFormat.COLUMNS;
private static final String DEFAULT_SPACER = " ";
private static final String DEFAULT_TIMESTAMP_FORMAT = "HH:mm:ss";
private static final long serialVersionUID = -2524398424293401200L;
private final boolean includeTimestamp;
private final FormattableColumn timestampColumn;
private final FormattableColumn[] columns;
private final OutputFormat outputFormat;
private final String spacer;
private final String timestampFormat;
private final transient ThreadLocal<DecimalFormat> decimalFormatter;
private final transient ThreadLocal<SimpleDateFormat> timestampFormatter;
public ColumnFormatter(final FormattableColumn... columns)
{
this(false, null, null, null, columns);
}
public ColumnFormatter(final boolean includeTimestamp,
final String timestampFormat,
final OutputFormat outputFormat, final String spacer,
final FormattableColumn... columns)
{
Validator.ensureNotNull(columns);
Validator.ensureTrue(columns.length > 0);
this.includeTimestamp = includeTimestamp;
this.columns = columns;
decimalFormatter = new ThreadLocal<DecimalFormat>();
timestampFormatter = new ThreadLocal<SimpleDateFormat>();
if (timestampFormat == null)
{
this.timestampFormat = DEFAULT_TIMESTAMP_FORMAT;
}
else
{
this.timestampFormat = timestampFormat;
}
if (outputFormat == null)
{
this.outputFormat = DEFAULT_OUTPUT_FORMAT;
}
else
{
this.outputFormat = outputFormat;
}
if (spacer == null)
{
this.spacer = DEFAULT_SPACER;
}
else
{
this.spacer = spacer;
}
if (includeTimestamp)
{
final SimpleDateFormat dateFormat =
new SimpleDateFormat(this.timestampFormat);
final String timestamp = dateFormat.format(new Date());
final String label = INFO_COLUMN_LABEL_TIMESTAMP.get();
final int width = Math.max(label.length(), timestamp.length());
timestampFormatter.set(dateFormat);
timestampColumn =
new FormattableColumn(width, HorizontalAlignment.LEFT, label);
}
else
{
timestampColumn = null;
}
}
public boolean includeTimestamps()
{
return includeTimestamp;
}
public String getTimestampFormatString()
{
return timestampFormat;
}
public OutputFormat getOutputFormat()
{
return outputFormat;
}
public String getSpacer()
{
return spacer;
}
public FormattableColumn[] getColumns()
{
final FormattableColumn[] copy = new FormattableColumn[columns.length];
System.arraycopy(columns, 0, copy, 0, columns.length);
return copy;
}
public String[] getHeaderLines(final boolean includeDashes)
{
if (outputFormat == OutputFormat.COLUMNS)
{
int maxColumns = 1;
final String[][] headerLines = new String[columns.length][];
for (int i=0; i < columns.length; i++)
{
headerLines[i] = columns[i].getLabelLines();
maxColumns = Math.max(maxColumns, headerLines[i].length);
}
final StringBuilder[] buffers = new StringBuilder[maxColumns];
for (int i=0; i < maxColumns; i++)
{
final StringBuilder buffer = new StringBuilder();
buffers[i] = buffer;
if (includeTimestamp)
{
if (i == (maxColumns - 1))
{
timestampColumn.format(buffer, timestampColumn.getSingleLabelLine(),
outputFormat);
}
else
{
timestampColumn.format(buffer, "", outputFormat);
}
}
for (int j=0; j < columns.length; j++)
{
if (includeTimestamp || (j > 0))
{
buffer.append(spacer);
}
final int rowNumber = i + headerLines[j].length - maxColumns;
if (rowNumber < 0)
{
columns[j].format(buffer, "", outputFormat);
}
else
{
columns[j].format(buffer, headerLines[j][rowNumber], outputFormat);
}
}
}
final String[] returnArray;
if (includeDashes)
{
returnArray = new String[maxColumns+1];
}
else
{
returnArray = new String[maxColumns];
}
for (int i=0; i < maxColumns; i++)
{
returnArray[i] = buffers[i].toString();
}
if (includeDashes)
{
final StringBuilder buffer = new StringBuilder();
if (timestampColumn != null)
{
for (int i=0; i < timestampColumn.getWidth(); i++)
{
buffer.append('-');
}
}
for (int i=0; i < columns.length; i++)
{
if (includeTimestamp || (i > 0))
{
buffer.append(spacer);
}
for (int j=0; j < columns[i].getWidth(); j++)
{
buffer.append('-');
}
}
returnArray[returnArray.length - 1] = buffer.toString();
}
return returnArray;
}
else
{
final StringBuilder buffer = new StringBuilder();
if (timestampColumn != null)
{
timestampColumn.format(buffer, timestampColumn.getSingleLabelLine(),
outputFormat);
}
for (int i=0; i < columns.length; i++)
{
if (includeTimestamp || (i > 0))
{
if (outputFormat == OutputFormat.TAB_DELIMITED_TEXT)
{
buffer.append('\t');
}
else if (outputFormat == OutputFormat.CSV)
{
buffer.append(',');
}
}
final FormattableColumn c = columns[i];
c.format(buffer, c.getSingleLabelLine(), outputFormat);
}
return new String[] { buffer.toString() };
}
}
public String formatRow(final Object... columnData)
{
final StringBuilder buffer = new StringBuilder();
if (includeTimestamp)
{
SimpleDateFormat dateFormat = timestampFormatter.get();
if (dateFormat == null)
{
dateFormat = new SimpleDateFormat(timestampFormat);
timestampFormatter.set(dateFormat);
}
timestampColumn.format(buffer, dateFormat.format(new Date()),
outputFormat);
}
for (int i=0; i < columns.length; i++)
{
if (includeTimestamp || (i > 0))
{
switch (outputFormat)
{
case TAB_DELIMITED_TEXT:
buffer.append('\t');
break;
case CSV:
buffer.append(',');
break;
case COLUMNS:
buffer.append(spacer);
break;
}
}
if (i >= columnData.length)
{
columns[i].format(buffer, "", outputFormat);
}
else
{
columns[i].format(buffer, toString(columnData[i]), outputFormat);
}
}
return buffer.toString();
}
private String toString(final Object o)
{
if (o == null)
{
return "";
}
if ((o instanceof Float) || (o instanceof Double))
{
DecimalFormat f = decimalFormatter.get();
if (f == null)
{
f = new DecimalFormat("0.000", DECIMAL_FORMAT_SYMBOLS);
decimalFormatter.set(f);
}
final double d;
if (o instanceof Float)
{
d = ((Float) o).doubleValue();
}
else
{
d = ((Double) o);
}
return f.format(d);
}
return String.valueOf(o);
}
}