/*
* Copyright 2014 Jocki Hendry
*
* 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.
*/
package simple.escp.json;
import simple.escp.dom.Line;
import simple.escp.dom.PageFormat;
import simple.escp.dom.Report;
import simple.escp.dom.TableColumn;
import simple.escp.dom.line.ListLine;
import simple.escp.dom.line.TableLine;
import simple.escp.dom.line.TextLine;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonValue;
import java.util.logging.Logger;
/**
* A helper class for parsing.
*/
public class Parser {
private static final Logger LOG = Logger.getLogger("simple.escp");
private Report result;
private Integer pageLength;
private PageFormat pageFormat;
private JsonArray firstPage;
private JsonArray lastPage;
private JsonArray header;
private JsonArray footer;
private JsonArray lastPageFooter;
private JsonArray detail;
/**
* Create a new instance of this class.
*
* @param pageFormat a <code>PageFormat</code>.
*/
public Parser(PageFormat pageFormat) {
this.pageFormat = pageFormat;
this.pageLength = pageFormat.getPageLength();
}
/**
* Set the "firstPage" section.
*
* @param firstPage a <code>JsonArray</code> or <code>null</code> if it is not available.
*/
public void setFirstPage(JsonArray firstPage) {
this.firstPage = firstPage;
}
/**
* Set the "header" section.
*
* @param header a <code>JsonArray</code> or <code>null</code> if it is not available.
*/
public void setHeader(JsonArray header) {
if (pageLength == null) {
throw new IllegalArgumentException("Can't use 'header' if 'pageLength' is not defined.");
}
this.header = header;
}
/**
* Set the "footer" section.
*
* @param footer a <code>JsonArray</code> or <code>null</code> if it is not available.
*/
public void setFooter(JsonArray footer) {
if (pageLength == null) {
throw new IllegalArgumentException("Can't use 'footer' if 'pageLength' is not defined.");
}
this.footer = footer;
}
/**
* Set the "lastPageFooter" section.
*
* @param lastPageFooter a <code>JsonArray</code> or <code>null</code> if it is not available.
*/
public void setLastPageFooter(JsonArray lastPageFooter) {
if (pageLength == null) {
throw new IllegalArgumentException("Can't use 'lastPageFooter' if 'pageLength' is not defined.");
}
this.lastPageFooter = lastPageFooter;
}
/**
* Set the "lastPage" section.
*
* @param lastPage a <code>JsonArray</code> or <code>null</code> if it is not available.
*/
public void setLastPage(JsonArray lastPage) {
this.lastPage = lastPage;
}
/**
* Set the "detail" section. If this method is called more than once, it will append the
* <code>JsonArray</code> to previous detail.
*
* @param detail a <code>JsonArray</code>.
*/
public void setDetail(JsonArray detail) {
if (this.detail == null) {
this.detail = detail;
} else {
this.detail.addAll(detail);
}
}
/**
* Convert <code>JsonArray</code> into <code>String[]</code>.
*
* @param text is the JSON array to convert.
* @return result in <code>String[]</code>.
*/
private String[] jsonToString(JsonArray text) {
int size = (text == null ? 0 : text.size());
String[] result = new String[size];
for (int i = 0; i < size; i++) {
result[i] = text.getString(i);
}
return result;
}
/**
* Convert <code>JsonArray</code> into <code>TextLine[]</code>. This method will <strong>ignore</strong>
* non-text line or dynamic line such as <code>TableLine</code>.
*
* <p>See also {@link #jsonToLine(javax.json.JsonArray)} for converting to generic <code>Line[]</code>.
*
* @param text is the JSON array to convert.
* @return result in <code>TextLine[]</code>.
*/
private TextLine[] jsonToTextLine(JsonArray text) {
LOG.fine("Converting [" + text + "] into TextLine.");
int size = (text == null ? 0 : text.size());
TextLine[] result = new TextLine[size];
for (int i = 0; i < size; i++) {
JsonValue value = text.get(i);
if (value.getValueType() == JsonValue.ValueType.STRING) {
result[i] = new TextLine(text.getString(i));
} else {
LOG.warning("[" + value + "] is not a string and will be skipped.");
}
}
return result;
}
/**
* Convert <code>JsonObject</code> into <code>TableLine</code>.
*
* @param table is the JSON object to convert.
* @return result in <code>TableLine</code>.
*/
private TableLine jsonToTableLine(JsonObject table) {
LOG.fine("Converting [" + table + "] into TableLine.");
TableLine tableLine = new TableLine(table.getString("table"));
if (table.containsKey("border")) {
tableLine.setDrawBorder(table.getBoolean("border", false));
}
if (table.containsKey("lineSeparator")) {
tableLine.setDrawLineSeparator(table.getBoolean("lineSeparator", false));
}
if (table.containsKey("underlineSeparator")) {
tableLine.setDrawUnderlineSeparator(table.getBoolean("underlineSeparator", false));
}
JsonArray columns = table.getJsonArray("columns");
if (columns == null) {
throw new IllegalArgumentException("Table must have 'columns'.");
} else {
for (int i = 0; i < columns.size(); i++) {
JsonObject column = columns.getJsonObject(i);
if (!column.containsKey("source")) {
throw new IllegalArgumentException("Can't find 'source' for column " + i);
}
if (!column.containsKey("width")) {
throw new IllegalArgumentException("Can't find 'width' for column " + i);
}
TableColumn tableColumn = tableLine.addColumn(column.getString("source"), column.getInt("width"));
if (column.containsKey("caption")) {
tableColumn.setCaption(column.getString("caption"));
}
if (column.containsKey("wrap")) {
tableColumn.setWrap(column.getBoolean("wrap", false));
}
}
}
return tableLine;
}
/**
* Convert <code>JsonObject</code> into <code>ListLine</code>.
*
* @param list is the JSON object to convert.
* @return result in <code>ListLine</code>.
*/
private ListLine jsonToListLine(JsonObject list) {
LOG.fine("Converting [" + list + "] into ListLine.");
String source = list.getString("list");
if (!list.containsKey("line")) {
throw new IllegalArgumentException("List must have 'line'.");
}
String line = list.getString("line");
TextLine[] header = null, footer = null;
if (list.containsKey("header")) {
header = jsonToTextLine(list.getJsonArray("header"));
}
if (list.containsKey("footer")) {
footer = jsonToTextLine(list.getJsonArray("footer"));
}
return new ListLine(source, line, header, footer);
}
/**
* Convert <code>JsonArray</code> into <code>Line[]</code>.
*
* @param text is the JSON array to convert.
* @return result in <code>Line[]</code>.
*/
private Line[] jsonToLine(JsonArray text) {
LOG.fine("Converting [" + text + "] into Line.");
int size = (text == null ? 0 : text.size());
Line[] result = new Line[size];
for (int i = 0; i < size; i++) {
JsonValue value = text.get(i);
if (value.getValueType() == JsonValue.ValueType.STRING) {
result[i] = new TextLine(text.getString(i));
} else if (value.getValueType() == JsonValue.ValueType.OBJECT) {
JsonObject object = text.getJsonObject(i);
if (object.containsKey("table")) {
result[i] = jsonToTableLine(object);
} else if (object.containsKey("list")) {
result[i] = jsonToListLine(object);
} else {
LOG.warning("Found unsupported object [" + object + "]");
throw new IllegalArgumentException("Unsupported object: " + object);
}
}
}
return result;
}
/**
* Before calling this method, don't forget to call setters such as <code>setFirstPage()</code>,
* <code>setLastPage()</code>, <code>setDetail()</code>, etc. The parse result from this method
* can also be obtained later by calling <code>getResult()</code>.
*
* @return result of parsing in <code>Pages</code>.
*/
public Report parse() {
result = new Report(pageFormat, jsonToTextLine(header), jsonToTextLine(footer), jsonToTextLine(lastPageFooter));
if (firstPage != null) {
LOG.fine("Parsing firstPage section");
result.appendSinglePage(jsonToLine(firstPage), true);
result.lineBreak();
}
if (detail != null) {
LOG.fine("Parsing detail section");
for (Line line: jsonToLine(detail)) {
result.append(line, false);
}
}
if (lastPage != null) {
LOG.fine("Parsing lastPage section");
result.lineBreak();
result.appendSinglePage(jsonToLine(lastPage), true);
}
return getResult();
}
/**
* Get the result of previous <code>parse()</code> invocation. If <code>parse()</code> hasn't been invoked
* before, this method will invoke it and return the result.
*
* @return result of parsing in <code>Pages</code>.
*/
public Report getResult() {
if (result == null) {
parse();
}
return result;
}
}