package org.anodyneos.xp.tag.fmt;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import javax.servlet.jsp.el.ELException;
import org.anodyneos.servlet.xsl.xalan.AutoHtmlParserUrlGen;
import org.anodyneos.servlet.xsl.xalan.AutoHtmlParserUrlGenDefault;
import org.anodyneos.servlet.xsl.xalan.BBCodeParser;
import org.anodyneos.servlet.xsl.xalan.ParseException;
import org.anodyneos.xp.XpException;
import org.anodyneos.xp.XpOutput;
import org.anodyneos.xp.tagext.XpFragment;
import org.anodyneos.xp.tagext.XpTagSupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
public class BBCodeTag extends XpTagSupport {
public static final String XHTML_NS = "http://www.w3.org/1999/xhtml";
public static final String XHTML_PREFIX = "xhtml";
public static final String MODE_HTML = "html";
public static final String MODE_TEXT = "text";
private static final Log logger = LogFactory.getLog(BBCodeTag.class);
private String text;
private String mode = MODE_HTML;
public void doTag(XpOutput out) throws XpException, ELException,
SAXException {
if (null == text) {
XpFragment body = getXpBody();
if (null == body) {
text = "";
} else {
text = body.invokeToString();
}
}
if (! "".equals(text)) {
try {
if (MODE_TEXT.equals(getMode())) {
BBCodeParserXpText ahps = new BBCodeParserXpText(new java.io.StringReader(text), out);
ahps.process();
} else {
BBCodeParserXp ahps = new BBCodeParserXp(new java.io.StringReader(text), out);
ahps.process();
}
} catch (Exception e) {
// TODO:
}
}
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
protected static AutoHtmlParserUrlGen urlGenDefault = new AutoHtmlParserUrlGenDefault();
protected static Attributes emptyAttributes = new AttributesImpl();
protected class BBCodeParserXpText extends BBCodeParser {
private XpOutput out;
private StringBuffer sb;
private String delayedUrl;
protected BBCodeParserXpText(InputStream stream, XpOutput out) {
super(stream);
this.out = out;
}
protected BBCodeParserXpText(java.io.Reader stream, XpOutput out) {
super(stream);
this.out = out;
}
protected void process() throws ParseException {
Input();
flushText();
}
protected void processWord(String s) { addText(s); }
protected void processSpace(String s) { addText(s); }
protected void processEol(String s) { addText(s); }
protected void processEmail(String s) { addText(s); }
protected void processUrl(String s) { addText(s); }
protected void processFtp(String s) { addText(s); }
protected void processWww(String s) { addText(s); }
private void addText(char c) {
if (null == sb) {
sb = new StringBuffer();
}
sb.append(c);
}
private void addText(String s) {
if (null == sb) {
sb = new StringBuffer();
}
sb.append(s);
}
private void flushText() {
// Write contents of sb to node.
try {
if (null != sb) {
out.write(sb.toString().toCharArray(), 0, sb.length());
sb.setLength(0);
}
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
protected void processInvalidOpen(String arg0) { processWord(arg0); }
protected void processCloseTag(String arg0) {
if (BBCodeParser.TAG_URL.equals(arg0) && null != delayedUrl) {
processWord(" <" + delayedUrl + ">");
delayedUrl = null;
} else if (BBCodeParser.TAG_QUOTE.equals(arg0) || BBCodeParser.TAG_CODE.equals(arg0)) {
// parser removes whitespace around block tags (quote & code). So, add some whitespace.
addText('\n');
addText('\n');
}
}
protected void processOpenColorTag(String arg0) { /* noop */ }
protected void processOpenSizeTag(String arg0) { /* noop */ }
protected void processOpenSimpleTag(String arg0) {
// parser removes whitespace around block tags (quote & code). So, add some whitespace.
if (BBCodeParser.TAG_QUOTE.equals(arg0) || BBCodeParser.TAG_CODE.equals(arg0)) {
addText('\n');
addText('\n');
}
}
protected void processOpenUrlEmailTag(String arg0) { delayedUrl = arg0; }
protected void processOpenUrlFtpTag(String arg0) { delayedUrl = arg0; }
protected void processOpenUrlTag(String arg0) { delayedUrl = arg0; }
protected void processOpenUrlWwwTag(String arg0) { delayedUrl = arg0; }
}
protected class BBCodeParserXp extends BBCodeParser {
private XpOutput out;
private StringBuffer sb;
private AutoHtmlParserUrlGen urlGen;
private List elementStack = new ArrayList();
protected BBCodeParserXp(InputStream stream, XpOutput out) {
super(stream);
this.out = out;
}
protected BBCodeParserXp(java.io.Reader stream, XpOutput out) {
super(stream);
this.out = out;
}
protected void process() throws ParseException {
if (urlGen == null) {
urlGen = urlGenDefault;
}
Input();
flushText();
}
protected void processWord(String s) { addText(s); }
protected void processSpace(String s) { addSpace(s); }
protected void processEol(String s) { addEol(s); }
protected void processEmail(String s) { addHref(urlGen.emailToUrl(s), s); }
protected void processUrl(String s) { addHref(urlGen.urlToUrl(s), s); }
protected void processFtp(String s) { addHref(urlGen.ftpToUrl(s), s); }
protected void processWww(String s) { addHref(urlGen.wwwToUrl(s), s); }
private void addSpace(String s) {
addText(' ');
}
private void addText(char c) {
if (null == sb) {
sb = new StringBuffer();
}
sb.append(c);
}
private void addText(String s) {
if (null == sb) {
sb = new StringBuffer();
}
sb.append(s);
}
private void flushText() {
// Write contents of sb to node.
try {
if (null != sb) {
out.write(sb.toString().toCharArray(), 0, sb.length());
sb.setLength(0);
}
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
private void addHref(String href, String display) {
// first, write out cached text to node
flushText();
try {
// "a" element
out.startElement(XHTML_NS, XHTML_PREFIX + ":a");
out.addAttribute("", "href", href);
out.write(display.toCharArray(), 0, display.length());
out.endElement(XHTML_NS, XHTML_PREFIX + ":a");
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
private void addEol(String s) {
flushText();
try {
// "br" element
out.startElement(XHTML_NS, XHTML_PREFIX + ":br");
out.endElement(XHTML_NS, XHTML_PREFIX + ":br");
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
public AutoHtmlParserUrlGen getUrlGen() {
return urlGen;
}
public void setUrlGen(AutoHtmlParserUrlGen urlGen) {
this.urlGen = urlGen;
}
protected void processCloseTag(String s) {
flushText();
Element[] elements = (Element[]) elementStack.remove(elementStack.size()-1);
for(int i = 0; i < elements.length; i++) {
Element el = elements[i];
try {
out.endElement(el.namespace, el.qName);
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
}
protected void processInvalidOpen(String s) {
processWord(s);
}
protected void processOpenColorTag(String s) {
flushText();
try {
Element el = new Element(XHTML_NS, XHTML_PREFIX + ":span");
pushElements(new Element[] {el});
startElement(el);
out.addAttribute("", "style", "color:" + s + ";");
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
protected void processOpenSimpleTag(String s) {
flushText();
// <#SIMPLE_TAG: "b" | "i" | "u" | "s" | "quote" | "code" >
try {
if (BBCodeParser.TAG_BOLD.equals(s)) {
Element el = new Element(XHTML_NS, XHTML_PREFIX + ":span");
pushElements(new Element[] {el});
startElement(el);
out.addAttribute("", "style", "font-weight:bold;");
} else if (BBCodeParser.TAG_ITALICS.equals(s)) {
Element el = new Element(XHTML_NS, XHTML_PREFIX + ":span");
pushElements(new Element[] {el});
startElement(el);
out.addAttribute("", "style", "font-style:italic;");
} else if (BBCodeParser.TAG_UNDERLINE.equals(s)) {
Element el = new Element(XHTML_NS, XHTML_PREFIX + ":span");
pushElements(new Element[] {el});
startElement(el);
out.addAttribute("", "style", "text-decoration:underline;");
} else if (BBCodeParser.TAG_STRIKETHROUGH.equals(s)) {
Element el = new Element(XHTML_NS, XHTML_PREFIX + ":span");
pushElements(new Element[] {el});
startElement(el);
out.addAttribute("", "style", "text-decoration:line-through;");
} else if (BBCodeParser.TAG_QUOTE.equals(s)) {
Element el1 = new Element(XHTML_NS, XHTML_PREFIX + ":blockquote");
Element el2 = new Element(XHTML_NS, XHTML_PREFIX + ":p");
pushElements(new Element[] {el2, el1});
startElement(el1);
startElement(el2);
} else if (BBCodeParser.TAG_CODE.equals(s)) {
Element el = new Element(XHTML_NS, XHTML_PREFIX + ":pre");
pushElements(new Element[] {el});
startElement(el);
}
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
protected void processOpenSizeTag(String s) {
flushText();
try {
Element el = new Element(XHTML_NS, XHTML_PREFIX + ":span");
pushElements(new Element[] {el});
startElement(el);
out.addAttribute("", "style", "font-size:" + s + "%;");
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
protected void processOpenUrlFtpTag(String s) { _processOpenUrlTag(urlGen.ftpToUrl(s)); }
protected void processOpenUrlWwwTag(String s) { _processOpenUrlTag(urlGen.wwwToUrl(s)); }
protected void processOpenUrlEmailTag(String s) { _processOpenUrlTag(urlGen.emailToUrl(s)); }
protected void processOpenUrlTag(String s) { _processOpenUrlTag(urlGen.urlToUrl(s)); }
protected void _processOpenUrlTag(String s) {
flushText();
try {
Element el = new Element(XHTML_NS, XHTML_PREFIX + ":a");
pushElements(new Element[] {el});
startElement(el);
out.addAttribute("", "href", s);
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
private void pushElements(Element[] elements) {
this.elementStack.add(elements);
}
private void startElement(Element el) {
try {
out.startElement(el.namespace, el.qName);
} catch (SAXException e) {
logger.error("FIXME: Thrown away SAXException.", e);
// FIXME: should not throw away exception
}
}
}
protected class Element {
protected Element(String namespace, String qName) {
this.namespace = namespace;
this.qName = qName;
}
String namespace;
String qName;
}
public String getMode() { return mode; }
public void setMode(String mode) { this.mode = mode; }
}