package org.rendersnake.tools;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import org.rendersnake.HtmlCanvas;
import org.rendersnake.Renderable;
public class PrettyWriter extends Writer {
public Writer writer;
public int indentLevel = 0;
private boolean inString = false;
private boolean lastCharWasSlash = false;
public PrettyWriter() {
super();
this.writer = new StringWriter(1024);
}
public PrettyWriter(Writer wrapped) {
super();
this.writer = wrapped;
}
/**
* Answer a pretty formatted HTML output for a Renderable component.
* @param component
* @return
*/
public static String toString(Renderable component) {
HtmlCanvas html = new HtmlCanvas(new PrettyWriter());
try {
component.renderOn(html);
} catch (Exception ex){
throw new RuntimeException("Error writing HTML for component:" + component);
}
return html.toHtml();
}
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
if (len < 2) {
if (lastCharWasSlash && cbuf[0]=='>') indentLevel--;
lastCharWasSlash = cbuf[0]=='/';
writer.write(cbuf, off, len);
return;
}
if (cbuf[off] == '<') {
// open or close
if (cbuf[off + 1] == '/') {
// close
indentLevel--;
this.doIndent(indentLevel);
writer.write(cbuf, off, len);
writer.write('\n');
return;
} else if (cbuf[off + len - 2] == '/') {
// empty
this.doIndent(indentLevel);
writer.write(cbuf, off, len);
writer.write('\n');
return;
} else if (cbuf[off + len - 1] == '>') {
// end open
this.doIndent(indentLevel);
indentLevel++;
writer.write(cbuf, off, len);
this.checkQuotes(cbuf,off, len);
this.doNewLine();
return;
} else {
// open open
this.doIndent(indentLevel);
indentLevel++;
writer.write(cbuf, off, len);
return;
}
} else if (cbuf[off + len - 2] == '/') {
// empty
writer.write(cbuf, off, len);
indentLevel--;
this.doIndent(indentLevel);
return;
}
this.checkQuotes(cbuf, off, len);
writer.write(cbuf, off, len);
}
private void doIndent(int level) throws IOException {
if (inString || level == 0)
return;
this.doNewLine();
for (int i = 0; i < level; i++) {
writer.write('\t');
}
}
private void doNewLine() throws IOException {
if (!inString)
writer.write('\n');
}
private void checkQuotes(char[] cbuf, int off, int len) {
// count number of quotes
int quotes = 0;
for (int i = 0; i < len; i++) {
quotes += cbuf[i+off] == '"' ? 1 : 0;
}
inString = inString ? quotes % 2 == 0 : quotes % 2 == 1;
}
@Override
public void flush() throws IOException {
writer.flush();
}
@Override
public void close() throws IOException {
writer.close();
}
public String toString() {
return writer.toString();
}
}