import static org.junit.Assert.*;

import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;

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


public class QuizTest {

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}
	
	private BinaryTree<String> constructFromPreorder(boolean linkedTree, List<String> preorder) {
		if (linkedTree)
			return LinkedBinaryTree.createFromPreorder(preorder);
		else
			return SequentialBinaryTree.createFromPreorder(preorder);
	}

	@Test
	public void linkedTreeTestCreateFromPreorderAndBinarySearch() {
		testCreateFromPreorderAndBinarySearch(true);
	}
	
	@Test
	public void linkedTreeTestBinarySearchAndConstructPreorder() {
		testBinarySearchAndConstructPreorder(true);
	}

	@Test
	public void linkedTreeCreateFromAndBuildPreorder() {
		testCreateFromAndBuildPreorder(true);
	}

	@Test
	public void linkedTreeBinaryTreeSearch() {
		testBinaryTreeSearch(true);
	}


	@Test
	public void sequentialTreeTestCreateFromPreorderAndBinarySearch() {
		testCreateFromPreorderAndBinarySearch(false);
	}
	
	@Test
	public void sequentialTreeTestBinarySearchAndConstructPreorder() {
		testBinarySearchAndConstructPreorder(false);
	}

	@Test
	public void sequentialTreeCreateFromAndBuildPreorder() {
		testCreateFromAndBuildPreorder(false);
	}
	
	@Test
	public void sequentialTreeBinaryTreeSearch() {
		testBinaryTreeSearch(false);
	}

	public void testCreateFromPreorderAndBinarySearch(boolean linkedTree) {
		List<String> preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "Elephant",
				"Mouse", "Does it live underwater?", "Trout", "Robin");

		BinaryTree<String> tree = constructFromPreorder(linkedTree, preorder);

		BinaryTreeSearch<String> search = tree.binaryTreeSearch();
		assertEquals("Is it a mammal?", search.getData());
		search.nextRightChild();
		assertEquals("Does it live underwater?", search.getData());
		search.nextRightChild();
		assertEquals("Robin", search.getData());
	}

	public void testBinarySearchAndConstructPreorder(boolean linkedTree) {
		BinaryTree<String> tree = linkedTree ? new LinkedBinaryTree<String>() : new SequentialBinaryTree<String>();
		
		BinaryTreeSearch<String> search = tree.binaryTreeSearch();
		search.setNode("Is it a mammal?", "d1", "d2");
		search.nextLeftChild();
		search.setNode("Is it bigger than a tiger?", "Elephant", "Mouse");
		search = tree.binaryTreeSearch();
		search.nextRightChild();
		search.setNode("Does it live underwater?", "Trout", "Robin");

		List<String> preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "Elephant",
				"Mouse", "Does it live underwater?", "Trout", "Robin");
		assertEquals(preorder, tree.preorder());
	}
	
	public void testCreateFromAndBuildPreorder(boolean linkedTree) {
		List<String> preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "Elephant",
				"Mouse", "Does it live underwater?", "Trout", "Robin");
		BinaryTree<String> tree = constructFromPreorder(linkedTree, preorder);
		assertEquals(preorder, tree.preorder());
	}

	public void testBinaryTreeSearch(boolean linkedTree) {
		BinaryTree<Integer> tree = linkedTree ? new LinkedBinaryTree<Integer>() : new SequentialBinaryTree<Integer>();
		BinaryTreeSearch<Integer> search = tree.binaryTreeSearch();
		search.setNode(2, 5, 15);
		search.nextLeftChild();
		search.setNode(5, -5, -8);
		search = tree.binaryTreeSearch();
		search.nextRightChild();
		search.setNode(15, 2, -5);
		search.nextLeftChild();
		search.setNode(2, -20, -10);
		
		search = tree.binaryTreeSearch();
		assertEquals(2, search.getData().intValue());
		search.nextLeftChild();
		assertEquals(5, search.getData().intValue());
		search.nextRightChild();
		assertEquals(-8, search.getData().intValue());

		search = tree.binaryTreeSearch();
		search.nextLeftChild();
		search.nextRightChild();
		try {
			search.nextLeftChild();
			assertTrue("Expected NoSuchElementException!", false);
		} catch (NoSuchElementException e) {
		}
	}

	
	@Test
	public void quizTestLinkedRunSuccess() {
		testRunSuccess(true);
	}
	
	@Test
	public void quizTestSequentialRunSuccess() {
		testRunSuccess(false);
	}
	
	@Test
	public void quizTestLinkedRunLearn() {
		testRunLearn(true);
	}
	
	@Test
	public void quizTestSequentialRunLearn() {
		testRunLearn(false);
	}
	
	public void testRunSuccess(boolean linkedTree) {
		List<String> preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "elephant",
				"mouse", "Does it live underwater?", "trout", "robin");
		
		UnitTestIoAdapter ioAdapter = new UnitTestIoAdapter();
		
		Quiz quiz = new Quiz(constructFromPreorder(linkedTree, preorder), ioAdapter);

		ioAdapter.queueYesNoQuestion("a mammal");
		ioAdapter.queueAnswer(true);
		ioAdapter.queueYesNoQuestion("bigger than a tiger");
		ioAdapter.queueAnswer(true);
		ioAdapter.queueYesNoQuestion("elephant");
		ioAdapter.queueAnswer(true);
		quiz.run();
	}

	public void testRunLearn(boolean linkedTree) {
		List<String> preorder = Arrays.asList("Is it a mammal?", "Is it bigger than a tiger?", "elephant",
				"mouse", "Does it live underwater?", "trout", "robin");
		
		UnitTestIoAdapter ioAdapter = new UnitTestIoAdapter();
		
		Quiz quiz = new Quiz(constructFromPreorder(linkedTree, preorder), ioAdapter);

		ioAdapter.queueYesNoQuestion("a mammal");
		ioAdapter.queueAnswer(true);
		ioAdapter.queueYesNoQuestion("bigger than a tiger");
		ioAdapter.queueAnswer(true);
		ioAdapter.queueYesNoQuestion("elephant");
		ioAdapter.queueAnswer(false);
		ioAdapter.queueAnswer("whale");
		ioAdapter.queueAnswer("Does it live underwater?");
		ioAdapter.queueYesNoQuestion("?");
		ioAdapter.queueAnswer(true);
		
		quiz.run();
		
		// Next round
		ioAdapter.queueYesNoQuestion("a mammal");
		ioAdapter.queueAnswer(true);
		ioAdapter.queueYesNoQuestion("bigger than a tiger");
		ioAdapter.queueAnswer(true);
		ioAdapter.queueYesNoQuestion("underwater");
		ioAdapter.queueAnswer(true);
		ioAdapter.queueYesNoQuestion("whale");
		ioAdapter.queueAnswer(true);
		
		quiz.run();
	}
}
