/*
* Copyright (C) 2013 4th Line GmbH, Switzerland
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fourthline.lemma.reader.content.printer;
import org.fourthline.lemma.anchor.CitationAnchor;
import org.seamless.xhtml.Option;
import org.seamless.xhtml.XHTML;
import org.seamless.xhtml.XHTMLElement;
import org.seamless.xhtml.XHTMLParser;
import org.seamless.xml.ParserException;
import javax.xml.xpath.XPath;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Christian Bauer
*/
abstract public class CalloutContentPrinter extends ContentPrinter {
final public static Pattern PATTERN_CALLOUT = Pattern.compile("^\\s*DOC:\\s*CALLOUT.*");
@Override
protected void append(String[] source, CitationAnchor citation, XHTMLElement contentElement, String... preFormattedClasses) {
// TODO: This option should be tested!
Option calloutsOption = citation.getOption(CitationAnchor.OptionKey.CALLOUTS);
boolean calloutsEnabled = calloutsOption == null || Boolean.valueOf(calloutsOption.getFirstValue());
List<Integer> skippedLines = new ArrayList<Integer>();
Map<Integer, String> callouts = new LinkedHashMap<Integer, String>();
int currentLine = 0;
while (currentLine < source.length) {
String line = source[currentLine];
List<Integer> commentLines = new ArrayList<Integer>();
if (getCommentBeginPattern().matcher(line).matches()) {
StringBuilder blockComment = new StringBuilder();
commentLines.clear();
Matcher blockCommentEndMatcher = getCommentEndPattern().matcher(line);
boolean foundBlockCommentEnd = blockCommentEndMatcher.matches();
line = line.trim();
line = replaceCommentBegin(line);
if (foundBlockCommentEnd)
line = replaceCommentEnd(line);
blockComment.append(line);
commentLines.add(currentLine);
while (!foundBlockCommentEnd && currentLine + 1 < source.length) {
currentLine++;
line = source[currentLine];
blockCommentEndMatcher = getCommentEndPattern().matcher(line);
foundBlockCommentEnd = blockCommentEndMatcher.matches();
line = line.trim();
if (foundBlockCommentEnd)
line = replaceCommentEnd(line);
line = replaceLine(line);
if (!line.startsWith(" "))
line = " " + line;
blockComment.append(line);
commentLines.add(currentLine);
}
String blockCommentString = blockComment.toString();
currentLine++;
if (PATTERN_CALLOUT.matcher(blockCommentString).matches()) {
String calloutText = blockCommentString.replaceAll("DOC:\\s*CALLOUT", "").trim();
callouts.put(currentLine, calloutText);
skippedLines.addAll(commentLines);
}
} else {
currentLine++;
}
}
StringBuilder preFormattedString = new StringBuilder();
currentLine = 0;
int currentCallout = 1;
boolean searchNextLine = false;
while (currentLine < source.length) {
if (skippedLines.contains(currentLine)) {
currentLine++;
continue;
}
String line = source[currentLine];
if (searchNextLine || callouts.containsKey(currentLine)) {
if (calloutsEnabled && isCalloutMarkerLine(line)) {
preFormattedString.append(line)
.append(wrapCalloutMarker(currentCallout++))
.append(getEndOfLine());
searchNextLine = false;
} else {
preFormattedString.append(line).append(getEndOfLine());
searchNextLine = true;
}
} else {
preFormattedString.append(line).append(getEndOfLine());
}
currentLine++;
}
XHTMLParser parser = new XHTMLParser();
XPath xpath = parser.createXPath();
XHTMLElement preFormatted =
createPreFormattedElement(contentElement, preFormattedClasses);
if (preFormattedString.length() > 0) {
preFormatted.setContent(preFormattedString.toString());
} else {
preFormatted.getParent().removeChild(preFormatted);
}
if (calloutsEnabled) {
XHTMLElement calloutList =
contentElement.createChild(XHTML.ELEMENT.ol)
.setClasses("callouts");
// Wrap the callout comment in an XHTML <li> and append to the <ol>
for (String calloutString : callouts.values()) {
if (calloutString.length() > 0) {
try {
XHTML calloutContent = parser.parse(
XHTMLParser.wrap(
XHTML.ELEMENT.li.name(),
XHTML.NAMESPACE_URI,
calloutString
)
);
XHTMLElement calloutItem = calloutContent.getRoot(xpath);
calloutItem.setClasses("callout");
calloutList.appendChild(calloutItem, true);
} catch (ParserException ex) {
throw new RuntimeException(
"Error parsing callout comment as XHTML: " + calloutString, ex
);
}
}
}
if (calloutList.getChildren().length == 0)
calloutList.getParent().removeChild(calloutList);
}
}
protected boolean isCalloutMarkerLine(String line) {
return true;
}
abstract protected String wrapCalloutMarker(int callout);
abstract protected Pattern getCommentBeginPattern();
abstract protected Pattern getCommentEndPattern();
abstract protected String replaceCommentBegin(String line);
abstract protected String replaceCommentEnd(String line);
abstract protected String replaceLine(String line);
}