package net.onrc.onos.core.intent;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import net.onrc.onos.core.intent.IntentOperation.Operator;
import net.onrc.onos.core.topology.LinkEvent;
import net.onrc.onos.core.topology.Path;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * @author Toshio Koide (t-koide@onlab.us)
 */
public class ConstrainedBFSTreeTest {
	static long LOCAL_PORT = 0xFFFEL;

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testCreate() {
		MockNetworkGraph graph = new MockNetworkGraph();
		graph.createSampleTopology1();
		ConstrainedBFSTree tree = new ConstrainedBFSTree(graph.getSwitch(1L));
		assertNotNull(tree);
	}

	@Test
	public void testCreateConstrained() {
		MockNetworkGraph graph = new MockNetworkGraph();
		graph.createSampleTopology1();
		PathIntentMap intents = new PathIntentMap();
		ConstrainedBFSTree tree = new ConstrainedBFSTree(graph.getSwitch(1L), intents, 1000.0);
		assertNotNull(tree);
	}

	@Test
	public void testGetPath() {
		MockNetworkGraph graph = new MockNetworkGraph();
		graph.createSampleTopology1();
		ConstrainedBFSTree tree = new ConstrainedBFSTree(graph.getSwitch(1L));
		Path path11 = tree.getPath(graph.getSwitch(1L));
		Path path12 = tree.getPath(graph.getSwitch(2L));
		Path path13 = tree.getPath(graph.getSwitch(3L));
		Path path14 = tree.getPath(graph.getSwitch(4L));

		assertNotNull(path11);
		assertEquals(0, path11.size());

		assertNotNull(path12);
		assertEquals(1, path12.size());
		assertEquals(new LinkEvent(graph.getLink(1L, 12L)), path12.get(0));

		assertNotNull(path13);
		assertEquals(2, path13.size());
		if (path13.get(0).getDst().getDpid() == 2L) {
			assertEquals(new LinkEvent(graph.getLink(1L, 12L)), path13.get(0));
			assertEquals(new LinkEvent(graph.getLink(2L, 23L)), path13.get(1));
		}
		else {
			assertEquals(new LinkEvent(graph.getLink(1L, 14L)), path13.get(0));
			assertEquals(new LinkEvent(graph.getLink(4L, 43L)), path13.get(1));
		}

		assertNotNull(path14);
		assertEquals(1, path14.size());
		assertEquals(new LinkEvent(graph.getLink(1L, 14L)), path14.get(0));
	}

	@Test
	public void testGetPathNull() {
		MockNetworkGraph graph = new MockNetworkGraph();
		graph.createSampleTopology1();
		graph.removeLink(1L, 12L, 2L, 21L);
		graph.removeLink(1L, 14L, 4L, 41L);
		// now, there is no path from switch 1, but to switch1

		ConstrainedBFSTree tree1 = new ConstrainedBFSTree(graph.getSwitch(1L));
		Path path12 = tree1.getPath(graph.getSwitch(2L));
		Path path13 = tree1.getPath(graph.getSwitch(3L));
		Path path14 = tree1.getPath(graph.getSwitch(4L));

		ConstrainedBFSTree tree2 = new ConstrainedBFSTree(graph.getSwitch(2L));
		Path path21 = tree2.getPath(graph.getSwitch(1L));

		assertNull(path12);
		assertNull(path13);
		assertNull(path14);
		assertNotNull(path21);
		assertEquals(1, path21.size());
		assertEquals(new LinkEvent(graph.getLink(2L, 21L)), path21.get(0));
	}

	@Test
	public void testGetConstrainedPath() {
		MockNetworkGraph graph = new MockNetworkGraph();
		graph.createSampleTopology1();
		PathIntentMap intents = new PathIntentMap();
		IntentOperationList intentOps = new IntentOperationList();

		// create constrained shortest path intents that have the same source destination ports
		ConstrainedShortestPathIntent intent1 = new ConstrainedShortestPathIntent(
				"1", 1L, LOCAL_PORT, 0x111L, 2L, LOCAL_PORT, 0x222L, 600.0);
		ConstrainedShortestPathIntent intent2 = new ConstrainedShortestPathIntent(
				"2", 1L, LOCAL_PORT, 0x333L, 2L, LOCAL_PORT, 0x444L, 600.0);

		// calculate path of the intent1
		ConstrainedBFSTree tree = new ConstrainedBFSTree(graph.getSwitch(1L), intents, 600.0);
		Path path1 = tree.getPath(graph.getSwitch(2L));

		assertNotNull(path1);
		assertEquals(1, path1.size());
		assertEquals(new LinkEvent(graph.getLink(1L, 12L)), path1.get(0));

		PathIntent pathIntent1 = new PathIntent("pi1", path1, 600.0, intent1);
		intentOps.add(Operator.ADD, pathIntent1);
		intents.executeOperations(intentOps);

		// calculate path of the intent2
		tree = new ConstrainedBFSTree(graph.getSwitch(1L), intents, 600.0);
		Path path2 = tree.getPath(graph.getSwitch(2L));

		assertNotNull(path2);
		assertEquals(2, path2.size());
		assertEquals(new LinkEvent(graph.getLink(1L, 14L)), path2.get(0));
		assertEquals(new LinkEvent(graph.getLink(4L, 42L)), path2.get(1));

		PathIntent pathIntent2 = new PathIntent("pi2", path2, 600.0, intent2);
		intentOps.add(Operator.ADD, pathIntent2);
		intents.executeOperations(intentOps);

		// calculate path of the intent3
		tree = new ConstrainedBFSTree(graph.getSwitch(1L), intents, 600.0);
		Path path3 = tree.getPath(graph.getSwitch(2L));

		assertNull(path3);
	}
}