/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.iterators;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import net.ranides.assira.collection.lists.IntArrayList;
import net.ranides.assira.collection.suite.IteratorTester;
import org.junit.Test;
import static net.ranides.assira.junit.NewAssert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class IteratorUtilsTest {
	
	@Test
	public void testFirst() {
		assertEquals((Integer)1, IteratorUtils.first(Arrays.asList(1,2,3,4).iterator()));
		assertEquals((Integer)1, IteratorUtils.first(Arrays.asList(1,2).iterator()));
		assertEquals((Integer)1, IteratorUtils.first(Arrays.asList(1).iterator()));
		
		assertThrows(NoSuchElementException.class, () -> {
			IteratorUtils.first(Arrays.asList().iterator());
		});
	}
	
	@Test
	public void testLast() {
		assertEquals((Integer)4, IteratorUtils.last(Arrays.asList(1,2,3,4).iterator()));
		assertEquals((Integer)4, IteratorUtils.last(Arrays.asList(3,4).iterator()));
		assertEquals((Integer)4, IteratorUtils.last(Arrays.asList(4).iterator()));
		
		assertThrows(NoSuchElementException.class, () -> {
			IteratorUtils.last(Arrays.asList().iterator());
		});
	}
	
	
	@Test
	public void testFirst_Filter() {
		assertEquals((Integer)7, IteratorUtils.first(Arrays.asList(1,2,7,0,8,0,3).iterator(), a -> a>5));
		
		assertThrows(NoSuchElementException.class, () -> {
			IteratorUtils.first(Arrays.asList(1,2,3).iterator(), a -> a>5);
		});
		assertThrows(NoSuchElementException.class, () -> {
			IteratorUtils.first(Arrays.<Integer>asList().iterator(), a -> a>5);
		});
	}
	
	@Test
	public void testLast_Filter() {
		assertEquals((Integer)8, IteratorUtils.last(Arrays.asList(1,2,7,0,8,0,3).iterator(), a -> a>5));
		assertEquals((Integer)8, IteratorUtils.last(Arrays.asList(1,2,7,0,8).iterator(), a -> a>5));
		assertEquals((Integer)8, IteratorUtils.last(Arrays.asList(1,8).iterator(), a -> a>5));
		assertEquals((Integer)8, IteratorUtils.last(Arrays.asList(8,1).iterator(), a -> a>5));
		
		assertThrows(NoSuchElementException.class, () -> {
			IteratorUtils.last(Arrays.asList(1,2,3).iterator(), a -> a>5);
		});
		assertThrows(NoSuchElementException.class, () -> {
			IteratorUtils.last(Arrays.<Integer>asList().iterator(), a -> a>5);
		});
	}
	
	@Test
	public void testSize() {
		assertEquals(4, IteratorUtils.size(Arrays.asList(1,2,7,8).iterator()));
		assertEquals(2, IteratorUtils.size(Arrays.asList(1,2).iterator()));
		assertEquals(1, IteratorUtils.size(Arrays.asList(1).iterator()));
		assertEquals(0, IteratorUtils.size(Arrays.asList().iterator()));
		assertEquals(0, IteratorUtils.size(null));
	}
	
	@Test
	public void testMap_Iterator() {
        List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
		
        Iterator<String> a = IteratorUtils.map(list.iterator(), String::toUpperCase);
		IteratorTester.basicIterator(a, 0, new String[]{"A", "B", "C", "D"});
        
        Iterator<String> b = IteratorUtils.map(list.iterator(), String::toUpperCase);
        b.next();
        b.remove();
        b.next();
        b.next();
        b.remove();
        assertEquals(Arrays.asList("b","d"), list);
	}
	
	@Test
	public void testMap_ListIterator() {
        List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
		
        ListIterator<String> a = IteratorUtils.map(list.listIterator(), String::toUpperCase);
		IteratorTester.listIterator(a, 0, new String[]{"A", "B", "C", "D"});
        
        ListIterator<String> b = IteratorUtils.map(list.listIterator(), String::toUpperCase);
        b.next();
        b.remove();
        b.next();
        assertThrows(UnsupportedOperationException.class, ()->{ b.set("Q"); });
        assertThrows(UnsupportedOperationException.class, ()->{ b.add("Q"); });
        b.next();
        b.remove();
        assertEquals(Arrays.asList("b","d"), list);
	}
	
	@Test
	public void testFilter_Iterator() {
		List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);

		IteratorTester.basicIterator(IteratorUtils.filter(list.iterator(), v -> v%2==0), 0, new Integer[]{2,4,6,8});
		IteratorTester.basicIterator(IteratorUtils.filter(list.iterator(), v -> v%2==1), 0, new Integer[]{1,3,5,7,9});
		IteratorTester.basicIterator(IteratorUtils.filter(list.iterator(), v -> v>5), 0, new Integer[]{6,7,8,9});
	}
	
	@Test
	public void testFilter_ListIterator() {
		List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);

		IteratorTester.listIterator(IteratorUtils.filter(list.listIterator(), v -> v%2==0), 0, new Integer[]{2,4,6,8});
		IteratorTester.listIterator(IteratorUtils.filter(list.listIterator(), v -> v%2==1), 0, new Integer[]{1,3,5,7,9});
		IteratorTester.listIterator(IteratorUtils.filter(list.listIterator(), v -> v>5), 0, new Integer[]{6,7,8,9});
		
		
		IteratorTester.listIterator(IteratorUtils.filter(list.listIterator(2), v -> v%2==0), 0, new Integer[]{4,6,8});
		IteratorTester.listIterator(IteratorUtils.filter(list.listIterator(2), v -> v%2==1), 0, new Integer[]{3,5,7,9});
		IteratorTester.listIterator(IteratorUtils.filter(list.listIterator(6), v -> v>5), 0, new Integer[]{7,8,9});
	}
    
    @Test
	public void testReverse() {
        List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5,6,7,8,9));
        ListIterator<Integer> i = list.listIterator(9);
        IteratorTester.basicIterator(IteratorUtils.reverse(i), 0, new Integer[]{9,8,7,6,5,4,3,2,1});
        
        Iterator<Integer> b = IteratorUtils.reverse(list.listIterator(9));
        IteratorUtils.next(b, 1);
        b.remove();
        IteratorUtils.next(b, 2);
        b.remove();
        IteratorUtils.next(b, 3);
        b.remove();
        assertEquals(new IntArrayList(new int[]{1,2,3,5,6,8}),list);
    }
    
    @Test
    public void testStream() {
        List<Integer> exp = Arrays.asList(1,2,3,4,5,6,7,8,9);
        List<Integer> out = new ArrayList<>();
        IteratorUtils.stream( exp.listIterator() ).forEach(v -> out.add(v));
        assertEquals(exp, out);
    }
	
}
