package org.jostraca.tree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jostraca.tree.path.Path;
public class Node {
private Node mParent;
private String mName;
private String mType;
private List<Node> mChildren = new ArrayList<Node>();
private Map<String,String> mAttrMap = new HashMap<String,String>();
protected Node() {}
public Node( String pName, String pType ) {
mName = pName;
mType = pType;
}
public void walk( NodeWalker pNodeWalker ) {
pNodeWalker.entry(this);
for( Node c: mChildren ) {
c.walk(pNodeWalker);
}
pNodeWalker.exit(this);
}
public List<Node> select( String pPath ) throws Exception {
Path p = new Path(pPath);
List<Node> res = p.select( this );
return res;
}
public String value( String pPath ) throws Exception {
Path p = new Path(pPath);
return p.value( this );
}
public Node append( Node pChild ) {
mChildren.add( pChild );
pChild.mParent = this;
return this;
}
public Node append( String pText ) {
return append( new TextNode(pText) );
}
public Node setAttr( String pName, String pValue ) {
return setAttr( pName, pValue, null );
}
public Node setAttr( String pName, String pValue, String pType ) {
String qn = null == pType ? pName : pType+":"+pName;
mAttrMap.put(qn, pValue);
return this;
}
public String getAttr( String pName ) {
return getAttr( pName, null );
}
public String getAttr( String pName, String pType ) {
String qn = null == pType ? pName : pType+":"+pName;
return mAttrMap.get( qn );
}
public boolean hasAttr( String pName ) {
return mAttrMap.containsKey( pName );
}
public Set<String> getAttrs() {
return mAttrMap.keySet();
}
public String getName() {
return mName;
}
public int hashCode() {
return mName.hashCode() ^ mType.hashCode() ^ mChildren.hashCode() ^ mAttrMap.hashCode();
}
public boolean equals( Object pOther ) {
boolean equals = this == pOther;
if( !equals && pOther instanceof Node ) {
Node other = (Node) pOther;
equals = mName.equals(other.mName)
&& mType.equals(other.mType)
&& mChildren.equals( other.mChildren)
&& mAttrMap.equals( other.mAttrMap );
}
return equals;
}
public List<Node> getChildren() {
return mChildren;
}
public String getType() {
return mType;
}
public String getText() {
TextWalker tw = new TextWalker();
walk(tw);
return tw.toString();
}
private static class TextWalker implements NodeWalker {
private StringBuffer mSB = new StringBuffer();
public void entry(Node pNode) {
if( pNode instanceof TextNode ) {
mSB.append( ((TextNode)pNode).getText() );
}
}
public void exit(Node pNode) {}
public String toString() {
return mSB.toString();
}
}
public boolean hasChildren() {
return 0 < mChildren.size();
}
public Node firstChild() {
return hasChildren() ? mChildren.get(0) : null;
}
public Node getParent() {
return mParent;
}
public Node nextSibling() {
Node n = null;
if( null != mParent ) {
List<Node> siblings = mParent.getChildren();
for( int sI = 0; sI < siblings.size()-1; sI++ ) {
if( this == siblings.get(sI) ) {
n = siblings.get(sI+1);
}
}
}
return n;
}
public String toString() {
ToStringWalker tsw = new ToStringWalker();
walk(tsw);
return tsw.toString();
}
private static class ToStringWalker implements NodeWalker {
private StringBuffer mSB = new StringBuffer();
private int mIndent = 0;
public void entry(Node pNode) {
for( int sI = 0; sI < mIndent; sI++ ) {
mSB.append(" ");
}
if( pNode instanceof TextNode ) {
mSB.append( "[" );
mSB.append( pNode.getText() );
mSB.append( "]" );
}
else {
mSB.append( pNode.getType() );
mSB.append( ":" );
mSB.append( pNode.getName() );
}
Set<String> attrs = pNode.getAttrs();
for( String an: attrs ) {
mSB.append(" ");
mSB.append(an);
mSB.append("=");
mSB.append( pNode.getAttr(an));
}
mSB.append("\n");
mIndent+=2;
}
public void exit(Node pNode) {
mIndent-=2;
}
public String toString() {
return mSB.toString();
}
}
private void precond( boolean pPass, String pMsg ) {
if( !pPass ) {
throw new RuntimeException("fail: "+pMsg+": "+toString());
}
}
}