package ch.usi.da.dmap.local;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
/*
* Server process; should be addressable with port (multi instances per server)
*/
public class TreeNode<K extends Comparable<K>,V> implements Comparable<TreeNode<K,V>> {
private TreeNode<K,V> parent = null;
private final int order;
private final int maxKeys;
private K minKey = null; // or splitKey
private TreeNode<K,V> nextNode = null;
private final int maxChildren;
private SortedSet<TreeNode<K,V>> children;
private SortedMap<K,V> data;
public TreeNode(TreeNode<K,V> parent,int order){
this.parent = parent;
this.order = order;
this.maxKeys = order-1;
this.maxChildren = order;
this.children = new TreeSet<TreeNode<K,V>>();
this.data = new TreeMap<K,V>();
}
public void setParent(TreeNode<K,V> node){
parent = node;
}
public TreeNode<K,V> getParent(){
return parent;
}
public Result<V> get(K k){
if(children.isEmpty() && (nextNode == null || k.compareTo(nextNode.minKey) < 0)){
return new Result<V>(true,data.get(k));
}else{
return new Result<V>(false,null);
}
}
public K getMinKey(){
return minKey;
}
public void setMinKey(K k){
minKey = k;
}
public TreeNode<K,V> getNextNode(){
return nextNode;
}
public void setNextNode(TreeNode<K,V> n){
nextNode = n;
}
public SortedMap<K,V> getData(){
return data;
}
public SortedSet<TreeNode<K, V>> getChildren(){
return children;
}
public boolean put(K k,V v){
boolean valid = false;
if(minKey == null){
minKey = k;
}else if(k.compareTo(minKey) <= 0){
minKey = k;
}
// test is leaf and max boundary (allow node split detection)
if(children.isEmpty() && (nextNode == null || k.compareTo(nextNode.minKey) < 0)){
data.put(k,v);
valid = true;
}
if(data.size() > maxKeys){ // split data
if(parent == null){ // root
TreeNode<K,V> left = new TreeNode<K,V>(this,order);
TreeNode<K,V> right = new TreeNode<K,V>(this,order);
int middle = data.size()/2;
@SuppressWarnings("unchecked")
K splitKey = (K) data.keySet().toArray()[middle];
SortedMap<K,V> lmap = new TreeMap<K,V>(data.headMap(splitKey));
left.getData().putAll(lmap);
left.setMinKey(lmap.firstKey());
SortedMap<K,V> rmap = new TreeMap<K,V>(data.tailMap(splitKey));
right.getData().putAll(rmap);
right.setMinKey(rmap.firstKey());
left.setNextNode(right);
children.add(left);
children.add(right);
data.clear();
}else{
TreeNode<K,V> right = new TreeNode<K,V>(parent,order);
int middle = data.size()/2;
@SuppressWarnings("unchecked")
K splitKey = (K) data.keySet().toArray()[middle];
SortedMap<K,V> rmap = new TreeMap<K,V>(data.tailMap(splitKey));
right.getData().putAll(rmap);
right.setMinKey(rmap.firstKey());
data = new TreeMap<K,V>(data.headMap(splitKey));
right.setNextNode(this.getNextNode());
this.setNextNode(right);
minKey = data.firstKey();
parent.addChild(right);
}
}
return valid;
}
public void addChild(TreeNode<K,V> node){
children.add(node);
if(children.size() > maxChildren){ // split inner node
if(parent == null){ // root
TreeNode<K,V> left = new TreeNode<K,V>(this,order);
TreeNode<K,V> right = new TreeNode<K,V>(this,order);
int middle = children.size()/2;
@SuppressWarnings("unchecked")
TreeNode<K,V> splitKey = (TreeNode<K, V>) children.toArray()[middle];
SortedSet<TreeNode<K,V>> lset = new TreeSet<TreeNode<K,V>>(children.headSet(splitKey));
left.getChildren().addAll(lset);
left.setMinKey(lset.first().getMinKey());
for(TreeNode<K,V> n : left.getChildren()){
n.setParent(left);
}
SortedSet<TreeNode<K,V>> rset = new TreeSet<TreeNode<K,V>>(children.tailSet(splitKey));
right.getChildren().addAll(rset);
right.setMinKey(rset.first().getMinKey());
for(TreeNode<K,V> n : right.getChildren()){
n.setParent(right);
}
children.clear();
children.add(left);
children.add(right);
}else{
TreeNode<K,V> right = new TreeNode<K,V>(parent,order);
int middle = children.size()/2;
@SuppressWarnings("unchecked")
TreeNode<K,V> splitKey = (TreeNode<K, V>) children.toArray()[middle];
SortedSet<TreeNode<K,V>> rset = new TreeSet<TreeNode<K,V>>(children.tailSet(splitKey));
right.getChildren().addAll(rset);
right.setMinKey(rset.first().getMinKey());
for(TreeNode<K,V> n : right.getChildren()){
n.setParent(right);
}
children = new TreeSet<TreeNode<K,V>>(children.headSet(splitKey));
minKey = children.first().getMinKey();
parent.addChild(right);
}
}
}
@Override
public String toString(){
StringBuffer buffer = new StringBuffer();
if(data.size() > 0){
buffer.append("D: " + data);
}else{
buffer.append("I: " + children);
}
//buffer.append(" (" + minKey + "/" + nextNode.getMinKey() + ")");
return buffer.toString();
}
@Override
public int compareTo(TreeNode<K,V> o) {
return this.getMinKey().compareTo(o.getMinKey());
}
}