package LinkedList;

import static org.junit.Assert.*;

import org.junit.Test;
import java.util.Iterator;

public class DLLTest {

	@Test
    public void testConstructor() {
        DLL<Integer> c= new DLL<>();
        assertEquals("[]", c.toString());
        assertEquals("[]", c.toStringRev());
        assertEquals(0, c.size());
    }
	
	@Test
	public void testAppend() {
		DLL<String> ll= new DLL<String>(); 
		ll.append("Sampson"); 
		assertEquals("[Sampson]", ll.toString()); 
		assertEquals("[Sampson]", ll.toStringRev()); 
		assertEquals(1, ll.size());
		
		ll.append("Gries");
		assertEquals("[Sampson, Gries]", ll.toString());
		assertEquals("[Gries, Sampson]", ll.toStringRev());
		assertEquals(2,ll.size());
	}
	
	@Test
	public void testPrepend() {
		DLL<String> ll= new DLL<String>(); 
		ll.prepend("Sampson"); 
		assertEquals("[Sampson]", ll.toString()); 
		assertEquals("[Sampson]", ll.toStringRev()); 
		assertEquals(1, ll.size());
		
		ll.prepend("Gries");
		assertEquals("[Gries, Sampson]", ll.toString());
		assertEquals("[Sampson, Gries]", ll.toStringRev());
		assertEquals(2,ll.size());
	}
	
	@Test
	public void testGetNode() {
		DLL<String> ll = new DLL<String>();
		try {
			ll.getNode(-1);
			fail();
		} catch (AssertionError e) {}
		try {
			ll.getNode(0);
			fail();
		} catch (AssertionError e) {}
		
		ll.append("Sampson");
		ll.append("Gries");
		assertEquals(ll.getFirst(),ll.getNode(0));
		assertEquals(ll.getLast(),ll.getNode(1));
		
	}
	
	@Test 
	public void testInsertAfter() {
		DLL<String> ll = new DLL<String>();
		ll.append("Sampson");
		
		ll.insertAfter("Gries", ll.getFirst());
		assertEquals("[Sampson, Gries]", ll.toString()); 
		assertEquals("[Gries, Sampson]", ll.toStringRev()); 
		assertEquals(2, ll.size());
		
		ll.insertAfter("Birrell", ll.getFirst());
		assertEquals("[Sampson, Birrell, Gries]", ll.toString()); 
		assertEquals("[Gries, Birrell, Sampson]", ll.toStringRev()); 
		assertEquals(3, ll.size());
		
	}

	@Test 
	public void testInsertBefore() {
		DLL<String> ll = new DLL<String>();
		ll.append("Sampson");
		
		ll.insertBefore("Gries", ll.getLast());
		assertEquals("[Gries, Sampson]", ll.toString()); 
		assertEquals("[Sampson, Gries]", ll.toStringRev()); 
		assertEquals(2, ll.size());
		
		ll.insertBefore("Birrell", ll.getLast());
		assertEquals("[Gries, Birrell, Sampson]", ll.toString()); 
		assertEquals("[Sampson, Birrell, Gries]", ll.toStringRev()); 
		assertEquals(3, ll.size());
		
	}
	
	public void testRemove() {
		DLL<String> ll = new DLL<String>();
		ll.append("Sampson");
		ll.append("Gries");
		ll.append("Birrell");
		
		try {
			ll.remove(null);
			fail();
		} catch (AssertionError e) {}
		
		try {
			DLL<String> ll2 = new DLL<String>();
			ll2.remove(ll.getFirst());
			fail();
		} catch (AssertionError e) {}
		
		ll.remove(ll.getNode(1));
		assertEquals("[Sampson, Birrell]", ll.toString()); 
		assertEquals("[Birrell, Sampson]", ll.toStringRev()); 
		assertEquals(2, ll.size());
		
		ll.remove(ll.getLast());
		assertEquals("[Sampson]", ll.toString()); 
		assertEquals("[Sampson]", ll.toStringRev()); 
		assertEquals(1, ll.size());
		
		ll.remove(ll.getFirst());
		assertEquals("[]", ll.toString()); 
		assertEquals("[]", ll.toStringRev()); 
		assertEquals(0, ll.size());
		
	}

    /*************************************************************************/

    @Test
    public void testIterator() {
        DLL<Integer> dll= new DLL<>();
        assertEquals("", useIterator(dll));

        dll.append(1); dll.append(8); dll.append(7);
        dll.append(5); dll.append(4); dll.append(3);
        assertEquals("1 8 7 5 4 3 ", useIterator(dll));
    }

    /** Return the enumeration of cll with a blank after each value,
     * using cll.iterator() */
    public static <V> String useIterator(DLL<V> dll) {
        String res= "";
        Iterator<V> it= dll.iterator();
        // invariant: res contains the values that have been
        //        enumerated so far, with a blank after each
        while (it.hasNext()) {
            res= res + it.next() + " ";
        }
        return res;
    }

    @Test
    public void testIterable() {
        DLL<Integer> dll= new DLL<>();
        assertEquals("", useForEach(dll));

        dll.append(1); dll.append(8); dll.append(7);
        dll.append(5); dll.append(4); dll.append(3);
        assertEquals("1 8 7 5 4 3 ", useForEach(dll));
    }

    /** Return the enumeration of cll, with a blank after each value */
    public static <V> String useForEach(DLL<V> dll) {
        String res= "";
        // invariant: res contains the values that have been
        //        enumerated so far (with a blank after each)
        for (V elem : dll) {
            res= res + elem + " ";
        }
        return res;
    }
}