package org.basex.io.serial;
import static org.basex.data.DataText.*;
import static org.basex.io.serial.DOTData.*;
import static org.basex.util.Token.*;
import java.io.IOException;
import java.io.OutputStream;
import org.basex.data.ExprInfo;
import org.basex.query.QueryException;
import org.basex.query.item.Item;
import org.basex.util.TokenBuilder;
import org.basex.util.Util;
import org.basex.util.list.IntList;
import org.basex.util.list.ObjList;
/**
* This class serializes data in the DOT syntax.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public final class DOTSerializer extends OutputSerializer {
/** Compact representation. */
private final boolean compact;
/** Cached children. */
private final ObjList<IntList> children = new ObjList<IntList>();
/** Cached attributes. */
private final TokenBuilder tb = new TokenBuilder();
/** Cached nodes. */
private final IntList nodes = new IntList();
/** Current color. */
private String color;
/** Node counter. */
private int count;
/**
* Constructor, defining colors for the dot output.
* @param os output stream
* @param c compact representation
* @throws IOException I/O exception
*/
public DOTSerializer(final OutputStream os, final boolean c)
throws IOException {
super(os, PROPS);
compact = c;
print(HEADER);
}
@Override
protected void startOpen(final byte[] t) {
tb.reset();
}
@Override
public void attribute(final byte[] n, final byte[] v) {
tb.addExt(DOTATTR, name(string(n)), v);
}
@Override
protected void finishOpen() throws IOException {
final byte[] attr = tb.finish();
if(color == null) color = color(string(tag));
if(color == null) color = attr.length == 0 ? ELEM1 : ELEM2;
print(concat(tag, attr), color);
}
@Override
protected void finishEmpty() throws IOException {
finishOpen();
finishClose();
}
@Override
protected void finishClose() throws IOException {
final int c = nodes.get(level);
final IntList il = child(level);
final int is = il.size();
for(int i = 0; i < is; ++i) {
indent();
print(Util.info(DOTLINK, c, il.get(i)));
}
color = null;
il.reset();
}
@Override
public void finishText(final byte[] t) throws IOException {
print(norm(t), DOTData.TEXT);
}
@Override
public void finishComment(final byte[] t) throws IOException {
print(new TokenBuilder(COMM_O).add(norm(t)).add(COMM_C).finish(),
DOTData.COMM);
}
@Override
public void finishPi(final byte[] n, final byte[] v) throws IOException {
print(new TokenBuilder(PI_O).add(n).add(SPACE).add(v).add(PI_C).finish(),
DOTData.PI);
}
@Override
public void finishItem(final Item it) throws IOException {
try {
print(norm(it.string(null)), ITEM);
} catch(final QueryException ex) {
throw new SerializerException(ex);
}
}
@Override
public void close() throws IOException {
indent();
print(FOOTER);
}
/**
* Prints a single node.
* @param t text
* @param col color
* @throws IOException I/O exception
*/
private void print(final byte[] t, final String col) throws IOException {
String txt = string(chop(t, 60)).replaceAll("\"|\\r|\\n", "'");
if(compact) txt = txt.replaceAll("\\\\n\\w+:", "\\\\n");
indent();
print(Util.info(DOTNODE, count, txt, col));
nodes.set(level, count);
if(level > 0) child(level - 1).add(count);
++count;
}
/**
* Returns the children from the stack.
* @param i index
* @return children
*/
private IntList child(final int i) {
while(i >= children.size()) children.add(new IntList());
return children.get(i);
}
@Override
protected byte[] info(final ExprInfo expr) {
color = color(expr);
return token(name(expr));
}
}