/*******************************************************************************
* Copyright (c) 2012 OpenLegacy Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* OpenLegacy Inc. - initial API and implementation
*******************************************************************************/
package org.openlegacy.terminal.web.render.support;
import org.apache.commons.io.IOUtils;
import org.openlegacy.exceptions.OpenLegacyRuntimeException;
import org.openlegacy.terminal.TerminalField;
import org.openlegacy.terminal.TerminalPosition;
import org.openlegacy.terminal.TerminalSnapshot;
import org.openlegacy.terminal.web.render.ElementsProvider;
import org.openlegacy.terminal.web.render.HtmlProportionsHandler;
import org.openlegacy.terminal.web.render.TerminalSnapshotHtmlRenderer;
import org.openlegacy.utils.DomUtils;
import org.openlegacy.utils.StringUtil;
import org.openlegacy.web.HtmlConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Collection;
import javax.inject.Inject;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
public class DefaultTerminalSnapshotHtmlRenderer implements TerminalSnapshotHtmlRenderer {
private static final String DEFAULT_SNAPSHOT_STYLE_SETTINGS = "#terminalSnapshot {direction:ltr;font-family:FONT_FAMILY;font-size:FONTpx} #terminalSnapshot span {white-space: pre;position:absolute;} #terminalSnapshot input {position:absolute;font-family:Courier New;font-size:FONTpx;height:INPUT-HEIGHTpx;INPUT_STYLE}";
private static final String TERMINAL_HTML = "TERMINAL_HTML";
private String completeStyleSettings = DEFAULT_SNAPSHOT_STYLE_SETTINGS;
private String templateResourceName = "defaultHtmlEmulationTemplate.html";
private boolean includeTemplate = true;
private String fontFamily = "Courier New";
private String inputStyle = "";
@Inject
private ElementsProvider<Element> elementsProvider;
@Inject
private HtmlProportionsHandler htmlProportionsHandler;
private String formActionURL = "emulation";
private String formMethod = HtmlConstants.POST;
public String render(TerminalSnapshot terminalSnapshot) {
String htmlContent = renderHtml(terminalSnapshot);
if (includeTemplate) {
InputStream htmlEmulationTemplateStream = getClass().getResourceAsStream(templateResourceName);
String htmlEmulationTemplateContent;
try {
htmlEmulationTemplateContent = IOUtils.toString(htmlEmulationTemplateStream);
} catch (IOException e) {
throw (new RuntimeException(e));
}
htmlEmulationTemplateContent = htmlEmulationTemplateContent.replace(TERMINAL_HTML, htmlContent);
return htmlEmulationTemplateContent;
}
return htmlContent;
}
private String renderHtml(TerminalSnapshot terminalSnapshot) {
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
Document doc;
try {
doc = dfactory.newDocumentBuilder().newDocument();
String styleSettings = createStyleSettings();
Element formTag = createWrappingTag(doc);
createHiddens(terminalSnapshot, formTag);
createFields(terminalSnapshot, formTag);
String cursorFieldName = getCursorFieldName(terminalSnapshot);
createScript(formTag, cursorFieldName);
calculateWidthHeight(terminalSnapshot, formTag);
// generate style before the document. cause non aligned page when it's part of the document
styleSettings = MessageFormat.format("<style>{0}</style>", styleSettings);
return generate(styleSettings, doc);
} catch (ParserConfigurationException e) {
throw (new OpenLegacyRuntimeException(e));
} catch (TransformerException e) {
throw (new OpenLegacyRuntimeException(e));
}
}
private static String getCursorFieldName(TerminalSnapshot terminalSnapshot) {
TerminalPosition cursorPosition = terminalSnapshot.getCursorPosition();
return cursorPosition != null ? HtmlNamingUtil.getFieldName(cursorPosition) : "";
}
private String createStyleSettings() {
String actualSyleSettings = completeStyleSettings.replaceAll("FONT_FAMILY", String.valueOf(fontFamily));
actualSyleSettings = actualSyleSettings.replaceAll("FONT", String.valueOf(htmlProportionsHandler.getFontSize()));
actualSyleSettings = actualSyleSettings.replaceAll("INPUT-HEIGHT",
String.valueOf(htmlProportionsHandler.getInputHeight()));
actualSyleSettings = actualSyleSettings.replace("INPUT_STYLE", inputStyle);
return actualSyleSettings;
}
private Element createWrappingTag(Document doc) {
Element wrapperTag = (Element)doc.appendChild(doc.createElement(HtmlConstants.DIV));
wrapperTag.setAttribute(HtmlConstants.ID, TerminalHtmlConstants.WRAPPER_TAG_ID);
Element formTag = elementsProvider.createFormTag(wrapperTag, formActionURL, formMethod,
TerminalHtmlConstants.HTML_EMULATION_FORM_NAME);
return formTag;
}
private void createScript(Element formTag, String cursorFieldName) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("try { document.");
stringBuilder.append(TerminalHtmlConstants.HTML_EMULATION_FORM_NAME);
stringBuilder.append(".");
stringBuilder.append(cursorFieldName);
stringBuilder.append(".focus(); } catch { }");
String script = stringBuilder.toString();
elementsProvider.createScriptTag(formTag, script);
}
private void createHiddens(TerminalSnapshot terminalSnapshot, Element formTag) {
String cursorFieldName = getCursorFieldName(terminalSnapshot);
Element cursorHidden = elementsProvider.createHidden(formTag, TerminalHtmlConstants.TERMINAL_CURSOR_HIDDEN);
cursorHidden.setAttribute(HtmlConstants.VALUE, cursorFieldName);
// hidden for keyboard action
elementsProvider.createHidden(formTag, TerminalHtmlConstants.KEYBOARD_KEY);
// hidden for session sequence
Element sequenceHidden = elementsProvider.createHidden(formTag, TerminalHtmlConstants.SEQUENCE);
sequenceHidden.setAttribute(HtmlConstants.VALUE, String.valueOf(terminalSnapshot.getSequence()));
}
private static String generate(String styleSettings, Document doc) throws TransformerConfigurationException,
TransformerFactoryConfigurationError, TransformerException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DomUtils.render(doc, baos);
return styleSettings + StringUtil.toString(baos);
}
private void calculateWidthHeight(TerminalSnapshot terminalSnapshot, Element wrapperTag) {
int width = htmlProportionsHandler.toWidth(terminalSnapshot.getSize().getColumns() + 1);
int height = htmlProportionsHandler.toHeight(terminalSnapshot.getSize().getRows() + 1);
wrapperTag.setAttribute(
HtmlConstants.STYLE,
MessageFormat.format("position:relative;{0}{1}", HtmlNamingUtil.toStyleWidth(width),
HtmlNamingUtil.toStyleHeight(height)));
}
private void createFields(TerminalSnapshot terminalSnapshot, Element formTag) {
Collection<TerminalField> fields = terminalSnapshot.getFields();
for (TerminalField terminalField : fields) {
if (terminalField.isEditable()) {
elementsProvider.createInput(formTag, terminalField);
} else {
elementsProvider.createLabel(formTag, terminalField);
}
}
}
public void setFormActionURL(String formActionURL) {
this.formActionURL = formActionURL;
}
public void setFormMethod(String formMethod) {
this.formMethod = formMethod;
}
public void setIncludeTemplate(boolean includeTemplate) {
this.includeTemplate = includeTemplate;
}
public void setTemplateResourceName(String templateResourceName) {
this.templateResourceName = templateResourceName;
}
public void setFontFamily(String fontFamily) {
this.fontFamily = fontFamily;
}
public void setInputStyle(String inputStyle) {
this.inputStyle = inputStyle;
}
public void setCompleteStyleSettings(String completeStyleSettings) {
this.completeStyleSettings = completeStyleSettings;
}
}