/*
* #%L
* data-exporter
* %%
* Copyright (C) 2012 - 2013 http://www.brsanthu.com
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.brsanthu.dataexporter.output.texttable;
import java.io.OutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import com.brsanthu.dataexporter.AbstractDataWriter;
import com.brsanthu.dataexporter.TextAligner;
import com.brsanthu.dataexporter.model.AlignType;
import com.brsanthu.dataexporter.model.CellDetails;
import com.brsanthu.dataexporter.model.Column;
import com.brsanthu.dataexporter.model.DataExporterCallback;
import com.brsanthu.dataexporter.model.RowDetails;
import com.brsanthu.dataexporter.model.Table;
import static com.brsanthu.dataexporter.util.Util.*;
public class TextTableWriter extends AbstractDataWriter {
private List<Column> columns;
public TextTableWriter(TextTableExportOptions options) {
this(options, System.out);
}
public TextTableWriter(OutputStream out) {
this(new TextTableExportOptions(), out);
}
public TextTableWriter(Writer out) {
this(new TextTableExportOptions(), out);
}
public TextTableWriter(TextTableExportOptions options, OutputStream out) {
super(options, out);
}
public TextTableWriter(TextTableExportOptions options, Writer out) {
super(options, out);
}
public TextTableExportOptions getTextTableExportOptions() {
return (TextTableExportOptions) getOptions();
}
@Override
public void writeHeader(Table table) {
columns = table.getColumns();
TextTableExportOptions options = getTextTableExportOptions();
if (options.isPrintHeaders()) {
//Render the top border
printTopBorder();
//Format header into multiple lines and render with dividers and separators.
printHeaderCells(formatHeaderCells());
}
//Render the top border
printTopDownBorder();
}
@Override
public void writeRow(RowDetails rowDetails) {
//If repeat header after rows is specified, and if that condition
//is come, print the headers.
if (getTextTableExportOptions().getRepeatHeadersAfterRows() > 0) {
if (rowDetails.getRowIndex() != 0 && rowDetails.getRowIndex() % getTextTableExportOptions().getRepeatHeadersAfterRows() == 0) {
printBottomBorder();
println();
writeHeader(rowDetails.getTable());
}
}
//Generate all row data as required.
generateRowData(rowDetails);
DataExporterCallback callback = rowDetails.getTable().getCallback();
if (callback != null) {
callback.beforeRow(rowDetails);
}
//Format the row into cells
List<List<String>> rowCells = formatRowCells(rowDetails);
//Render left row divider
printLine(getStyle().getCenterLeftDivider(), getStyle().getCenterLeftRightDivider(),
getStyle().getCenterCenterDivider(), getStyle().getCenterRightLeftDivider(),
getStyle().getCenterRightDivider(), rowCells);
if (callback != null) {
callback.afterRow(rowDetails);
}
}
@Override
public void afterTable(Table table) {
//Render the final border
printBottomBorder();
}
public List<List<String>> formatRowCells(RowDetails rowDetails) {
DataExporterCallback callback = rowDetails.getTable().getCallback();
int maxRowHeight = Math.max(getTextTableExportOptions().getMinRowHeight(), getMaxRowHeight(rowDetails));
List<List<String>> rowLines = new ArrayList<List<String>>();
for (int j = 0; j < maxRowHeight; j++) {
rowLines.add(new ArrayList<String>());
}
for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) {
Column column = columns.get(columnIndex);
CellDetails cellDetails = new CellDetails(rowDetails, columnIndex);
cellDetails.setRowHeight(maxRowHeight);
cellDetails.setCellValue(rowDetails.getRow().getCellValue(cellDetails));
cellDetails.setCellAlign(cellDetails.getColumn().getAlign());
if (callback != null) {
callback.beforeCell(cellDetails);
}
List<String> cells = column.align(cellDetails, column.format(cellDetails));
for (int j = 0; j < maxRowHeight; j++) {
rowLines.get(j).add(cells.get(j));
}
if (callback != null) {
callback.afterCell(cellDetails);
}
}
return rowLines;
}
public int getMaxRowHeight(RowDetails rowDetails) {
int height = 1;
TextAligner textAligner = new TextAligner();
for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) {
CellDetails cellDetails = new CellDetails(rowDetails, columnIndex);
Column column = columns.get(columnIndex);
Object cellValue = null;
if (column.isGeneratesOwnData()) {
cellValue = column.getCellValueGenerator().generateCellValue(cellDetails);
} else {
cellValue = rowDetails.getRow().getCellValue(cellDetails);
}
cellDetails.setCellValue(cellValue);
//height = Math.max(height, column.getMaxRowHeight(cellDetails));
height = Math.max(height, textAligner.getRowHeight(cellDetails.getColumn().getWidth(), String.valueOf(cellDetails.getCellValue()), cellDetails.getCellAlign()));
}
return height;
}
protected void printTopBorder() {
printLine(getStyle().getTopLeftIntersection(), getStyle().getTopRightIntersection(),
getStyle().getTopCenterIntersection(), getStyle().getTopRightLeftIntersection(),
getStyle().getTopRightIntersection(), getStyle().getTopBorder());
}
public void printTopDownBorder() {
printLine(getStyle().getTopDownLeftIntersection(), getStyle().getTopDownRightIntersection(),
getStyle().getTopDownCenterIntersection(), getStyle().getTopDownRightLeftIntersection(),
getStyle().getTopDownRightIntersection(), getStyle().getTopDownBorder());
}
public void printBottomBorder() {
printLine(getStyle().getBottomLeftIntersection(), getStyle().getBottomRightIntersection(),
getStyle().getBottomCenterIntersection(), getStyle().getBottomRightLeftIntersection(),
getStyle().getBottomRightIntersection(), getStyle().getBottomBorder());
}
public void printHeaderCells(List<List<String>> headerLines) {
printLine(getStyle().getTopLeftDivider(), getStyle().getTopRightDivider(), getStyle().getTopCenterDivider(),
getStyle().getTopRightLeftDivider(), getStyle().getTopRightDivider(), headerLines);
}
public void printLine(String left, String leftRight, String center,
String rightLeft, String right, List<List<String>> cells) {
for (List<String> rowLine : cells) {
printLine(left, leftRight, center, rightLeft, right, rowLine, null);
}
}
public void printLine(String left, String leftRight, String center,
String rightLeft, String right, String border) {
printLine(left, leftRight, center, rightLeft, right, null, border);
}
public void printLine(String left, String leftRight, String center,
String rightLeft, String right, List<String> cellValues, String defaultValue) {
if ("".equalsIgnoreCase(defaultValue)) {
defaultValue = " ";
}
StringBuilder sb = new StringBuilder();
//Render left intersection
sb.append(left);
for (int i = 0; i < columns.size(); i++) {
//Render the first column width using border char
sb.append(cellValues!=null?cellValues.get(i):createString(defaultValue, columns.get(i).getWidth()));
if (i == columns.size() - 1) {
//Last column so print the right intersection
sb.append(right);
} else if (i == 0) {
//If there are two columns, print the left right column and then right column
sb.append(leftRight);
} else if (i == columns.size() - 2) {
//If there are three columns, print the left right column and then right column
sb.append(rightLeft);
} else {
sb.append(center);
}
}
//If trimmed buffer is empty, just skip the line.
if (sb.toString().trim().length() != 0) {
print(sb.toString());
println();
}
}
public List<List<String>> formatHeaderCells() {
int maxHeaderHeight = 0;
for (Column column : columns) {
maxHeaderHeight = Math.max(maxHeaderHeight, Column.getMaxRowHeight(column.getWidth(), column.getTitle()));
}
//Init the header lines array which would store the formatted/aligned strings
List<List<String>> headerLines = new ArrayList<List<String>>();
for (int j = 0; j < maxHeaderHeight; j++) {
headerLines.add(new ArrayList<String>());
}
for (int i = 0; i < columns.size(); i++) {
Column column = columns.get(i);
AlignType align = getTextTableExportOptions().getHeaderAlignment();
if (align == null) {
align = column.getAlign();
}
List<String> cells = Column.align(column.getWidth(), maxHeaderHeight, align, column.getTitle());
for (int j = 0; j < maxHeaderHeight; j++) {
headerLines.get(j).add(cells.get(j));
}
}
return headerLines;
}
protected TextTableExportStyle getStyle() {
return getTextTableExportOptions().getStyle();
}
}