Created new version of the PATRICIA Trie which is object oriented, based on Ptree.java. Included unit tests for the new trie
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java
new file mode 100644
index 0000000..9ec50bf
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/IPatriciaTrie.java
@@ -0,0 +1,20 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.util.Iterator;
+
+public interface IPatriciaTrie {
+	public Rib put(Prefix p, Rib r);
+	
+	public Rib lookup(Prefix p);
+	
+	public Rib match(Prefix p);
+	
+	public boolean remove(Prefix p, Rib r);
+	
+	public Iterator<Entry> iterator();
+	
+	interface Entry {
+		public Prefix getPrefix();
+		public Rib getRib();
+	}
+}
diff --git a/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java
new file mode 100644
index 0000000..514758f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrie.java
@@ -0,0 +1,464 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class PatriciaTrie implements IPatriciaTrie{
+	private final byte maskBits[] = {(byte)0x00, (byte)0x80, (byte)0xc0, (byte)0xe0, (byte)0xf0, 
+												 (byte)0xf8, (byte)0xfc, (byte)0xfe, (byte)0xff};
+	
+	private int maxPrefixLength;
+	
+	private Node top;
+
+	public PatriciaTrie(int maxPrefixLength) {
+		this.maxPrefixLength = maxPrefixLength;
+	}
+
+	public synchronized Rib put(Prefix p, Rib r) {
+		if (p.getPrefixLength() > maxPrefixLength) {
+			throw new IllegalArgumentException(String.format(
+					"Prefix length %d is greater than max prefix length %d", 
+					p.getPrefixLength(), maxPrefixLength));
+		}
+		
+		if (p == null || r == null) {
+			throw new NullPointerException();
+		}
+		
+		Node node = top;
+		Node match = null;
+		
+		while (node != null
+				&& node.prefix.getPrefixLength() <= p.getPrefixLength()
+				&& key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), p.getAddress(), p.getPrefixLength()) == true) {
+		    if (node.prefix.getPrefixLength() == p.getPrefixLength()) {
+		    	/*
+		    	 * Prefix is already in tree. This may be an aggregate node, in which case
+		    	 * we are inserting a new prefix, or it could be an actual node, in which 
+		    	 * case we are inserting a new nexthop for the prefix and should return
+		    	 * the old nexthop.
+		    	 */
+		    	Rib oldRib = node.rib;
+		    	node.rib = r;
+		    	return oldRib;
+			}
+
+			match = node;
+			
+			if (bit_check(p.getAddress(), node.prefix.getPrefixLength()) == true) {
+				node = node.right;
+			} else {
+				node = node.left;
+			}
+		}
+
+		Node add = null;
+		
+		if (node == null) {
+			add = new Node(p, r);
+			
+			if (match != null) {
+				node_link(match, add);
+			} else {
+				top = add;
+			}
+		} else {
+			add = node_common(node, p.getAddress(), p.getPrefixLength());
+			if (add == null) {
+				//I think this is -ENOMEM?
+				//return null;
+			}				
+			
+			if (match != null) {
+				node_link(match, add);
+			} else {
+				top = add;
+			}
+			node_link(add, node);
+			
+			if (add.prefix.getPrefixLength() != p.getPrefixLength()) {
+				match = add;
+				
+				add = new Node(p, r);
+				node_link(match, add);
+			}
+			else {
+				add.rib = r;
+			}
+		}
+		
+		//If we added a new Node, there was no previous mapping
+		return null;
+		//return addReference(add);
+	}
+	
+	/*exact match*/
+	public synchronized Rib lookup(Prefix p) {
+		//TODO
+		
+		if (p.getPrefixLength() > maxPrefixLength) {
+			return null;
+		}
+		
+		/*
+		Node node = top;
+		
+		while (node != null
+				&& node.prefix.getPrefixLength() <= p.getPrefixLength()
+				&& key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), p.getAddress(), p.getPrefixLength()) == true) {
+			if (node.prefix.getPrefixLength() == p.getPrefixLength()) {
+				//return addReference(node);
+				return node.rib;
+			}
+			
+			if (bit_check(p.getAddress(), node.prefix.getPrefixLength()) == true) {
+				node = node.right;
+			} else {
+				node = node.left;
+			}
+		}
+		*/
+		
+		Node node = findNode(p);
+		
+		return node == null ? null : node.rib;
+	}
+	
+	/*closest containing prefix*/
+	public synchronized Rib match(Prefix p) {
+		//TODO
+		return null;
+	}
+	
+	public synchronized boolean remove(Prefix p, Rib r) {
+		Node child;
+		Node parent;
+		
+		if (p == null || r == null) {
+			return false;
+		}
+		
+		Node node = findNode(p);
+		
+		if (node == null || node.rib == null || !node.rib.equals(r)) {
+			//Given <prefix, nexthop> mapping is not in the tree
+			return false;
+		}
+		
+		if (node.left != null && node.right != null) {
+			//Remove the Rib entry and leave this node as an aggregate node
+			//In the future, maybe we should re-evaluate what the aggregate prefix should be?
+			//It shouldn't necessarily stay the same.
+			//More complicated if the above prefix is also aggregate.
+			node.rib = null;
+			return true;
+		}
+		
+		if (node.left != null) {
+			child = node.left;
+		} else {
+			child = node.right;
+		}
+		
+		parent = node.parent;
+		
+		if (child != null) {
+			child.parent = parent;
+		}
+		
+		if (parent != null) {
+			if (parent.left == node) {
+				parent.left = child;
+			} else {
+				parent.right = child;
+			}
+		} else {
+			top = child;
+		}
+		
+		/*
+		 * TODO not sure what to do here. I think this is lazily deleting aggregate nodes,
+		 * notice that it used to do nothing if it detected both children were not null earlier.
+		 * But here, what we really should do is reevaluate the aggregate prefix of the parent
+		 * node (if it is indeed an aggregate). Because at the moment, no aggregate node will ever
+		 * be removed. BUT, I don't actually think this presents a correctness problem, at
+		 * least from an external point of view.
+		 */
+		//if (parent != null && parent.refCount == 0) {
+			//node_remove(parent);
+		//}
+		
+		return true;
+	}
+	
+	public Iterator<Entry> iterator() {
+		return new PatriciaTrieIterator(top);
+	}
+	
+	private Node findNode(Prefix p) {
+		Node node = top;
+		
+		while (node != null
+				&& node.prefix.getPrefixLength() <= p.getPrefixLength()
+				&& key_match(node.prefix.getAddress(), node.prefix.getPrefixLength(), p.getAddress(), p.getPrefixLength()) == true) {
+			if (node.prefix.getPrefixLength() == p.getPrefixLength()) {
+				//return addReference(node);
+				return node;
+			}
+			
+			if (bit_check(p.getAddress(), node.prefix.getPrefixLength()) == true) {
+				node = node.right;
+			} else {
+				node = node.left;
+			}
+		}
+		
+		return null;
+	}
+	
+	/*
+	 * Receives a 1-based bit index
+	 * Returns a 1-based byte index
+	 * eg. (0 => 1), 1 => 1, 8 => 1, 9 => 2, 17 => 3
+	 */
+	private int getByteContainingBit(int bitNumber) {
+		return Math.max((bitNumber + 7) / 8, 1);
+	}
+	
+	private boolean key_match(byte [] key1, int key1_len, byte [] key2, int key2_len) {
+		//int offset;
+		//int shift;
+		
+		if (key1_len > key2_len) {
+			return false;
+		}
+		
+		int offset = (Math.min(key1_len, key2_len)) / 8;
+		int shift = (Math.min(key1_len, key2_len)) % 8;
+		
+		if (shift != 0) {
+			if ((maskBits[shift] & (key1[offset] ^ key2[offset])) != 0) {
+				return false;
+			}
+		}
+		
+		while (offset != 0) {
+			offset--;
+			if (key1[offset] != key2[offset]) {
+				return false;
+			}
+		}
+		return true;
+	}
+	
+	private boolean bit_check(byte [] key, int key_bits) {
+		int offset = key_bits / 8;
+		int shift = 7 - (key_bits % 8);
+		int bit = key[offset] & 0xff;
+
+		bit >>= shift;
+		
+		if ((bit & 1) == 1) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+	
+	private void node_link(Node node, Node add) {
+		boolean bit = bit_check(add.prefix.getAddress(), node.prefix.getPrefixLength());
+		
+		if (bit == true) {
+			node.right = add;
+		} else {
+			node.left = add;
+		}
+		add.parent = node;
+	}
+	
+    private Node node_common(Node node, byte [] key, int key_bits) {
+		int i;
+		int limit = Math.min(node.prefix.getPrefixLength(), key_bits) / 8;
+
+		for (i = 0; i < limit; i++) {
+			if (node.prefix.getAddress()[i] != key[i]) {
+				break;
+			}
+		}
+		
+		int common_len = i * 8;
+		int boundary = 0;
+
+		if (common_len != key_bits) {
+			byte diff = (byte)(node.prefix.getAddress()[i] ^ key[i]);
+			byte mask = (byte)0x80;
+			int shift_mask = 0;
+			
+			while (common_len < key_bits && ((mask & diff) == 0)) {
+				boundary = 1;
+
+				shift_mask = (mask & 0xff);
+				shift_mask >>= 1;
+				mask = (byte)shift_mask;
+
+				common_len++;
+			}
+		}
+		
+		//Node add = new Node(null, common_len, maxKeyOctets);
+		//if (add == null)
+			//Another -ENOMEM;
+			//return null;
+		
+		//Creating a new Prefix with a prefix length of common_len
+		//Bits are copied from node's up until the common_len'th bit
+		//Rib is null, because this is an aggregate prefix - it's not
+		//actually been added to the trie.
+		
+		byte[] newPrefix = new byte[getByteContainingBit(maxPrefixLength)];
+		
+		int j;
+		for (j = 0; j < i; j++)
+			newPrefix[j] = node.prefix.getAddress()[j];
+
+		if (boundary != 0)
+			newPrefix[j] = (byte)(node.prefix.getAddress()[j] & maskBits[common_len % 8]);
+		
+		return new Node(new Prefix(newPrefix, common_len), null);
+		//return add;
+	}
+	
+	private class Node {
+		public Node parent = null;
+		public Node left = null;
+		public Node right = null;
+		
+		public Prefix prefix;
+		public Rib rib;
+		
+		public Node(Prefix p, Rib r) {
+			this.prefix = p;
+			this.rib = r;
+		}
+		
+		public Entry getEntry() {
+			return new PatriciaTrieEntry(prefix, rib);
+		}
+	}
+	
+	private class PatriciaTrieEntry implements Entry {
+		private Prefix prefix;
+		private Rib rib;
+		
+		public PatriciaTrieEntry(Prefix prefix, Rib rib) {
+			this.prefix = prefix;
+			this.rib = rib;
+		}
+		
+		@Override
+		public Prefix getPrefix() {
+			return prefix;
+		}
+		
+		@Override
+		public Rib getRib() {
+			return rib;
+		}
+	}
+	
+	private class PatriciaTrieIterator implements Iterator<Entry> {
+		
+		private Node current;
+		private boolean started = false;
+		
+		public PatriciaTrieIterator(Node start) {
+			current = start;
+			
+			//If the start is an aggregate node fast forward to find the next valid node
+			if (current != null && current.rib == null) {
+				current = findNext(current);
+			}
+		}
+
+		@Override
+		public boolean hasNext() {
+			if (current == null) {
+				return false;
+			}
+			
+			if (!started) {
+				return true;
+			}
+			
+			return findNext(current) != null;
+		}
+
+		@Override
+		public Entry next() {
+			if (current == null) {
+				throw new NoSuchElementException();
+			}
+			
+			if (!started) {
+				started = true;
+				return current.getEntry();
+			}
+			
+			current = findNext(current);
+			if (current == null) {
+				throw new NoSuchElementException();
+			}
+			
+			return current.getEntry();
+		}
+
+		@Override
+		public void remove() {
+			// TODO This could be implemented, if it were needed
+			throw new NoSuchElementException();
+		}
+		
+		private Node findNext(Node node) {
+			Node next = null;
+			
+			if (node.left != null) {
+				next = node.left;
+				//addReference(next);
+				//delReference(node);
+				//return next;
+			}
+			else if (node.right != null) {
+				next = node.right;
+				//addReference(next);
+				//delReference(node);
+				//return next;
+			}
+			else {
+				//Node start = node;
+				while (node.parent != null) {
+					if (node.parent.left == node && node.parent.right != null) {
+						next = node.parent.right;
+						//addReference(next);
+						//delReference(start);
+						//return next;
+						break;
+					}
+					node = node.parent;
+				}
+			}
+			
+			if (next == null) {
+				return null;
+			}
+			
+			//If the node doesn't have a rib, it's not an actual node, it's an artifically
+			//inserted aggregate node. We don't want to return these to the user.
+			if (next.rib == null) {
+				return findNext(next);
+			}
+			
+			return next;
+		}
+	}
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java
new file mode 100644
index 0000000..d462d3e
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PatriciaTrieTest.java
@@ -0,0 +1,189 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class PatriciaTrieTest {
+
+	IPatriciaTrie ptrie;
+	Prefix[] prefixes;
+	Map<Prefix, Rib> mappings;
+	
+	@Before
+	public void setUp() throws Exception {
+		ptrie = new PatriciaTrie(32);
+		mappings = new HashMap<Prefix, Rib>();
+		
+		prefixes = new Prefix[] {
+			new Prefix("192.168.10.0", 24),
+			new Prefix("192.168.8.0", 23),
+			new Prefix("192.168.8.0", 22),
+			new Prefix("192.0.0.0", 7),
+			new Prefix("192.168.11.0", 24),
+			new Prefix("10.0.23.128", 25),
+			new Prefix("206.17.144.0", 20),
+			new Prefix("9.17.0.0", 12),
+			new Prefix("192.168.0.0", 16)
+		};
+				
+		for (int i = 0; i < prefixes.length; i++) {
+			mappings.put(prefixes[i], new Rib("192.168.10.101", "192.168.20." + i, 32));
+			ptrie.put(prefixes[i], new Rib("192.168.10.101", "192.168.20." + i, 32));
+		}
+	}
+
+	@After
+	public void tearDown() throws Exception {
+	}
+
+	@Test
+	public void testPut() {
+		IPatriciaTrie ptrie = new PatriciaTrie(32);
+		
+		Prefix p1 = new Prefix("192.168.240.0", 20);
+		Rib r1 = new Rib("192.168.10.101", "192.168.60.2", 20);
+		Rib retval = ptrie.put(p1, r1);
+		assertNull(retval);
+		retval = ptrie.lookup(p1);
+		assertTrue(r1 == retval); //should be the same object
+		
+		Prefix p2 = new Prefix("192.160.0.0", 12);
+		Rib r2 = new Rib("192.168.10.101", "192.168.20.1", 12);
+		retval = ptrie.put(p2, r2);
+		assertNull(retval);
+		
+		Prefix p3 = new Prefix("192.168.208.0", 20);
+		Rib r3 = new Rib("192.168.10.101", "192.168.30.1", 20);
+		retval = ptrie.put(p3,  r3);
+		assertNull(retval);
+		
+		//Insert a new Rib entry over a previous one
+		Rib r3new = new Rib("192.168.10.101", "192.168.60.2", 20);
+		retval = ptrie.put(p3, r3new);
+		assertNotNull(retval);
+		assertTrue(retval.equals(r3));
+		assertTrue(retval == r3); //should be the same object
+		
+		//Now we have an aggregate node with prefix 192.168.192.0/18.
+		//We will insert a Rib at this prefix
+		Prefix p4 = new Prefix("192.168.192.0", 18);
+		Rib r4 = new Rib("192.168.10.101", "192.168.40.1", 18);
+		retval = ptrie.put(p4, r4);
+		assertNull(retval);
+		retval = ptrie.lookup(p4);
+		assertTrue(retval == r4); //should be the same object
+	}
+
+	@Test
+	public void testLookup() {
+		for (Map.Entry<Prefix, Rib> entry : mappings.entrySet()) {
+			Rib r = ptrie.lookup(entry.getKey());
+			assertTrue(entry.getValue().equals(r));
+		}
+		
+		//These are aggregate nodes in the tree. Shouldn't be returned by lookup
+		Prefix p1 = new Prefix("0.0.0.0", 0);
+		Rib retval = ptrie.lookup(p1);
+		assertNull(retval);
+		
+		//We'll put a Rib at an aggregate node and check if lookup returns correctly
+		Prefix p2 = new Prefix("192.0.0.0", 4);
+		Rib r2 = new Rib("192.168.10.101", "192.168.60.1", 4);
+		retval = ptrie.put(p2, r2);
+		assertNull(retval);
+		retval = ptrie.lookup(p2);
+		assertTrue(retval.equals(r2));
+	}
+
+	@Ignore
+	@Test
+	public void testMatch() {
+		fail("Not yet implemented");
+	}
+
+	@Test
+	public void testRemove() {
+		Prefix p1 = new Prefix("192.168.8.0", 23);
+		Rib retval = ptrie.lookup(p1);
+		assertNotNull(retval);
+		boolean success = ptrie.remove(p1, retval);
+		assertTrue(success);
+		
+		Prefix p2 = new Prefix("192.168.8.0", 22);
+		Prefix p3 = new Prefix("192.168.10.0", 24);
+		
+		//Test it does the right thing with null arguments
+		success = ptrie.remove(null, null);
+		assertFalse(success);
+		success = ptrie.remove(p2, null);
+		assertFalse(success);
+		
+		//Check other prefixes are still there
+		retval = ptrie.lookup(p2);
+		assertNotNull(retval);
+		retval = ptrie.lookup(p3);
+		assertNotNull(retval);
+		
+		Prefix p4 = new Prefix("9.17.0.0", 12);
+		retval = ptrie.lookup(p4);
+		assertNotNull(retval);
+		success = ptrie.remove(p4, retval);
+		assertTrue(success);
+		success = ptrie.remove(p4, retval);
+		assertFalse(success);
+		
+		//Check other prefixes are still there
+		retval = ptrie.lookup(p2);
+		assertNotNull(retval);
+		retval = ptrie.lookup(p3);
+		assertNotNull(retval);
+		
+		Prefix p5 = new Prefix("192.0.0.0", 7);
+		retval = ptrie.lookup(p5);
+		assertNotNull(retval);
+		success = ptrie.remove(p5, retval);
+		assertTrue(success);
+		
+		//Check other prefixes are still there
+		retval = ptrie.lookup(p2);
+		assertNotNull(retval);
+		retval = ptrie.lookup(p3);
+		assertNotNull(retval);
+		
+		
+	}
+
+	@Test(expected=java.util.NoSuchElementException.class)
+	public void testIterator() {		
+		int[] order = new int[] {7, 5, 3, 8, 2, 1, 0, 4, 6};
+		
+		Iterator<IPatriciaTrie.Entry> it = ptrie.iterator();
+		int i = 0;
+		assertTrue(it.hasNext());
+		while (it.hasNext()) {
+			IPatriciaTrie.Entry entry = it.next();
+			assertTrue(entry.getPrefix().equals(prefixes[order[i]]));
+			i++;
+		}
+		assertFalse(it.hasNext());
+		assertTrue(i == order.length);
+		
+		IPatriciaTrie pt = new PatriciaTrie(32);
+		Iterator<IPatriciaTrie.Entry> it2 = pt.iterator();
+		assertFalse(it2.hasNext());
+		it.next(); //throws NoSuchElementException
+	}
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PrefixTest.java b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PrefixTest.java
new file mode 100644
index 0000000..01c5ea7
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PrefixTest.java
@@ -0,0 +1,66 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PrefixTest {
+
+	@Before
+	public void setUp() throws Exception {
+	}
+
+	@After
+	public void tearDown() throws Exception {
+	}
+
+	@Test
+	public void testPrefixByteArray() {
+		byte[] b1 = new byte[] {(byte)0x8f, (byte)0xa0, (byte)0x00, (byte)0x00};
+		byte[] b2 = new byte[] {(byte)0x8f, (byte)0xa0, (byte)0xff, (byte)0xff};
+		byte[] b3 = new byte[] {(byte)0x8f, (byte)0xac, (byte)0x00, (byte)0x00};
+		byte[] b4 = new byte[] {(byte)0x8f, (byte)0xa0, (byte)0x00, (byte)0x00};
+		
+		Prefix p1 = new Prefix(b1, 12);
+		Prefix p2 = new Prefix(b2, 12);
+		Prefix p3 = new Prefix(b3, 12);
+		Prefix p4 = new Prefix(b4, 11);
+		
+		//Have different byte arrays, but should be equal after construction
+		assertTrue(p1.equals(p2));
+		assertTrue(p2.equals(p3));
+		
+		//Same byte array, but should be false
+		assertFalse(p1.equals(p4));
+		
+		assertTrue(Arrays.equals(p1.getAddress(), p3.getAddress()));
+		assertTrue(p1.toString().equals(p2.toString()));
+		assertTrue(Arrays.equals(p1.getAddress(), p4.getAddress()));
+		assertFalse(p1.toString().equals(p4.toString()));
+	}
+
+	@Test
+	public void testPrefixString() {
+		Prefix p1 = new Prefix("192.168.166.0", 24);
+		Prefix p2 = new Prefix("192.168.166.0", 23);
+		Prefix p3 = new Prefix("192.168.166.128", 24);
+		Prefix p4 = new Prefix("192.168.166.128", 25);
+		
+		assertFalse(p1.equals(p2));
+		assertTrue(Arrays.equals(p1.getAddress(), p2.getAddress()));
+		
+		assertTrue(p1.equals(p3));
+		assertTrue(Arrays.equals(p1.getAddress(), p2.getAddress()));
+		
+		assertFalse(p3.equals(p4));
+		assertFalse(Arrays.equals(p3.getAddress(), p4.getAddress()));
+		
+		assertTrue(p1.toString().equals(p3.toString()));
+		assertEquals(p1.hashCode(), p3.hashCode());
+	}
+
+}
diff --git a/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java
new file mode 100644
index 0000000..1aa451c
--- /dev/null
+++ b/src/test/java/net/onrc/onos/ofcontroller/bgproute/PtreeTest.java
@@ -0,0 +1,227 @@
+package net.onrc.onos.ofcontroller.bgproute;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.net.InetAddresses;
+
+public class PtreeTest {
+	
+	private Logger log = LoggerFactory.getLogger(PtreeTest.class);
+	
+	private Ptree ptree;
+	private PatriciaTrie ooptrie;
+	
+	private Map<String, byte[]> byteAddresses;
+
+	@Before
+	public void setUp() throws Exception {
+		ptree = new Ptree(32);
+		ooptrie = new PatriciaTrie(32);
+			
+		String[] strPrefixes = {
+			"192.168.10.0/24",
+			"192.168.10.0/23",
+			"192.168.10.0/22",
+			"192.0.0.0/7",
+			"192.168.11.0/24",
+			"10.0.23.128/25",
+			"206.17.144.0/20",
+			"9.17.0.0/12",
+			"192.168.0.0/16"
+		};
+		
+		byteAddresses = new HashMap<String, byte[]>(strPrefixes.length+10);
+		for (String prefix : strPrefixes) {
+			String address = prefix.split("/")[0];
+			int prefixLength = Integer.parseInt(prefix.split("/")[1]);
+			byteAddresses.put(prefix, InetAddresses.forString(address).getAddress());
+			
+			PtreeNode node = ptree.acquire(byteAddresses.get(prefix), prefixLength);
+			node.rib = new Rib("192.168.10.101", "192.168.60.1", prefixLength);
+			ooptrie.put(new Prefix(byteAddresses.get(prefix), prefixLength), 
+					new Rib("192.168.10.101", "192.168.60.1", prefixLength));
+		}
+	}
+
+	@After
+	public void tearDown() throws Exception {
+	}
+
+	@Ignore
+	@Test
+	public void testAcquireByteArray() {
+		fail("Not yet implemented");
+	}
+
+	@Ignore
+	@Test
+	public void testAcquireByteArrayInt() {
+		//First let's test an empty Ptree
+		Ptree localPtree = new Ptree(32);
+		PtreeNode node = localPtree.acquire(new byte[] {0x00, 0x00, 0x00, 0x00});
+		assertTrue(node != null && node.rib == null);
+		
+		//Now let's look at the prepopulated tree
+		String testPrefix = "206.17.144.0/20";
+		PtreeNode existingNode = ptree.acquire(byteAddresses.get(testPrefix), 20);
+		printByteArray(existingNode.key);
+		printByteArray(byteAddresses.get(testPrefix));
+		assertTrue(existingNode != null && existingNode.rib == null);
+		
+		assertTrue(Arrays.equals(existingNode.key, byteAddresses.get(testPrefix)));
+	}
+
+	@Test
+	public void testLookup() {
+		String prefix1 = "192.168.10.12";
+		int length1 = 29;
+		PtreeNode node1 = ptree.lookup(InetAddresses.forString(prefix1).getAddress(), length1);
+		
+		//There should be no direct match
+		assertTrue(node1 == null);
+		
+		log.debug("{} null: {}", "node1", node1 == null ? "true" : "false");
+		
+		String prefix2 = "206.17.144.0";
+		int length2 = 20;
+		PtreeNode node2 = ptree.lookup(InetAddresses.forString(prefix2).getAddress(), length2);
+		
+		assertTrue(node2 != null);
+		assertTrue(Arrays.equals(node2.key, byteAddresses.get(prefix2 + "/" + length2)));
+		
+		log.debug("{} null: {}", "node2", node2 == null ? "true" : "false");
+		if (node2 != null) {
+			log.debug("{} key: {}, keybits: {}", new Object[] {"node2", node2.key, node2.keyBits});
+		}
+		
+		String prefix3 = "192.0.0.0";
+		int length3 = 7;
+		PtreeNode node3 = ptree.lookup(InetAddresses.forString(prefix3).getAddress(), length3);
+		assertTrue(node3 != null);
+	}
+
+	@Test
+	public void testMatch() {
+		String prefix1 = "192.168.10.12";
+		int length1 = 29;
+		PtreeNode node1 = ptree.match(InetAddresses.forString(prefix1).getAddress(), length1);
+		
+		//There should be no direct match, but we should get the covering prefix
+		assertTrue(node1 != null);
+		assertTrue(Arrays.equals(node1.key, byteAddresses.get("192.168.10.0/24")));
+		
+		log.debug("{} null: {}", "node1", node1 == null ? "true" : "false");
+		if (node1 != null) {
+			log.debug("{} key: {}, keybits: {}", new Object[] {"node1", node1.key, node1.keyBits});
+		}
+	}
+	
+	@Ignore
+	@Test
+	public void testTraverse() {
+		
+		String expected = "[0, 0, 0, 0]/0\n";
+		expected += "[8, 0, 0, 0]/6\n";
+		expected += "[9, 17, 0, 0]/12\n";
+		expected += "[10, 0, 23, -128]/25\n";
+		expected += "[-64, 0, 0, 0]/4\n";
+		expected += "[-64, -88, 0, 0]/16\n";
+		expected += "[-64, -88, 8, 0]/22\n";
+		expected += "[-64, -88, 10, 0]/23\n";
+		expected += "[-64, -88, 10, 0]/24\n";
+		expected += "[-64, -88, 11, 0]/24\n";
+		expected += "[-50, 17, -112, 0]/20\n";
+		
+		PtreeNode node;
+		String result = "";
+		
+		for (node = ptree.begin(); node != null; node = ptree.next(node)) {
+			result += printByteArray(node.key) + "/" + node.keyBits + "\n";
+		}
+		
+		assertEquals(expected, result);
+	}
+
+	@Ignore
+	@Test
+	public void testBegin() {
+		fail("Not yet implemented");
+	}
+
+	@Ignore
+	@Test
+	public void testNext() {
+		fail("Not yet implemented");
+	}
+
+	@Ignore
+	@Test
+	public void testDelReference() {
+		fail("Not yet implemented");
+	}
+	
+	@Test
+	public void testMisc() {
+		int bitIndex = -1;
+		int index = (int)(bitIndex / Byte.SIZE);
+	    int bit = (int)(bitIndex % Byte.SIZE);
+	    
+	    log.debug("index {} bit {}", index, bit); 
+	    log.debug("percent {}", 1%8);
+	    
+	    //PtreeNode node1 = new PtreeNode(new byte[] {0x0, 0x0, 0x0, 0x0}, 0, 4);
+	    PtreeNode node1 = new PtreeNode(null, 0, 4);
+	    log.debug("node1: key {}, keybits {}", printByteArray(node1.key), node1.keyBits);
+	    
+	    //PtreeNode node2 = new PtreeNode(new byte[] {(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}, 
+	    PtreeNode node2 = new PtreeNode(null,
+	    		32, 4);
+	    log.debug("node2: key {}, keybits {}", printByteArray(node2.key), node2.keyBits);
+	}
+	
+	@Test
+	public void testIteration() {
+		Iterator<IPatriciaTrie.Entry> it = ooptrie.iterator();
+		
+		while (it.hasNext()) {
+			IPatriciaTrie.Entry entry = it.next();
+			log.debug("PatriciaTrie prefix {} \t {}", entry.getPrefix(), entry.getPrefix().printAsBits());
+		}
+		
+		try {
+			PtreeNode node;
+			for (node = ptree.begin(); node != null; node = ptree.next(node)) {
+				log.debug("Ptree prefix {}/{}", InetAddress.getByAddress(node.key).getHostAddress(), node.keyBits);
+			}
+		} catch (UnknownHostException e) {
+			
+		}
+	}
+	
+	private String printByteArray(byte[] array) {
+		String result = "[";
+		for (byte b : array) {
+			result += b + ", ";
+		}
+		result = result.substring(0, result.length() - 2);
+		result += "]";
+		return result;
+	}
+
+}