package net.onrc.onos.apps.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<RibEntry> ooptrie;
	
	private Map<String, byte[]> byteAddresses;

	@Before
	public void setUp() throws Exception {
		ptree = new Ptree(32);
		ooptrie = new PatriciaTrie<RibEntry>(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 RibEntry("192.168.10.101", "192.168.60.1");
			ooptrie.put(new Prefix(byteAddresses.get(prefix), prefixLength), 
					new RibEntry("192.168.10.101", "192.168.60.1"));
		}
	}

	@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");
	}
	
	@Ignore
	@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<RibEntry>> it = ooptrie.iterator();
		
		while (it.hasNext()) {
			IPatriciaTrie.Entry<RibEntry> 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;
	}

}
