package ch.hsr.ifs.pasta.tree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import ch.hsr.ifs.pasta.tree.NodeVisitor.AfterVisitBehaviour;
public class Node<T> {
private final T data;
private final List<Node<T>> children;
private Node<T> parent;
private Node<T> ancestor;
private Node<T> thread;
private float x;
private float y;
private float mod;
private int number;
private float change;
private float shift;
private float width;
private boolean treatAsLeaf;
public Node(final T data) {
this(new ArrayList<Node<T>>(), data);
}
public Node(final List<Node<T>> children, final T data) {
this.parent = null;
this.thread = null;
this.data = data;
this.children = children;
this.x = 0;
this.y = 0;
this.mod = 0;
this.ancestor = this;
this.number = 1;
this.width = 1;
this.treatAsLeaf = false;
}
public List<Node<T>> children() {
return hasChildren() ? children : Collections.<Node<T>>emptyList();
}
public List<Node<T>> getChildren() {
return children;
}
public Node<T> parent() {
return parent;
}
/**
* Traverse the tree post order (children first).
*
* @param visitor
*/
public void visit(final NodeVisitor<T> visitor) {
final AfterVisitBehaviour visit = visitor.visit(this);
if (visit == AfterVisitBehaviour.Abort) {
return;
}
for (final Node<T> child : children) {
child.visit(visitor);
}
}
public Node<T> leftMostSibling() {
return (parent.children().get(0) != this) ? parent.children().get(0) : null;
}
public Node<T> leftMostChild() {
if (thread != null) {
return thread;
}
return hasChildren() ? children.get(0) : null;
}
private boolean hasChildren() {
return !(children.isEmpty() || treatAsLeaf);
}
public Node<T> rightMostChild() {
if (thread != null) {
return thread;
}
return hasChildren() ? children.get(children.size() - 1) : null;
}
public Node<T> leftSibling() {
return hasLeftSibling() ? parent.children().get(this.number() - 2) : null;
}
public Node<T> rightSibling() {
return hasRightSibling() ? parent.children().get(this.number()) : null;
}
public boolean hasRightSibling() {
return (parent != null && (parent.children().size() > this.number()));
}
public boolean hasLeftSibling() {
return (parent != null && this.number > 1);
}
public void addChild(final Node<T> child) {
children.add(child);
child.setNumber(children.size());
child.setY(this.y() + 1);
child.setParent(this);
}
public float x() {
return x;
}
protected void setX(final float x) {
this.x = x;
}
public float y() {
return y;
}
protected void setY(final float y) {
this.y = y;
}
public float width() {
return width;
}
public void setWidth(final float width) {
this.width = width;
}
public T data() {
return data;
}
public void treatAsLeaf(final boolean isLeaf) {
this.treatAsLeaf = isLeaf;
}
public boolean isTreatedAsLeaf() {
return treatAsLeaf;
}
protected Node<T> ancestor() {
return ancestor;
}
protected void setAncestor(final Node<T> ancestor) {
this.ancestor = ancestor;
}
protected float mod() {
return mod;
}
protected void setMod(final float mod) {
this.mod = mod;
}
protected Node<T> thread() {
return thread;
}
public void setThread(final Node<T> thread) {
this.thread = thread;
}
protected void setNumber(final int number) {
this.number = number;
}
public int number() {
return number;
}
protected float change() {
return change;
}
protected void setChange(final float change) {
this.change = change;
}
protected float shift() {
return shift;
}
protected void setShift(final float shift) {
this.shift = shift;
}
protected void setParent(final Node<T> parent) {
this.parent = parent;
}
@Override
public String toString() {
return data + ": number:" + number + " x:" + x + " y:" + y;
}
public void adjust() {
JBaum.reset(this);
JBaum.adjustTree(this, 1f, 1f);
}
public void adjust(final float siblingDistance, final float branchDistance) {
JBaum.reset(this);
JBaum.adjustTree(this, siblingDistance, branchDistance);
}
}